Merge tag 'mmc-updates-for-3.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 10 Jul 2013 18:16:00 +0000 (11:16 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 10 Jul 2013 18:16:00 +0000 (11:16 -0700)
Pull MMC updates from Chris Ball:
 "MMC highlights for 3.11:

  Core:
   - Add support for eMMC 5.1 devices
   - Add MMC_CAP_AGGRESSIVE_PM capability for aggressive power
     management of eMMC/SD between requests, using runtime PM
   - Add an ioctl to perform the eMMC 4.5 Sanitize command.  Sample code
     at:

       git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc-utils.git

  Drivers:
   - dw_mmc: Add support for Rockchip's Cortex-A9 SoCs
   - dw_mmc: Add support for Altera SoCFPGAs
   - sdhci-esdhc-imx: Add support for 8-bit bus width, non-removable
     cards
   - sdhci-bcm-kona: New driver for Broadcom Kona (281xx) SoCs
   - sdhi/tmio: Add DT DMA support"

* tag 'mmc-updates-for-3.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (87 commits)
  mmc: bcm281xx SDHCI driver
  mmc: sdhci: add card_event callback to sdhci
  mmc: core: Fixup Oops for SDIO shutdown
  mmc: sdhci-pci: add another device id
  mmc: esdhc: Fix bug when writing to SDHCI_HOST_CONTROL register
  mmc: esdhc: Add support for 8-bit bus width and non-removable card
  mmc: core: production year for eMMC 4.41 and later
  mmc: omap: remove unnecessary #if 0's
  mmc: sdhci: fix ctrl_2 on super-speed selection
  mmc: dw_mmc-pltfm: add Rockchip variant
  mmc: dw_mmc-pltfm: move probe and remove below dt match table
  mmc: dw_mmc-pltfm: remove static from dw_mci_pltfm_remove
  mmc: sdhci-acpi: add support for eMMC hardware reset for HID 80860F14
  mmc: sdhci-pci: add support for eMMC hardware reset for BYT eMMC.
  mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA
  mmc: sdhci: fix caps2 for HS200
  sdhci-pxav3: Fix runtime PM initialization
  mmc: core: Add DT-bindings for MMC_CAP2_FULL_PWR_CYCLE
  mmc: core: Invent MMC_CAP2_FULL_PWR_CYCLE
  mmc: core: Enable power_off_notify for eMMC shutdown sequence
  ...

73 files changed:
Documentation/devicetree/bindings/mmc/mmc.txt
Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/synopsis-dw-mshc.txt
arch/arm/configs/bcm_defconfig
drivers/mmc/card/block.c
drivers/mmc/card/mmc_test.c
drivers/mmc/card/queue.c
drivers/mmc/core/bus.c
drivers/mmc/core/core.c
drivers/mmc/core/core.h
drivers/mmc/core/debugfs.c
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/mmc_ops.h
drivers/mmc/core/sd.c
drivers/mmc/core/sdio.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/android-goldfish.c
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/au1xmmc.c
drivers/mmc/host/bfin_sdh.c
drivers/mmc/host/cb710-mmc.c
drivers/mmc/host/cb710-mmc.h
drivers/mmc/host/davinci_mmc.c
drivers/mmc/host/dw_mmc-exynos.c
drivers/mmc/host/dw_mmc-pci.c
drivers/mmc/host/dw_mmc-pltfm.c
drivers/mmc/host/dw_mmc-socfpga.c [new file with mode: 0644]
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h
drivers/mmc/host/jz4740_mmc.c
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/pxamci.c
drivers/mmc/host/rtsx_pci_sdmmc.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci-bcm-kona.c [new file with mode: 0644]
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-esdhc.c
drivers/mmc/host/sdhci-of-hlwd.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-pltfm.c
drivers/mmc/host/sdhci-pltfm.h
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/sh_mobile_sdhi.c
drivers/mmc/host/tmio_mmc.c
drivers/mmc/host/tmio_mmc.h
drivers/mmc/host/tmio_mmc_dma.c
drivers/mmc/host/tmio_mmc_pio.c
drivers/mmc/host/wmt-sdmmc.c
include/linux/mfd/tmio.h
include/linux/mmc/card.h
include/linux/mmc/core.h
include/linux/mmc/host.h
include/linux/mmc/sdhci.h
include/linux/platform_data/mmc-esdhc-imx.h

index 85aada2..458b57f 100644 (file)
@@ -28,6 +28,7 @@ Optional properties:
 - cap-mmc-highspeed: MMC high-speed timing is supported
 - cap-power-off-card: powering off the card is safe
 - cap-sdio-irq: enable SDIO IRQ signalling on this interface
+- full-pwr-cycle: full power cycle of the card 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/rockchip-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
new file mode 100644 (file)
index 0000000..8a3d91d
--- /dev/null
@@ -0,0 +1,23 @@
+* Rockchip specific extensions to the Synopsis Designware Mobile
+  Storage Host Controller
+
+The Synopsis designware mobile storage host controller is used to interface
+a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
+differences between the core Synopsis dw mshc controller properties described
+by synopsis-dw-mshc.txt and the properties used by the Rockchip specific
+extensions to the Synopsis Designware Mobile Storage Host Controller.
+
+Required Properties:
+
+* compatible: should be
+       - "rockchip,rk2928-dw-mshc": for Rockchip RK2928 and following
+
+Example:
+
+       rkdwmmc0@12200000 {
+               compatible = "rockchip,rk2928-dw-mshc";
+               reg = <0x12200000 0x1000>;
+               interrupts = <0 75 0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
index 1180d78..cdcebea 100644 (file)
@@ -39,6 +39,19 @@ Required Properties:
 
 Optional properties:
 
+* clocks: from common clock binding: handle to biu and ciu clocks for the
+  bus interface unit clock and the card interface unit clock.
+
+* clock-names: from common clock binding: Shall be "biu" and "ciu".
+  If the biu clock is missing we'll simply skip enabling it.  If the
+  ciu clock is missing we'll just assume that the clock is running at
+  clock-frequency.  It is an error to omit both the ciu clock and the
+  clock-frequency.
+
+* clock-frequency: should be the frequency (in Hz) of the ciu clock.  If this
+  is specified and the ciu clock is specified then we'll try to set the ciu
+  clock to this at probe time.
+
 * num-slots: specifies the number of slots supported by the controller.
   The number of physical slots actually used could be equal or less than the
   value specified by num-slots. If this property is not specified, the value
@@ -55,6 +68,9 @@ Optional properties:
 
 * broken-cd: as documented in mmc core bindings.
 
+* vmmc-supply: The phandle to the regulator to use for vmmc.  If this is
+  specified we'll defer probe until we can find this regulator.
+
 Aliases:
 
 - All the MSHC controller nodes should be represented in the aliases node using
@@ -67,6 +83,8 @@ board specific portions as listed below.
 
        dwmmc0@12200000 {
                compatible = "snps,dw-mshc";
+               clocks = <&clock 351>, <&clock 132>;
+               clock-names = "biu", "ciu";
                reg = <0x12200000 0x1000>;
                interrupts = <0 75 0>;
                #address-cells = <1>;
@@ -74,11 +92,13 @@ board specific portions as listed below.
        };
 
        dwmmc0@12200000 {
+               clock-frequency = <400000000>;
                num-slots = <1>;
                supports-highspeed;
                broken-cd;
                fifo-depth = <0x80>;
                card-detect-delay = <200>;
+               vmmc-supply = <&buck8>;
 
                slot@0 {
                        reg = <0>;
index e3bf2d6..65edf6d 100644 (file)
@@ -78,6 +78,13 @@ CONFIG_BACKLIGHT_LCD_SUPPORT=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
 # CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_TEST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_BCM_KONA=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_TRIGGERS=y
index dd27b07..cd0b7f4 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/delay.h>
 #include <linux/capability.h>
 #include <linux/compat.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/mmc/ioctl.h>
 #include <linux/mmc/card.h>
@@ -58,6 +59,8 @@ MODULE_ALIAS("mmc:block");
 #define INAND_CMD38_ARG_SECTRIM1 0x81
 #define INAND_CMD38_ARG_SECTRIM2 0x88
 #define MMC_BLK_TIMEOUT_MS  (10 * 60 * 1000)        /* 10 minute timeout */
+#define MMC_SANITIZE_REQ_TIMEOUT 240000
+#define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16)
 
 #define mmc_req_rel_wr(req)    (((req->cmd_flags & REQ_FUA) || \
                                  (req->cmd_flags & REQ_META)) && \
@@ -222,7 +225,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
        md = mmc_blk_get(dev_to_disk(dev));
        card = md->queue.card;
 
-       mmc_claim_host(card->host);
+       mmc_get_card(card);
 
        ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
                                card->ext_csd.boot_ro_lock |
@@ -233,7 +236,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
        else
                card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN;
 
-       mmc_release_host(card->host);
+       mmc_put_card(card);
 
        if (!ret) {
                pr_info("%s: Locking boot partition ro until next power on\n",
@@ -408,6 +411,35 @@ static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status,
        return err;
 }
 
+static int ioctl_do_sanitize(struct mmc_card *card)
+{
+       int err;
+
+       if (!(mmc_can_sanitize(card) &&
+             (card->host->caps2 & MMC_CAP2_SANITIZE))) {
+                       pr_warn("%s: %s - SANITIZE is not supported\n",
+                               mmc_hostname(card->host), __func__);
+                       err = -EOPNOTSUPP;
+                       goto out;
+       }
+
+       pr_debug("%s: %s - SANITIZE IN PROGRESS...\n",
+               mmc_hostname(card->host), __func__);
+
+       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                       EXT_CSD_SANITIZE_START, 1,
+                                       MMC_SANITIZE_REQ_TIMEOUT);
+
+       if (err)
+               pr_err("%s: %s - EXT_CSD_SANITIZE_START failed. err=%d\n",
+                      mmc_hostname(card->host), __func__, err);
+
+       pr_debug("%s: %s - SANITIZE COMPLETED\n", mmc_hostname(card->host),
+                                            __func__);
+out:
+       return err;
+}
+
 static int mmc_blk_ioctl_cmd(struct block_device *bdev,
        struct mmc_ioc_cmd __user *ic_ptr)
 {
@@ -491,7 +523,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
 
        mrq.cmd = &cmd;
 
-       mmc_claim_host(card->host);
+       mmc_get_card(card);
 
        err = mmc_blk_part_switch(card, md);
        if (err)
@@ -510,6 +542,17 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
                        goto cmd_rel_host;
        }
 
+       if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_SANITIZE_START) &&
+           (cmd.opcode == MMC_SWITCH)) {
+               err = ioctl_do_sanitize(card);
+
+               if (err)
+                       pr_err("%s: ioctl_do_sanitize() failed. err = %d",
+                              __func__, err);
+
+               goto cmd_rel_host;
+       }
+
        mmc_wait_for_req(card->host, &mrq);
 
        if (cmd.error) {
@@ -558,7 +601,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
        }
 
 cmd_rel_host:
-       mmc_release_host(card->host);
+       mmc_put_card(card);
 
 cmd_done:
        mmc_blk_put(md);
@@ -939,10 +982,10 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
 {
        struct mmc_blk_data *md = mq->data;
        struct mmc_card *card = md->queue.card;
-       unsigned int from, nr, arg, trim_arg, erase_arg;
+       unsigned int from, nr, arg;
        int err = 0, type = MMC_BLK_SECDISCARD;
 
-       if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) {
+       if (!(mmc_can_secure_erase_trim(card))) {
                err = -EOPNOTSUPP;
                goto out;
        }
@@ -950,23 +993,11 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
        from = blk_rq_pos(req);
        nr = blk_rq_sectors(req);
 
-       /* The sanitize operation is supported at v4.5 only */
-       if (mmc_can_sanitize(card)) {
-               erase_arg = MMC_ERASE_ARG;
-               trim_arg = MMC_TRIM_ARG;
-       } else {
-               erase_arg = MMC_SECURE_ERASE_ARG;
-               trim_arg = MMC_SECURE_TRIM1_ARG;
-       }
+       if (mmc_can_trim(card) && !mmc_erase_group_aligned(card, from, nr))
+               arg = MMC_SECURE_TRIM1_ARG;
+       else
+               arg = MMC_SECURE_ERASE_ARG;
 
-       if (mmc_erase_group_aligned(card, from, nr))
-               arg = erase_arg;
-       else if (mmc_can_trim(card))
-               arg = trim_arg;
-       else {
-               err = -EINVAL;
-               goto out;
-       }
 retry:
        if (card->quirks & MMC_QUIRK_INAND_CMD38) {
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
@@ -1002,9 +1033,6 @@ retry:
                        goto out;
        }
 
-       if (mmc_can_sanitize(card))
-               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                                EXT_CSD_SANITIZE_START, 1, 0);
 out_retry:
        if (err && !mmc_blk_reset(md, card->host, type))
                goto retry;
@@ -1895,7 +1923,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 
        if (req && !mq->mqrq_prev->req)
                /* claim host only for the first request */
-               mmc_claim_host(card->host);
+               mmc_get_card(card);
 
        ret = mmc_blk_part_switch(card, md);
        if (ret) {
@@ -1939,7 +1967,7 @@ out:
                 * In case sepecial request, there is no reentry to
                 * the 'mmc_blk_issue_rq' with 'mqrq_prev->req'.
                 */
-               mmc_release_host(card->host);
+               mmc_put_card(card);
        return ret;
 }
 
@@ -2158,6 +2186,14 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
        struct mmc_card *card;
 
        if (md) {
+               /*
+                * Flush remaining requests and free queues. It
+                * is freeing the queue that stops new requests
+                * from being accepted.
+                */
+               mmc_cleanup_queue(&md->queue);
+               if (md->flags & MMC_BLK_PACKED_CMD)
+                       mmc_packed_clean(&md->queue);
                card = md->queue.card;
                if (md->disk->flags & GENHD_FL_UP) {
                        device_remove_file(disk_to_dev(md->disk), &md->force_ro);
@@ -2166,14 +2202,8 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
                                device_remove_file(disk_to_dev(md->disk),
                                        &md->power_ro_lock);
 
-                       /* Stop new requests from getting into the queue */
                        del_gendisk(md->disk);
                }
-
-               /* Then flush out any already in there */
-               mmc_cleanup_queue(&md->queue);
-               if (md->flags & MMC_BLK_PACKED_CMD)
-                       mmc_packed_clean(&md->queue);
                mmc_blk_put(md);
        }
 }
@@ -2336,6 +2366,19 @@ static int mmc_blk_probe(struct mmc_card *card)
                if (mmc_add_disk(part_md))
                        goto out;
        }
+
+       pm_runtime_set_autosuspend_delay(&card->dev, 3000);
+       pm_runtime_use_autosuspend(&card->dev);
+
+       /*
+        * Don't enable runtime PM for SD-combo cards here. Leave that
+        * decision to be taken during the SDIO init sequence instead.
+        */
+       if (card->type != MMC_TYPE_SD_COMBO) {
+               pm_runtime_set_active(&card->dev);
+               pm_runtime_enable(&card->dev);
+       }
+
        return 0;
 
  out:
@@ -2349,20 +2392,24 @@ static void mmc_blk_remove(struct mmc_card *card)
        struct mmc_blk_data *md = mmc_get_drvdata(card);
 
        mmc_blk_remove_parts(card, md);
+       pm_runtime_get_sync(&card->dev);
        mmc_claim_host(card->host);
        mmc_blk_part_switch(card, md);
        mmc_release_host(card->host);
+       if (card->type != MMC_TYPE_SD_COMBO)
+               pm_runtime_disable(&card->dev);
+       pm_runtime_put_noidle(&card->dev);
        mmc_blk_remove_req(md);
        mmc_set_drvdata(card, NULL);
 }
 
-#ifdef CONFIG_PM
-static int mmc_blk_suspend(struct mmc_card *card)
+static int _mmc_blk_suspend(struct mmc_card *card)
 {
        struct mmc_blk_data *part_md;
        struct mmc_blk_data *md = mmc_get_drvdata(card);
 
        if (md) {
+               pm_runtime_get_sync(&card->dev);
                mmc_queue_suspend(&md->queue);
                list_for_each_entry(part_md, &md->part, part) {
                        mmc_queue_suspend(&part_md->queue);
@@ -2371,6 +2418,17 @@ static int mmc_blk_suspend(struct mmc_card *card)
        return 0;
 }
 
+static void mmc_blk_shutdown(struct mmc_card *card)
+{
+       _mmc_blk_suspend(card);
+}
+
+#ifdef CONFIG_PM
+static int mmc_blk_suspend(struct mmc_card *card)
+{
+       return _mmc_blk_suspend(card);
+}
+
 static int mmc_blk_resume(struct mmc_card *card)
 {
        struct mmc_blk_data *part_md;
@@ -2386,6 +2444,7 @@ static int mmc_blk_resume(struct mmc_card *card)
                list_for_each_entry(part_md, &md->part, part) {
                        mmc_queue_resume(&part_md->queue);
                }
+               pm_runtime_put(&card->dev);
        }
        return 0;
 }
@@ -2402,6 +2461,7 @@ static struct mmc_driver mmc_driver = {
        .remove         = mmc_blk_remove,
        .suspend        = mmc_blk_suspend,
        .resume         = mmc_blk_resume,
+       .shutdown       = mmc_blk_shutdown,
 };
 
 static int __init mmc_blk_init(void)
index 759714e..a69df52 100644 (file)
@@ -3025,12 +3025,17 @@ static void mmc_test_remove(struct mmc_card *card)
        mmc_test_free_dbgfs_file(card);
 }
 
+static void mmc_test_shutdown(struct mmc_card *card)
+{
+}
+
 static struct mmc_driver mmc_driver = {
        .drv            = {
                .name   = "mmc_test",
        },
        .probe          = mmc_test_probe,
        .remove         = mmc_test_remove,
+       .shutdown       = mmc_test_shutdown,
 };
 
 static int __init mmc_test_init(void)
index 9447a0e..fa9632e 100644 (file)
@@ -173,7 +173,7 @@ static void mmc_queue_setup_discard(struct request_queue *q,
        /* granularity must not be greater than max. discard */
        if (card->pref_erase > max_discard)
                q->limits.discard_granularity = 0;
-       if (mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))
+       if (mmc_can_secure_erase_trim(card))
                queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q);
 }
 
index 9d5c711..704bf66 100644 (file)
@@ -122,15 +122,39 @@ static int mmc_bus_remove(struct device *dev)
        return 0;
 }
 
+static void mmc_bus_shutdown(struct device *dev)
+{
+       struct mmc_driver *drv = to_mmc_driver(dev->driver);
+       struct mmc_card *card = mmc_dev_to_card(dev);
+       struct mmc_host *host = card->host;
+       int ret;
+
+       if (dev->driver && drv->shutdown)
+               drv->shutdown(card);
+
+       if (host->bus_ops->shutdown) {
+               ret = host->bus_ops->shutdown(host);
+               if (ret)
+                       pr_warn("%s: error %d during shutdown\n",
+                               mmc_hostname(host), ret);
+       }
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int mmc_bus_suspend(struct device *dev)
 {
        struct mmc_driver *drv = to_mmc_driver(dev->driver);
        struct mmc_card *card = mmc_dev_to_card(dev);
-       int ret = 0;
+       struct mmc_host *host = card->host;
+       int ret;
 
-       if (dev->driver && drv->suspend)
+       if (dev->driver && drv->suspend) {
                ret = drv->suspend(card);
+               if (ret)
+                       return ret;
+       }
+
+       ret = host->bus_ops->suspend(host);
        return ret;
 }
 
@@ -138,10 +162,17 @@ static int mmc_bus_resume(struct device *dev)
 {
        struct mmc_driver *drv = to_mmc_driver(dev->driver);
        struct mmc_card *card = mmc_dev_to_card(dev);
-       int ret = 0;
+       struct mmc_host *host = card->host;
+       int ret;
+
+       ret = host->bus_ops->resume(host);
+       if (ret)
+               pr_warn("%s: error %d during resume (card was removed?)\n",
+                       mmc_hostname(host), ret);
 
        if (dev->driver && drv->resume)
                ret = drv->resume(card);
+
        return ret;
 }
 #endif
@@ -151,15 +182,25 @@ static int mmc_bus_resume(struct device *dev)
 static int mmc_runtime_suspend(struct device *dev)
 {
        struct mmc_card *card = mmc_dev_to_card(dev);
+       struct mmc_host *host = card->host;
+       int ret = 0;
+
+       if (host->bus_ops->runtime_suspend)
+               ret = host->bus_ops->runtime_suspend(host);
 
-       return mmc_power_save_host(card->host);
+       return ret;
 }
 
 static int mmc_runtime_resume(struct device *dev)
 {
        struct mmc_card *card = mmc_dev_to_card(dev);
+       struct mmc_host *host = card->host;
+       int ret = 0;
+
+       if (host->bus_ops->runtime_resume)
+               ret = host->bus_ops->runtime_resume(host);
 
-       return mmc_power_restore_host(card->host);
+       return ret;
 }
 
 static int mmc_runtime_idle(struct device *dev)
@@ -182,6 +223,7 @@ static struct bus_type mmc_bus_type = {
        .uevent         = mmc_bus_uevent,
        .probe          = mmc_bus_probe,
        .remove         = mmc_bus_remove,
+       .shutdown       = mmc_bus_shutdown,
        .pm             = &mmc_bus_pm_ops,
 };
 
index c40396f..49a5bca 100644 (file)
@@ -402,6 +402,7 @@ static int mmc_wait_for_data_req_done(struct mmc_host *host,
                        context_info->is_done_rcv = false;
                        context_info->is_new_req = false;
                        cmd = mrq->cmd;
+
                        if (!cmd->error || !cmd->retries ||
                            mmc_card_removed(host->card)) {
                                err = host->areq->err_check(host->card,
@@ -436,6 +437,24 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
                wait_for_completion(&mrq->completion);
 
                cmd = mrq->cmd;
+
+               /*
+                * If host has timed out waiting for the sanitize
+                * to complete, card might be still in programming state
+                * so let's try to bring the card out of programming
+                * state.
+                */
+               if (cmd->sanitize_busy && cmd->error == -ETIMEDOUT) {
+                       if (!mmc_interrupt_hpi(host->card)) {
+                               pr_warning("%s: %s: Interrupted sanitize\n",
+                                          mmc_hostname(host), __func__);
+                               cmd->error = 0;
+                               break;
+                       } else {
+                               pr_err("%s: %s: Failed to interrupt sanitize\n",
+                                      mmc_hostname(host), __func__);
+                       }
+               }
                if (!cmd->error || !cmd->retries ||
                    mmc_card_removed(host->card))
                        break;
@@ -952,6 +971,29 @@ void mmc_release_host(struct mmc_host *host)
 EXPORT_SYMBOL(mmc_release_host);
 
 /*
+ * This is a helper function, which fetches a runtime pm reference for the
+ * card device and also claims the host.
+ */
+void mmc_get_card(struct mmc_card *card)
+{
+       pm_runtime_get_sync(&card->dev);
+       mmc_claim_host(card->host);
+}
+EXPORT_SYMBOL(mmc_get_card);
+
+/*
+ * This is a helper function, which releases the host and drops the runtime
+ * pm reference for the card device.
+ */
+void mmc_put_card(struct mmc_card *card)
+{
+       mmc_release_host(card->host);
+       pm_runtime_mark_last_busy(&card->dev);
+       pm_runtime_put_autosuspend(&card->dev);
+}
+EXPORT_SYMBOL(mmc_put_card);
+
+/*
  * Internal function that does the actual ios call to the host driver,
  * optionally printing some debug output.
  */
@@ -1459,7 +1501,7 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
  * If a host does all the power sequencing itself, ignore the
  * initial MMC_POWER_UP stage.
  */
-static void mmc_power_up(struct mmc_host *host)
+void mmc_power_up(struct mmc_host *host)
 {
        int bit;
 
@@ -2325,14 +2367,13 @@ int mmc_detect_card_removed(struct mmc_host *host)
         * The card will be considered unchanged unless we have been asked to
         * detect a change or host requires polling to provide card detection.
         */
-       if (!host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL) &&
-           !(host->caps2 & MMC_CAP2_DETECT_ON_ERR))
+       if (!host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL))
                return ret;
 
        host->detect_change = 0;
        if (!ret) {
                ret = _mmc_detect_card_removed(host);
-               if (ret && (host->caps2 & MMC_CAP2_DETECT_ON_ERR)) {
+               if (ret && (host->caps & MMC_CAP_NEEDS_POLL)) {
                        /*
                         * Schedule a detect work as soon as possible to let a
                         * rescan handle the card removal.
@@ -2442,9 +2483,7 @@ void mmc_stop_host(struct mmc_host *host)
        mmc_bus_get(host);
        if (host->bus_ops && !host->bus_dead) {
                /* Calling bus_ops->remove() with a claimed host can deadlock */
-               if (host->bus_ops->remove)
-                       host->bus_ops->remove(host);
-
+               host->bus_ops->remove(host);
                mmc_claim_host(host);
                mmc_detach_bus(host);
                mmc_power_off(host);
@@ -2509,52 +2548,6 @@ int mmc_power_restore_host(struct mmc_host *host)
 }
 EXPORT_SYMBOL(mmc_power_restore_host);
 
-int mmc_card_awake(struct mmc_host *host)
-{
-       int err = -ENOSYS;
-
-       if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
-               return 0;
-
-       mmc_bus_get(host);
-
-       if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
-               err = host->bus_ops->awake(host);
-
-       mmc_bus_put(host);
-
-       return err;
-}
-EXPORT_SYMBOL(mmc_card_awake);
-
-int mmc_card_sleep(struct mmc_host *host)
-{
-       int err = -ENOSYS;
-
-       if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
-               return 0;
-
-       mmc_bus_get(host);
-
-       if (host->bus_ops && !host->bus_dead && host->bus_ops->sleep)
-               err = host->bus_ops->sleep(host);
-
-       mmc_bus_put(host);
-
-       return err;
-}
-EXPORT_SYMBOL(mmc_card_sleep);
-
-int mmc_card_can_sleep(struct mmc_host *host)
-{
-       struct mmc_card *card = host->card;
-
-       if (card && mmc_card_mmc(card) && card->ext_csd.rev >= 3)
-               return 1;
-       return 0;
-}
-EXPORT_SYMBOL(mmc_card_can_sleep);
-
 /*
  * Flush the cache to the non-volatile storage.
  */
@@ -2626,48 +2619,9 @@ EXPORT_SYMBOL(mmc_cache_ctrl);
  */
 int mmc_suspend_host(struct mmc_host *host)
 {
-       int err = 0;
-
-       cancel_delayed_work(&host->detect);
-       mmc_flush_scheduled_work();
-
-       mmc_bus_get(host);
-       if (host->bus_ops && !host->bus_dead) {
-               if (host->bus_ops->suspend) {
-                       if (mmc_card_doing_bkops(host->card)) {
-                               err = mmc_stop_bkops(host->card);
-                               if (err)
-                                       goto out;
-                       }
-                       err = host->bus_ops->suspend(host);
-               }
-
-               if (err == -ENOSYS || !host->bus_ops->resume) {
-                       /*
-                        * We simply "remove" the card in this case.
-                        * It will be redetected on resume.  (Calling
-                        * bus_ops->remove() with a claimed host can
-                        * deadlock.)
-                        */
-                       if (host->bus_ops->remove)
-                               host->bus_ops->remove(host);
-                       mmc_claim_host(host);
-                       mmc_detach_bus(host);
-                       mmc_power_off(host);
-                       mmc_release_host(host);
-                       host->pm_flags = 0;
-                       err = 0;
-               }
-       }
-       mmc_bus_put(host);
-
-       if (!err && !mmc_card_keep_power(host))
-               mmc_power_off(host);
-
-out:
-       return err;
+       /* This function is deprecated */
+       return 0;
 }
-
 EXPORT_SYMBOL(mmc_suspend_host);
 
 /**
@@ -2676,39 +2630,8 @@ EXPORT_SYMBOL(mmc_suspend_host);
  */
 int mmc_resume_host(struct mmc_host *host)
 {
-       int err = 0;
-
-       mmc_bus_get(host);
-       if (host->bus_ops && !host->bus_dead) {
-               if (!mmc_card_keep_power(host)) {
-                       mmc_power_up(host);
-                       mmc_select_voltage(host, host->ocr);
-                       /*
-                        * Tell runtime PM core we just powered up the card,
-                        * since it still believes the card is powered off.
-                        * Note that currently runtime PM is only enabled
-                        * for SDIO cards that are MMC_CAP_POWER_OFF_CARD
-                        */
-                       if (mmc_card_sdio(host->card) &&
-                           (host->caps & MMC_CAP_POWER_OFF_CARD)) {
-                               pm_runtime_disable(&host->card->dev);
-                               pm_runtime_set_active(&host->card->dev);
-                               pm_runtime_enable(&host->card->dev);
-                       }
-               }
-               BUG_ON(!host->bus_ops->resume);
-               err = host->bus_ops->resume(host);
-               if (err) {
-                       pr_warning("%s: error %d during resume "
-                                           "(card was removed?)\n",
-                                           mmc_hostname(host), err);
-                       err = 0;
-               }
-       }
-       host->pm_flags &= ~MMC_PM_KEEP_POWER;
-       mmc_bus_put(host);
-
-       return err;
+       /* This function is deprecated */
+       return 0;
 }
 EXPORT_SYMBOL(mmc_resume_host);
 
@@ -2727,29 +2650,22 @@ int mmc_pm_notify(struct notifier_block *notify_block,
        switch (mode) {
        case PM_HIBERNATION_PREPARE:
        case PM_SUSPEND_PREPARE:
-               if (host->card && mmc_card_mmc(host->card) &&
-                   mmc_card_doing_bkops(host->card)) {
-                       err = mmc_stop_bkops(host->card);
-                       if (err) {
-                               pr_err("%s: didn't stop bkops\n",
-                                       mmc_hostname(host));
-                               return err;
-                       }
-                       mmc_card_clr_doing_bkops(host->card);
-               }
-
                spin_lock_irqsave(&host->lock, flags);
                host->rescan_disable = 1;
                spin_unlock_irqrestore(&host->lock, flags);
                cancel_delayed_work_sync(&host->detect);
 
-               if (!host->bus_ops || host->bus_ops->suspend)
+               if (!host->bus_ops)
                        break;
 
-               /* Calling bus_ops->remove() with a claimed host can deadlock */
-               if (host->bus_ops->remove)
-                       host->bus_ops->remove(host);
+               /* Validate prerequisites for suspend */
+               if (host->bus_ops->pre_suspend)
+                       err = host->bus_ops->pre_suspend(host);
+               if (!err && host->bus_ops->suspend)
+                       break;
 
+               /* Calling bus_ops->remove() with a claimed host can deadlock */
+               host->bus_ops->remove(host);
                mmc_claim_host(host);
                mmc_detach_bus(host);
                mmc_power_off(host);
index b9f18a2..5345d15 100644 (file)
 #define MMC_CMD_RETRIES        3
 
 struct mmc_bus_ops {
-       int (*awake)(struct mmc_host *);
-       int (*sleep)(struct mmc_host *);
        void (*remove)(struct mmc_host *);
        void (*detect)(struct mmc_host *);
+       int (*pre_suspend)(struct mmc_host *);
        int (*suspend)(struct mmc_host *);
        int (*resume)(struct mmc_host *);
+       int (*runtime_suspend)(struct mmc_host *);
+       int (*runtime_resume)(struct mmc_host *);
        int (*power_save)(struct mmc_host *);
        int (*power_restore)(struct mmc_host *);
        int (*alive)(struct mmc_host *);
+       int (*shutdown)(struct mmc_host *);
 };
 
 void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -44,6 +46,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
 int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
 void mmc_set_timing(struct mmc_host *host, unsigned int timing);
 void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
+void mmc_power_up(struct mmc_host *host);
 void mmc_power_off(struct mmc_host *host);
 void mmc_power_cycle(struct mmc_host *host);
 
index 35c2f85..54829c0 100644 (file)
@@ -258,13 +258,13 @@ static int mmc_dbg_card_status_get(void *data, u64 *val)
        u32             status;
        int             ret;
 
-       mmc_claim_host(card->host);
+       mmc_get_card(card);
 
        ret = mmc_send_status(data, &status);
        if (!ret)
                *val = status;
 
-       mmc_release_host(card->host);
+       mmc_put_card(card);
 
        return ret;
 }
@@ -291,9 +291,9 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
                goto out_free;
        }
 
-       mmc_claim_host(card->host);
+       mmc_get_card(card);
        err = mmc_send_ext_csd(card, ext_csd);
-       mmc_release_host(card->host);
+       mmc_put_card(card);
        if (err)
                goto out_free;
 
index 2a3593d..6fb6f77 100644 (file)
@@ -306,7 +306,7 @@ static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
  * parse the properties and set respective generic mmc-host flags and
  * parameters.
  */
-void mmc_of_parse(struct mmc_host *host)
+int mmc_of_parse(struct mmc_host *host)
 {
        struct device_node *np;
        u32 bus_width;
@@ -315,7 +315,7 @@ void mmc_of_parse(struct mmc_host *host)
        int len, ret, gpio;
 
        if (!host->parent || !host->parent->of_node)
-               return;
+               return 0;
 
        np = host->parent->of_node;
 
@@ -338,6 +338,7 @@ void mmc_of_parse(struct mmc_host *host)
        default:
                dev_err(host->parent,
                        "Invalid \"bus-width\" value %ud!\n", bus_width);
+               return -EINVAL;
        }
 
        /* f_max is obtained from the optional "max-frequency" property */
@@ -367,18 +368,22 @@ void mmc_of_parse(struct mmc_host *host)
                        host->caps |= MMC_CAP_NEEDS_POLL;
 
                gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, &flags);
+               if (gpio == -EPROBE_DEFER)
+                       return gpio;
                if (gpio_is_valid(gpio)) {
                        if (!(flags & OF_GPIO_ACTIVE_LOW))
                                gpio_inv_cd = true;
 
                        ret = mmc_gpio_request_cd(host, gpio);
-                       if (ret < 0)
+                       if (ret < 0) {
                                dev_err(host->parent,
                                        "Failed to request CD GPIO #%d: %d!\n",
                                        gpio, ret);
-                       else
+                               return ret;
+                       } else {
                                dev_info(host->parent, "Got CD GPIO #%d.\n",
                                         gpio);
+                       }
                }
 
                if (explicit_inv_cd ^ gpio_inv_cd)
@@ -389,14 +394,23 @@ void mmc_of_parse(struct mmc_host *host)
        explicit_inv_wp = of_property_read_bool(np, "wp-inverted");
 
        gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags);
+       if (gpio == -EPROBE_DEFER) {
+               ret = -EPROBE_DEFER;
+               goto out;
+       }
        if (gpio_is_valid(gpio)) {
                if (!(flags & OF_GPIO_ACTIVE_LOW))
                        gpio_inv_wp = true;
 
                ret = mmc_gpio_request_ro(host, gpio);
-               if (ret < 0)
+               if (ret < 0) {
                        dev_err(host->parent,
                                "Failed to request WP GPIO: %d!\n", ret);
+                       goto out;
+               } else {
+                               dev_info(host->parent, "Got WP GPIO #%d.\n",
+                                        gpio);
+               }
        }
        if (explicit_inv_wp ^ gpio_inv_wp)
                host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
@@ -409,10 +423,18 @@ void mmc_of_parse(struct mmc_host *host)
                host->caps |= MMC_CAP_POWER_OFF_CARD;
        if (of_find_property(np, "cap-sdio-irq", &len))
                host->caps |= MMC_CAP_SDIO_IRQ;
+       if (of_find_property(np, "full-pwr-cycle", &len))
+               host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
        if (of_find_property(np, "keep-power-in-suspend", &len))
                host->pm_caps |= MMC_PM_KEEP_POWER;
        if (of_find_property(np, "enable-sdio-wakeup", &len))
                host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
+
+       return 0;
+
+out:
+       mmc_gpio_free_cd(host);
+       return ret;
 }
 
 EXPORT_SYMBOL(mmc_of_parse);
index 0cbd1ef..6d02012 100644 (file)
@@ -293,7 +293,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
        }
 
        card->ext_csd.rev = ext_csd[EXT_CSD_REV];
-       if (card->ext_csd.rev > 6) {
+       if (card->ext_csd.rev > 7) {
                pr_err("%s: unrecognised EXT_CSD revision %d\n",
                        mmc_hostname(card->host), card->ext_csd.rev);
                err = -EINVAL;
@@ -461,9 +461,31 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
                 */
                card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP];
                card->ext_csd.boot_ro_lockable = true;
+
+               /* Save power class values */
+               card->ext_csd.raw_pwr_cl_52_195 =
+                       ext_csd[EXT_CSD_PWR_CL_52_195];
+               card->ext_csd.raw_pwr_cl_26_195 =
+                       ext_csd[EXT_CSD_PWR_CL_26_195];
+               card->ext_csd.raw_pwr_cl_52_360 =
+                       ext_csd[EXT_CSD_PWR_CL_52_360];
+               card->ext_csd.raw_pwr_cl_26_360 =
+                       ext_csd[EXT_CSD_PWR_CL_26_360];
+               card->ext_csd.raw_pwr_cl_200_195 =
+                       ext_csd[EXT_CSD_PWR_CL_200_195];
+               card->ext_csd.raw_pwr_cl_200_360 =
+                       ext_csd[EXT_CSD_PWR_CL_200_360];
+               card->ext_csd.raw_pwr_cl_ddr_52_195 =
+                       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];
        }
 
        if (card->ext_csd.rev >= 5) {
+               /* Adjust production date as per JEDEC JESD84-B451 */
+               if (card->cid.year < 2010)
+                       card->cid.year += 16;
+
                /* check whether the eMMC card supports BKOPS */
                if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
                        card->ext_csd.bkops = 1;
@@ -607,7 +629,23 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
                (card->ext_csd.raw_sectors[2] ==
                        bw_ext_csd[EXT_CSD_SEC_CNT + 2]) &&
                (card->ext_csd.raw_sectors[3] ==
-                       bw_ext_csd[EXT_CSD_SEC_CNT + 3]));
+                       bw_ext_csd[EXT_CSD_SEC_CNT + 3]) &&
+               (card->ext_csd.raw_pwr_cl_52_195 ==
+                       bw_ext_csd[EXT_CSD_PWR_CL_52_195]) &&
+               (card->ext_csd.raw_pwr_cl_26_195 ==
+                       bw_ext_csd[EXT_CSD_PWR_CL_26_195]) &&
+               (card->ext_csd.raw_pwr_cl_52_360 ==
+                       bw_ext_csd[EXT_CSD_PWR_CL_52_360]) &&
+               (card->ext_csd.raw_pwr_cl_26_360 ==
+                       bw_ext_csd[EXT_CSD_PWR_CL_26_360]) &&
+               (card->ext_csd.raw_pwr_cl_200_195 ==
+                       bw_ext_csd[EXT_CSD_PWR_CL_200_195]) &&
+               (card->ext_csd.raw_pwr_cl_200_360 ==
+                       bw_ext_csd[EXT_CSD_PWR_CL_200_360]) &&
+               (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]));
        if (err)
                err = -EINVAL;
 
@@ -676,11 +714,10 @@ static struct device_type mmc_type = {
  * mmc_switch command.
  */
 static int mmc_select_powerclass(struct mmc_card *card,
-               unsigned int bus_width, u8 *ext_csd)
+               unsigned int bus_width)
 {
        int err = 0;
-       unsigned int pwrclass_val;
-       unsigned int index = 0;
+       unsigned int pwrclass_val = 0;
        struct mmc_host *host;
 
        BUG_ON(!card);
@@ -688,9 +725,6 @@ static int mmc_select_powerclass(struct mmc_card *card,
        host = card->host;
        BUG_ON(!host);
 
-       if (ext_csd == NULL)
-               return 0;
-
        /* Power class selection is supported for versions >= 4.0 */
        if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
                return 0;
@@ -702,13 +736,13 @@ static int mmc_select_powerclass(struct mmc_card *card,
        switch (1 << host->ios.vdd) {
        case MMC_VDD_165_195:
                if (host->ios.clock <= 26000000)
-                       index = EXT_CSD_PWR_CL_26_195;
+                       pwrclass_val = card->ext_csd.raw_pwr_cl_26_195;
                else if (host->ios.clock <= 52000000)
-                       index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
-                               EXT_CSD_PWR_CL_52_195 :
-                               EXT_CSD_PWR_CL_DDR_52_195;
+                       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)
-                       index = EXT_CSD_PWR_CL_200_195;
+                       pwrclass_val = card->ext_csd.raw_pwr_cl_200_195;
                break;
        case MMC_VDD_27_28:
        case MMC_VDD_28_29:
@@ -720,13 +754,13 @@ static int mmc_select_powerclass(struct mmc_card *card,
        case MMC_VDD_34_35:
        case MMC_VDD_35_36:
                if (host->ios.clock <= 26000000)
-                       index = EXT_CSD_PWR_CL_26_360;
+                       pwrclass_val = card->ext_csd.raw_pwr_cl_26_360;
                else if (host->ios.clock <= 52000000)
-                       index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
-                               EXT_CSD_PWR_CL_52_360 :
-                               EXT_CSD_PWR_CL_DDR_52_360;
+                       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)
-                       index = EXT_CSD_PWR_CL_200_360;
+                       pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
                break;
        default:
                pr_warning("%s: Voltage range not supported "
@@ -734,8 +768,6 @@ static int mmc_select_powerclass(struct mmc_card *card,
                return -EINVAL;
        }
 
-       pwrclass_val = ext_csd[index];
-
        if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8))
                pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >>
                                EXT_CSD_PWR_CL_8BIT_SHIFT;
@@ -1013,11 +1045,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        }
 
        /*
-        * If the host supports the power_off_notify capability then
-        * set the notification byte in the ext_csd register of device
+        * Enable power_off_notification byte in the ext_csd register
         */
-       if ((host->caps2 & MMC_CAP2_POWEROFF_NOTIFY) &&
-           (card->ext_csd.rev >= 6)) {
+       if (card->ext_csd.rev >= 6) {
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                                 EXT_CSD_POWER_OFF_NOTIFICATION,
                                 EXT_CSD_POWER_ON,
@@ -1131,7 +1161,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 
                ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
                                EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
-               err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
+               err = mmc_select_powerclass(card, ext_csd_bits);
                if (err)
                        pr_warning("%s: power class selection to bus width %d"
                                   " failed\n", mmc_hostname(card->host),
@@ -1164,8 +1194,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                        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],
-                                                   ext_csd);
+                       err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
                        if (err)
                                pr_warning("%s: power class selection to "
                                           "bus width %d failed\n",
@@ -1195,8 +1224,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                }
 
                if (!err && ddr) {
-                       err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
-                                                   ext_csd);
+                       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",
@@ -1321,6 +1349,45 @@ err:
        return err;
 }
 
+static int mmc_can_sleep(struct mmc_card *card)
+{
+       return (card && card->ext_csd.rev >= 3);
+}
+
+static int mmc_sleep(struct mmc_host *host)
+{
+       struct mmc_command cmd = {0};
+       struct mmc_card *card = host->card;
+       int err;
+
+       if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
+               return 0;
+
+       err = mmc_deselect_cards(host);
+       if (err)
+               return err;
+
+       cmd.opcode = MMC_SLEEP_AWAKE;
+       cmd.arg = card->rca << 16;
+       cmd.arg |= 1 << 15;
+
+       cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+       err = mmc_wait_for_cmd(host, &cmd, 0);
+       if (err)
+               return err;
+
+       /*
+        * If the host does not wait while the card signals busy, then we will
+        * will have to wait the sleep/awake timeout.  Note, we cannot use the
+        * SEND_STATUS command to poll the status because that command (and most
+        * others) is invalid while the card sleeps.
+        */
+       if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
+               mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000));
+
+       return err;
+}
+
 static int mmc_can_poweroff_notify(const struct mmc_card *card)
 {
        return card &&
@@ -1380,14 +1447,14 @@ static void mmc_detect(struct mmc_host *host)
        BUG_ON(!host);
        BUG_ON(!host->card);
 
-       mmc_claim_host(host);
+       mmc_get_card(host->card);
 
        /*
         * Just check if our card has been removed.
         */
        err = _mmc_detect_card_removed(host);
 
-       mmc_release_host(host);
+       mmc_put_card(host->card);
 
        if (err) {
                mmc_remove(host);
@@ -1399,36 +1466,60 @@ static void mmc_detect(struct mmc_host *host)
        }
 }
 
-/*
- * Suspend callback from host.
- */
-static int mmc_suspend(struct mmc_host *host)
+static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 {
        int err = 0;
+       unsigned int notify_type = is_suspend ? EXT_CSD_POWER_OFF_SHORT :
+                                       EXT_CSD_POWER_OFF_LONG;
 
        BUG_ON(!host);
        BUG_ON(!host->card);
 
        mmc_claim_host(host);
 
+       if (mmc_card_doing_bkops(host->card)) {
+               err = mmc_stop_bkops(host->card);
+               if (err)
+                       goto out;
+       }
+
        err = mmc_cache_ctrl(host, 0);
        if (err)
                goto out;
 
-       if (mmc_can_poweroff_notify(host->card))
-               err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_SHORT);
-       else if (mmc_card_can_sleep(host))
-               err = mmc_card_sleep(host);
+       if (mmc_can_poweroff_notify(host->card) &&
+               ((host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) || !is_suspend))
+               err = mmc_poweroff_notify(host->card, notify_type);
+       else if (mmc_can_sleep(host->card))
+               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);
 out:
        mmc_release_host(host);
        return err;
 }
 
 /*
+ * Suspend callback from host.
+ */
+static int mmc_suspend(struct mmc_host *host)
+{
+       return _mmc_suspend(host, true);
+}
+
+/*
+ * Shutdown callback
+ */
+static int mmc_shutdown(struct mmc_host *host)
+{
+       return _mmc_suspend(host, false);
+}
+
+/*
  * Resume callback from host.
  *
  * This function tries to determine if the same card is still present
@@ -1442,74 +1533,94 @@ static int mmc_resume(struct mmc_host *host)
        BUG_ON(!host->card);
 
        mmc_claim_host(host);
+       mmc_power_up(host);
+       mmc_select_voltage(host, host->ocr);
        err = mmc_init_card(host, host->ocr, host->card);
        mmc_release_host(host);
 
        return err;
 }
 
-static int mmc_power_restore(struct mmc_host *host)
+
+/*
+ * Callback for runtime_suspend.
+ */
+static int mmc_runtime_suspend(struct mmc_host *host)
 {
-       int ret;
+       int err;
+
+       if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+               return 0;
 
-       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
        mmc_claim_host(host);
-       ret = mmc_init_card(host, host->ocr, host->card);
-       mmc_release_host(host);
 
-       return ret;
+       err = mmc_suspend(host);
+       if (err) {
+               pr_err("%s: error %d doing aggessive suspend\n",
+                       mmc_hostname(host), err);
+               goto out;
+       }
+       mmc_power_off(host);
+
+out:
+       mmc_release_host(host);
+       return err;
 }
 
-static int mmc_sleep(struct mmc_host *host)
+/*
+ * Callback for runtime_resume.
+ */
+static int mmc_runtime_resume(struct mmc_host *host)
 {
-       struct mmc_card *card = host->card;
-       int err = -ENOSYS;
+       int err;
 
-       if (card && card->ext_csd.rev >= 3) {
-               err = mmc_card_sleepawake(host, 1);
-               if (err < 0)
-                       pr_debug("%s: Error %d while putting card into sleep",
-                                mmc_hostname(host), err);
-       }
+       if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+               return 0;
 
-       return err;
+       mmc_claim_host(host);
+
+       mmc_power_up(host);
+       err = mmc_resume(host);
+       if (err)
+               pr_err("%s: error %d doing aggessive resume\n",
+                       mmc_hostname(host), err);
+
+       mmc_release_host(host);
+       return 0;
 }
 
-static int mmc_awake(struct mmc_host *host)
+static int mmc_power_restore(struct mmc_host *host)
 {
-       struct mmc_card *card = host->card;
-       int err = -ENOSYS;
+       int ret;
 
-       if (card && card->ext_csd.rev >= 3) {
-               err = mmc_card_sleepawake(host, 0);
-               if (err < 0)
-                       pr_debug("%s: Error %d while awaking sleeping card",
-                                mmc_hostname(host), err);
-       }
+       host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
+       mmc_claim_host(host);
+       ret = mmc_init_card(host, host->ocr, host->card);
+       mmc_release_host(host);
 
-       return err;
+       return ret;
 }
 
 static const struct mmc_bus_ops mmc_ops = {
-       .awake = mmc_awake,
-       .sleep = mmc_sleep,
        .remove = mmc_remove,
        .detect = mmc_detect,
        .suspend = NULL,
        .resume = NULL,
        .power_restore = mmc_power_restore,
        .alive = mmc_alive,
+       .shutdown = mmc_shutdown,
 };
 
 static const struct mmc_bus_ops mmc_ops_unsafe = {
-       .awake = mmc_awake,
-       .sleep = mmc_sleep,
        .remove = mmc_remove,
        .detect = mmc_detect,
        .suspend = mmc_suspend,
        .resume = mmc_resume,
+       .runtime_suspend = mmc_runtime_suspend,
+       .runtime_resume = mmc_runtime_resume,
        .power_restore = mmc_power_restore,
        .alive = mmc_alive,
+       .shutdown = mmc_shutdown,
 };
 
 static void mmc_attach_bus_ops(struct mmc_host *host)
index 49f04bc..837fc73 100644 (file)
@@ -59,40 +59,6 @@ int mmc_deselect_cards(struct mmc_host *host)
        return _mmc_select_card(host, NULL);
 }
 
-int mmc_card_sleepawake(struct mmc_host *host, int sleep)
-{
-       struct mmc_command cmd = {0};
-       struct mmc_card *card = host->card;
-       int err;
-
-       if (sleep)
-               mmc_deselect_cards(host);
-
-       cmd.opcode = MMC_SLEEP_AWAKE;
-       cmd.arg = card->rca << 16;
-       if (sleep)
-               cmd.arg |= 1 << 15;
-
-       cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
-       err = mmc_wait_for_cmd(host, &cmd, 0);
-       if (err)
-               return err;
-
-       /*
-        * If the host does not wait while the card signals busy, then we will
-        * will have to wait the sleep/awake timeout.  Note, we cannot use the
-        * SEND_STATUS command to poll the status because that command (and most
-        * others) is invalid while the card sleeps.
-        */
-       if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
-               mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000));
-
-       if (!sleep)
-               err = mmc_select_card(card);
-
-       return err;
-}
-
 int mmc_go_idle(struct mmc_host *host)
 {
        int err;
@@ -431,6 +397,8 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
 
 
        cmd.cmd_timeout_ms = timeout_ms;
+       if (index == EXT_CSD_SANITIZE_START)
+               cmd.sanitize_busy = true;
 
        err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
        if (err)
index 3dd8941..80ae9f4 100644 (file)
@@ -24,7 +24,6 @@ int mmc_send_status(struct mmc_card *card, u32 *status);
 int mmc_send_cid(struct mmc_host *host, u32 *cid);
 int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
 int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
-int mmc_card_sleepawake(struct mmc_host *host, int sleep);
 int mmc_bus_test(struct mmc_card *card, u8 bus_width);
 int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
 
index 9e645e1..176d125 100644 (file)
@@ -646,8 +646,13 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
        if (err)
                goto out;
 
-       /* SPI mode doesn't define CMD19 */
-       if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) {
+       /*
+        * SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and
+        * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104.
+        */
+       if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning &&
+                       (card->sd_bus_speed == UHS_SDR50_BUS_SPEED ||
+                        card->sd_bus_speed == UHS_SDR104_BUS_SPEED)) {
                mmc_host_clk_hold(card->host);
                err = card->host->ops->execute_tuning(card->host,
                                                      MMC_SEND_TUNING_BLOCK);
@@ -1037,14 +1042,14 @@ static void mmc_sd_detect(struct mmc_host *host)
        BUG_ON(!host);
        BUG_ON(!host->card);
 
-       mmc_claim_host(host);
+       mmc_get_card(host->card);
 
        /*
         * Just check if our card has been removed.
         */
        err = _mmc_detect_card_removed(host);
 
-       mmc_release_host(host);
+       mmc_put_card(host->card);
 
        if (err) {
                mmc_sd_remove(host);
@@ -1070,6 +1075,8 @@ 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_release_host(host);
 
        return err;
@@ -1089,12 +1096,61 @@ static int mmc_sd_resume(struct mmc_host *host)
        BUG_ON(!host->card);
 
        mmc_claim_host(host);
+       mmc_power_up(host);
+       mmc_select_voltage(host, host->ocr);
        err = mmc_sd_init_card(host, host->ocr, host->card);
        mmc_release_host(host);
 
        return err;
 }
 
+/*
+ * Callback for runtime_suspend.
+ */
+static int mmc_sd_runtime_suspend(struct mmc_host *host)
+{
+       int err;
+
+       if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+               return 0;
+
+       mmc_claim_host(host);
+
+       err = mmc_sd_suspend(host);
+       if (err) {
+               pr_err("%s: error %d doing aggessive suspend\n",
+                       mmc_hostname(host), err);
+               goto out;
+       }
+       mmc_power_off(host);
+
+out:
+       mmc_release_host(host);
+       return err;
+}
+
+/*
+ * Callback for runtime_resume.
+ */
+static int mmc_sd_runtime_resume(struct mmc_host *host)
+{
+       int err;
+
+       if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
+               return 0;
+
+       mmc_claim_host(host);
+
+       mmc_power_up(host);
+       err = mmc_sd_resume(host);
+       if (err)
+               pr_err("%s: error %d doing aggessive resume\n",
+                       mmc_hostname(host), err);
+
+       mmc_release_host(host);
+       return 0;
+}
+
 static int mmc_sd_power_restore(struct mmc_host *host)
 {
        int ret;
@@ -1114,15 +1170,19 @@ static const struct mmc_bus_ops mmc_sd_ops = {
        .resume = NULL,
        .power_restore = mmc_sd_power_restore,
        .alive = mmc_sd_alive,
+       .shutdown = mmc_sd_suspend,
 };
 
 static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
        .remove = mmc_sd_remove,
        .detect = mmc_sd_detect,
+       .runtime_suspend = mmc_sd_runtime_suspend,
+       .runtime_resume = mmc_sd_runtime_resume,
        .suspend = mmc_sd_suspend,
        .resume = mmc_sd_resume,
        .power_restore = mmc_sd_power_restore,
        .alive = mmc_sd_alive,
+       .shutdown = mmc_sd_suspend,
 };
 
 static void mmc_sd_attach_bus_ops(struct mmc_host *host)
index 6889a82..80d89cf 100644 (file)
@@ -563,10 +563,18 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card)
        if (err)
                goto out;
 
-       /* Initialize and start re-tuning timer */
-       if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
+       /*
+        * SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and
+        * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104.
+        */
+       if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning &&
+                       ((card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR50) ||
+                        (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104))) {
+               mmc_host_clk_hold(card->host);
                err = card->host->ops->execute_tuning(card->host,
                                                      MMC_SEND_TUNING_BLOCK);
+               mmc_host_clk_release(card->host);
+       }
 
 out:
 
@@ -902,11 +910,11 @@ out:
 }
 
 /*
- * SDIO suspend.  We need to suspend all functions separately.
+ * SDIO pre_suspend.  We need to suspend all functions separately.
  * Therefore all registered functions must have drivers with suspend
  * and resume methods.  Failing that we simply remove the whole card.
  */
-static int mmc_sdio_suspend(struct mmc_host *host)
+static int mmc_sdio_pre_suspend(struct mmc_host *host)
 {
        int i, err = 0;
 
@@ -917,8 +925,26 @@ static int mmc_sdio_suspend(struct mmc_host *host)
                        if (!pmops || !pmops->suspend || !pmops->resume) {
                                /* force removal of entire card in that case */
                                err = -ENOSYS;
-                       } else
-                               err = pmops->suspend(&func->dev);
+                               break;
+                       }
+               }
+       }
+
+       return err;
+}
+
+/*
+ * SDIO suspend.  Suspend all functions separately.
+ */
+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;
                }
@@ -937,6 +963,9 @@ static int mmc_sdio_suspend(struct mmc_host *host)
                mmc_release_host(host);
        }
 
+       if (!err && !mmc_card_keep_power(host))
+               mmc_power_off(host);
+
        return err;
 }
 
@@ -950,6 +979,23 @@ static int mmc_sdio_resume(struct mmc_host *host)
        /* Basic card reinitialization. */
        mmc_claim_host(host);
 
+       /* Restore power if needed */
+       if (!mmc_card_keep_power(host)) {
+               mmc_power_up(host);
+               mmc_select_voltage(host, host->ocr);
+               /*
+                * Tell runtime PM core we just powered up the card,
+                * since it still believes the card is powered off.
+                * Note that currently runtime PM is only enabled
+                * for SDIO cards that are MMC_CAP_POWER_OFF_CARD
+                */
+               if (host->caps & MMC_CAP_POWER_OFF_CARD) {
+                       pm_runtime_disable(&host->card->dev);
+                       pm_runtime_set_active(&host->card->dev);
+                       pm_runtime_enable(&host->card->dev);
+               }
+       }
+
        /* No need to reinitialize powered-resumed nonremovable cards */
        if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
                sdio_reset(host);
@@ -987,6 +1033,7 @@ static int mmc_sdio_resume(struct mmc_host *host)
                }
        }
 
+       host->pm_flags &= ~MMC_PM_KEEP_POWER;
        return err;
 }
 
@@ -1051,11 +1098,28 @@ out:
        return ret;
 }
 
+static int mmc_sdio_runtime_suspend(struct mmc_host *host)
+{
+       /* No references to the card, cut the power to it. */
+       mmc_power_off(host);
+       return 0;
+}
+
+static int mmc_sdio_runtime_resume(struct mmc_host *host)
+{
+       /* Restore power and re-initialize. */
+       mmc_power_up(host);
+       return mmc_sdio_power_restore(host);
+}
+
 static const struct mmc_bus_ops mmc_sdio_ops = {
        .remove = mmc_sdio_remove,
        .detect = mmc_sdio_detect,
+       .pre_suspend = mmc_sdio_pre_suspend,
        .suspend = mmc_sdio_suspend,
        .resume = mmc_sdio_resume,
+       .runtime_suspend = mmc_sdio_runtime_suspend,
+       .runtime_resume = mmc_sdio_runtime_resume,
        .power_restore = mmc_sdio_power_restore,
        .alive = mmc_sdio_alive,
 };
index 9ab8f8d..8a4c066 100644 (file)
@@ -249,6 +249,17 @@ config MMC_SDHCI_S3C_DMA
 
          YMMV.
 
+config MMC_SDHCI_BCM_KONA
+       tristate "SDHCI support on Broadcom KONA platform"
+       depends on ARCH_BCM
+       select MMC_SDHCI_PLTFM
+       help
+         This selects the Broadcom Kona Secure Digital Host Controller
+         Interface(SDHCI) support.
+         This is used in Broadcom mobile SoCs.
+
+         If you have a controller with this interface, say Y or M here.
+
 config MMC_SDHCI_BCM2835
        tristate "SDHCI platform support for the BCM2835 SD/MMC Controller"
        depends on ARCH_BCM2835
@@ -556,6 +567,14 @@ config MMC_DW_EXYNOS
          Synopsys DesignWare Memory Card Interface driver. Select this option
          for platforms based on Exynos4 and Exynos5 SoC's.
 
+config MMC_DW_SOCFPGA
+       tristate "SOCFPGA specific extensions for Synopsys DW Memory Card Interface"
+       depends on MMC_DW
+       select MMC_DW_PLTFM
+       help
+         This selects support for Altera SoCFPGA specific extensions to the
+         Synopsys DesignWare Memory Card Interface driver.
+
 config MMC_DW_PCI
        tristate "Synopsys Designware MCI support on PCI bus"
        depends on MMC_DW && PCI
index cd32280..d422e21 100644 (file)
@@ -42,6 +42,7 @@ obj-$(CONFIG_SDH_BFIN)                += bfin_sdh.o
 obj-$(CONFIG_MMC_DW)           += dw_mmc.o
 obj-$(CONFIG_MMC_DW_PLTFM)     += dw_mmc-pltfm.o
 obj-$(CONFIG_MMC_DW_EXYNOS)    += dw_mmc-exynos.o
+obj-$(CONFIG_MMC_DW_SOCFPGA)   += dw_mmc-socfpga.o
 obj-$(CONFIG_MMC_DW_PCI)       += dw_mmc-pci.o
 obj-$(CONFIG_MMC_SH_MMCIF)     += sh_mmcif.o
 obj-$(CONFIG_MMC_JZ4740)       += jz4740_mmc.o
@@ -60,6 +61,7 @@ obj-$(CONFIG_MMC_SDHCI_DOVE)          += sdhci-dove.o
 obj-$(CONFIG_MMC_SDHCI_TEGRA)          += sdhci-tegra.o
 obj-$(CONFIG_MMC_SDHCI_OF_ESDHC)       += sdhci-of-esdhc.o
 obj-$(CONFIG_MMC_SDHCI_OF_HLWD)                += sdhci-of-hlwd.o
+obj-$(CONFIG_MMC_SDHCI_BCM_KONA)       += sdhci-bcm-kona.o
 obj-$(CONFIG_MMC_SDHCI_BCM2835)                += sdhci-bcm2835.o
 
 ifeq ($(CONFIG_CB710_DEBUG),y)
index 7780c14..8b4e20a 100644 (file)
@@ -546,8 +546,6 @@ static int goldfish_mmc_remove(struct platform_device *pdev)
 {
        struct goldfish_mmc_host *host = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        BUG_ON(host == NULL);
 
        mmc_remove_host(host->mmc);
index aca59d9..bdb84da 100644 (file)
@@ -40,8 +40,6 @@
 #include <asm/io.h>
 #include <asm/unaligned.h>
 
-#include <mach/cpu.h>
-
 #include "atmel-mci-regs.h"
 
 #define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE)
@@ -2475,8 +2473,6 @@ static int __exit atmci_remove(struct platform_device *pdev)
        struct atmel_mci        *host = platform_get_drvdata(pdev);
        unsigned int            i;
 
-       platform_set_drvdata(pdev, NULL);
-
        if (host->buffer)
                dma_free_coherent(&pdev->dev, host->buf_size,
                                  host->buffer, host->buf_phys_addr);
@@ -2504,7 +2500,7 @@ static int __exit atmci_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int atmci_suspend(struct device *dev)
 {
        struct atmel_mci *host = dev_get_drvdata(dev);
@@ -2559,17 +2555,15 @@ static int atmci_resume(struct device *dev)
 
        return ret;
 }
-static SIMPLE_DEV_PM_OPS(atmci_pm, atmci_suspend, atmci_resume);
-#define ATMCI_PM_OPS   (&atmci_pm)
-#else
-#define ATMCI_PM_OPS   NULL
 #endif
 
+static SIMPLE_DEV_PM_OPS(atmci_pm, atmci_suspend, atmci_resume);
+
 static struct platform_driver atmci_driver = {
        .remove         = __exit_p(atmci_remove),
        .driver         = {
                .name           = "atmel_mci",
-               .pm             = ATMCI_PM_OPS,
+               .pm             = &atmci_pm,
                .of_match_table = of_match_ptr(atmci_dt_ids),
        },
 };
index 127a8fa..df9becd 100644 (file)
@@ -1149,7 +1149,6 @@ static int au1xmmc_remove(struct platform_device *pdev)
                kfree(host->ioarea);
 
                mmc_free_host(host->mmc);
-               platform_set_drvdata(pdev, NULL);
        }
        return 0;
 }
index fb4348c..94fae2f 100644 (file)
@@ -621,8 +621,6 @@ static int sdh_remove(struct platform_device *pdev)
 {
        struct mmc_host *mmc = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        if (mmc) {
                struct sdh_host *host = mmc_priv(mmc);
 
index 777ca20..9d6e2b8 100644 (file)
@@ -703,7 +703,7 @@ static int cb710_mmc_init(struct platform_device *pdev)
        if (!mmc)
                return -ENOMEM;
 
-       dev_set_drvdata(&pdev->dev, mmc);
+       platform_set_drvdata(pdev, mmc);
 
        /* harmless (maybe) magic */
        pci_read_config_dword(chip->pdev, 0x48, &val);
index e845c77..8984ec8 100644 (file)
@@ -24,7 +24,7 @@ struct cb710_mmc_reader {
 
 static inline struct mmc_host *cb710_slot_to_mmc(struct cb710_slot *slot)
 {
-       return dev_get_drvdata(&slot->pdev.dev);
+       return platform_get_drvdata(&slot->pdev);
 }
 
 static inline struct cb710_slot *cb710_mmc_to_slot(struct mmc_host *mmc)
index 5dfb70c..e9fa87d 100644 (file)
@@ -1407,7 +1407,6 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev)
 {
        struct mmc_davinci_host *host = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
        if (host) {
                mmc_davinci_cpufreq_deregister(host);
 
index f013e7e..866edef 100644 (file)
@@ -31,8 +31,6 @@
                                        SDMMC_CLKSEL_CCLK_DRIVE(y) |    \
                                        SDMMC_CLKSEL_CCLK_DIVIDER(z))
 
-#define SDMMC_CMD_USE_HOLD_REG         BIT(29)
-
 #define EXYNOS4210_FIXED_CIU_CLK_DIV   2
 #define EXYNOS4412_FIXED_CIU_CLK_DIV   4
 
index 083fcd2..b456b0c 100644 (file)
@@ -21,7 +21,6 @@
 #include "dw_mmc.h"
 
 #define PCI_BAR_NO 2
-#define COMPLETE_BAR 0
 #define SYNOPSYS_DW_MCI_VENDOR_ID 0x700
 #define SYNOPSYS_DW_MCI_DEVICE_ID 0x1107
 /* Defining the Capabilities */
@@ -38,51 +37,37 @@ static struct dw_mci_board pci_board_data = {
 };
 
 static int dw_mci_pci_probe(struct pci_dev *pdev,
-                                 const struct pci_device_id *entries)
+                           const struct pci_device_id *entries)
 {
        struct dw_mci *host;
        int ret;
 
-       ret = pci_enable_device(pdev);
+       ret = pcim_enable_device(pdev);
        if (ret)
                return ret;
-       if (pci_request_regions(pdev, "dw_mmc_pci")) {
-               ret = -ENODEV;
-               goto err_disable_dev;
-       }
 
-       host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL);
-       if (!host) {
-               ret = -ENOMEM;
-               goto err_release;
-       }
+       host = devm_kzalloc(&pdev->dev, sizeof(struct dw_mci), GFP_KERNEL);
+       if (!host)
+               return -ENOMEM;
 
        host->irq = pdev->irq;
        host->irq_flags = IRQF_SHARED;
        host->dev = &pdev->dev;
        host->pdata = &pci_board_data;
 
-       host->regs = pci_iomap(pdev, PCI_BAR_NO, COMPLETE_BAR);
-       if (!host->regs) {
-               ret = -EIO;
-               goto err_unmap;
-       }
+       ret = pcim_iomap_regions(pdev, 1 << PCI_BAR_NO, pci_name(pdev));
+       if (ret)
+               return ret;
+
+       host->regs = pcim_iomap_table(pdev)[0];
 
-       pci_set_drvdata(pdev, host);
        ret = dw_mci_probe(host);
        if (ret)
-               goto err_probe_failed;
-       return ret;
-
-err_probe_failed:
-       pci_iounmap(pdev, host->regs);
-err_unmap:
-       kfree(host);
-err_release:
-       pci_release_regions(pdev);
-err_disable_dev:
-       pci_disable_device(pdev);
-       return ret;
+               return ret;
+
+       pci_set_drvdata(pdev, host);
+
+       return 0;
 }
 
 static void dw_mci_pci_remove(struct pci_dev *pdev)
@@ -90,32 +75,23 @@ static void dw_mci_pci_remove(struct pci_dev *pdev)
        struct dw_mci *host = pci_get_drvdata(pdev);
 
        dw_mci_remove(host);
-       pci_set_drvdata(pdev, NULL);
-       pci_release_regions(pdev);
-       pci_iounmap(pdev, host->regs);
-       kfree(host);
-       pci_disable_device(pdev);
 }
 
 #ifdef CONFIG_PM_SLEEP
 static int dw_mci_pci_suspend(struct device *dev)
 {
-       int ret;
        struct pci_dev *pdev = to_pci_dev(dev);
        struct dw_mci *host = pci_get_drvdata(pdev);
 
-       ret = dw_mci_suspend(host);
-       return ret;
+       return dw_mci_suspend(host);
 }
 
 static int dw_mci_pci_resume(struct device *dev)
 {
-       int ret;
        struct pci_dev *pdev = to_pci_dev(dev);
        struct dw_mci *host = pci_get_drvdata(pdev);
 
-       ret = dw_mci_resume(host);
-       return ret;
+       return dw_mci_resume(host);
 }
 #else
 #define dw_mci_pci_suspend     NULL
index 41c27b7..ee52556 100644 (file)
 
 #include "dw_mmc.h"
 
+static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
+{
+       *cmdr |= SDMMC_CMD_USE_HOLD_REG;
+}
+
+static const struct dw_mci_drv_data rockchip_drv_data = {
+       .prepare_command        = dw_mci_rockchip_prepare_command,
+};
+
 int dw_mci_pltfm_register(struct platform_device *pdev,
-                               const struct dw_mci_drv_data *drv_data)
+                         const struct dw_mci_drv_data *drv_data)
 {
        struct dw_mci *host;
        struct resource *regs;
@@ -35,10 +44,6 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
        if (!host)
                return -ENOMEM;
 
-       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!regs)
-               return -ENXIO;
-
        host->irq = platform_get_irq(pdev, 0);
        if (host->irq < 0)
                return host->irq;
@@ -47,6 +52,8 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
        host->dev = &pdev->dev;
        host->irq_flags = 0;
        host->pdata = pdev->dev.platform_data;
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        host->regs = devm_ioremap_resource(&pdev->dev, regs);
        if (IS_ERR(host->regs))
                return PTR_ERR(host->regs);
@@ -58,52 +65,26 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
        }
 
        platform_set_drvdata(pdev, host);
-       ret = dw_mci_probe(host);
-       return ret;
+       return dw_mci_probe(host);
 }
 EXPORT_SYMBOL_GPL(dw_mci_pltfm_register);
 
-static int dw_mci_pltfm_probe(struct platform_device *pdev)
-{
-       return dw_mci_pltfm_register(pdev, NULL);
-}
-
-static int dw_mci_pltfm_remove(struct platform_device *pdev)
-{
-       struct dw_mci *host = platform_get_drvdata(pdev);
-
-       platform_set_drvdata(pdev, NULL);
-       dw_mci_remove(host);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove);
-
 #ifdef CONFIG_PM_SLEEP
 /*
  * TODO: we should probably disable the clock to the card in the suspend path.
  */
 static int dw_mci_pltfm_suspend(struct device *dev)
 {
-       int ret;
        struct dw_mci *host = dev_get_drvdata(dev);
 
-       ret = dw_mci_suspend(host);
-       if (ret)
-               return ret;
-
-       return 0;
+       return dw_mci_suspend(host);
 }
 
 static int dw_mci_pltfm_resume(struct device *dev)
 {
-       int ret;
        struct dw_mci *host = dev_get_drvdata(dev);
 
-       ret = dw_mci_resume(host);
-       if (ret)
-               return ret;
-
-       return 0;
+       return dw_mci_resume(host);
 }
 #else
 #define dw_mci_pltfm_suspend   NULL
@@ -115,10 +96,34 @@ EXPORT_SYMBOL_GPL(dw_mci_pltfm_pmops);
 
 static const struct of_device_id dw_mci_pltfm_match[] = {
        { .compatible = "snps,dw-mshc", },
+       { .compatible = "rockchip,rk2928-dw-mshc",
+               .data = &rockchip_drv_data },
        {},
 };
 MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
 
+static int dw_mci_pltfm_probe(struct platform_device *pdev)
+{
+       const struct dw_mci_drv_data *drv_data = NULL;
+       const struct of_device_id *match;
+
+       if (pdev->dev.of_node) {
+               match = of_match_node(dw_mci_pltfm_match, pdev->dev.of_node);
+               drv_data = match->data;
+       }
+
+       return dw_mci_pltfm_register(pdev, drv_data);
+}
+
+int dw_mci_pltfm_remove(struct platform_device *pdev)
+{
+       struct dw_mci *host = platform_get_drvdata(pdev);
+
+       dw_mci_remove(host);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dw_mci_pltfm_remove);
+
 static struct platform_driver dw_mci_pltfm_driver = {
        .probe          = dw_mci_pltfm_probe,
        .remove         = dw_mci_pltfm_remove,
diff --git a/drivers/mmc/host/dw_mmc-socfpga.c b/drivers/mmc/host/dw_mmc-socfpga.c
new file mode 100644 (file)
index 0000000..14b5961
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * Altera SoCFPGA Specific Extensions for Synopsys DW Multimedia Card Interface
+ * driver
+ *
+ *  Copyright (C) 2012, Samsung Electronics Co., Ltd.
+ *  Copyright (C) 2013 Altera Corporation
+ *
+ * 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.
+ *
+ * Taken from dw_mmc-exynos.c
+ */
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/dw_mmc.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "dw_mmc.h"
+#include "dw_mmc-pltfm.h"
+
+#define SYSMGR_SDMMCGRP_CTRL_OFFSET            0x108
+#define DRV_CLK_PHASE_SHIFT_SEL_MASK   0x7
+#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel)          \
+       ((((smplsel) & 0x7) << 3) | (((drvsel) & 0x7) << 0))
+
+/* SOCFPGA implementation specific driver private data */
+struct dw_mci_socfpga_priv_data {
+       u8      ciu_div; /* card interface unit divisor */
+       u32     hs_timing; /* bitmask for CIU clock phase shift */
+       struct regmap   *sysreg; /* regmap for system manager register */
+};
+
+static int dw_mci_socfpga_priv_init(struct dw_mci *host)
+{
+       struct dw_mci_socfpga_priv_data *priv;
+
+       priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               dev_err(host->dev, "mem alloc failed for private data\n");
+               return -ENOMEM;
+       }
+
+       priv->sysreg = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
+       if (IS_ERR(priv->sysreg)) {
+               dev_err(host->dev, "regmap for altr,sys-mgr lookup failed.\n");
+               return PTR_ERR(priv->sysreg);
+       }
+       host->priv = priv;
+
+       return 0;
+}
+
+static int dw_mci_socfpga_setup_clock(struct dw_mci *host)
+{
+       struct dw_mci_socfpga_priv_data *priv = host->priv;
+
+       clk_disable_unprepare(host->ciu_clk);
+       regmap_write(priv->sysreg, SYSMGR_SDMMCGRP_CTRL_OFFSET,
+               priv->hs_timing);
+       clk_prepare_enable(host->ciu_clk);
+
+       host->bus_hz /= (priv->ciu_div + 1);
+       return 0;
+}
+
+static void dw_mci_socfpga_prepare_command(struct dw_mci *host, u32 *cmdr)
+{
+       struct dw_mci_socfpga_priv_data *priv = host->priv;
+
+       if (priv->hs_timing & DRV_CLK_PHASE_SHIFT_SEL_MASK)
+               *cmdr |= SDMMC_CMD_USE_HOLD_REG;
+}
+
+static int dw_mci_socfpga_parse_dt(struct dw_mci *host)
+{
+       struct dw_mci_socfpga_priv_data *priv = host->priv;
+       struct device_node *np = host->dev->of_node;
+       u32 timing[2];
+       u32 div = 0;
+       int ret;
+
+       ret = of_property_read_u32(np, "altr,dw-mshc-ciu-div", &div);
+       if (ret)
+               dev_info(host->dev, "No dw-mshc-ciu-div specified, assuming 1");
+       priv->ciu_div = div;
+
+       ret = of_property_read_u32_array(np,
+                       "altr,dw-mshc-sdr-timing", timing, 2);
+       if (ret)
+               return ret;
+
+       priv->hs_timing = SYSMGR_SDMMC_CTRL_SET(timing[0], timing[1]);
+       return 0;
+}
+
+static const struct dw_mci_drv_data socfpga_drv_data = {
+       .init                   = dw_mci_socfpga_priv_init,
+       .setup_clock            = dw_mci_socfpga_setup_clock,
+       .prepare_command        = dw_mci_socfpga_prepare_command,
+       .parse_dt               = dw_mci_socfpga_parse_dt,
+};
+
+static const struct of_device_id dw_mci_socfpga_match[] = {
+       { .compatible = "altr,socfpga-dw-mshc",
+                       .data = &socfpga_drv_data, },
+       {},
+};
+MODULE_DEVICE_TABLE(of, dw_mci_socfpga_match);
+
+int dw_mci_socfpga_probe(struct platform_device *pdev)
+{
+       const struct dw_mci_drv_data *drv_data;
+       const struct of_device_id *match;
+
+       match = of_match_node(dw_mci_socfpga_match, pdev->dev.of_node);
+       drv_data = match->data;
+       return dw_mci_pltfm_register(pdev, drv_data);
+}
+
+static struct platform_driver dw_mci_socfpga_pltfm_driver = {
+       .probe          = dw_mci_socfpga_probe,
+       .remove         = __exit_p(dw_mci_pltfm_remove),
+       .driver         = {
+               .name           = "dwmmc_socfpga",
+               .of_match_table = of_match_ptr(dw_mci_socfpga_match),
+               .pm             = &dw_mci_pltfm_pmops,
+       },
+};
+
+module_platform_driver(dw_mci_socfpga_pltfm_driver);
+
+MODULE_DESCRIPTION("Altera SOCFPGA Specific DW-MSHC Driver Extension");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:dwmmc-socfpga");
index bc3a1bc..ee5f167 100644 (file)
@@ -39,7 +39,7 @@
 #include "dw_mmc.h"
 
 /* Common flag combinations */
-#define DW_MCI_DATA_ERROR_FLAGS        (SDMMC_INT_DTO | SDMMC_INT_DCRC | \
+#define DW_MCI_DATA_ERROR_FLAGS        (SDMMC_INT_DRTO | SDMMC_INT_DCRC | \
                                 SDMMC_INT_HTO | SDMMC_INT_SBE  | \
                                 SDMMC_INT_EBE)
 #define DW_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | \
 #define DW_MCI_DMA_THRESHOLD   16
 
 #ifdef CONFIG_MMC_DW_IDMAC
+#define IDMAC_INT_CLR          (SDMMC_IDMAC_INT_AI | SDMMC_IDMAC_INT_NI | \
+                                SDMMC_IDMAC_INT_CES | SDMMC_IDMAC_INT_DU | \
+                                SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \
+                                SDMMC_IDMAC_INT_TI)
+
 struct idmac_desc {
        u32             des0;   /* Control Descriptor */
 #define IDMAC_DES0_DIC BIT(1)
@@ -433,6 +438,7 @@ static int dw_mci_idmac_init(struct dw_mci *host)
        mci_writel(host, BMOD, SDMMC_IDMAC_SWRESET);
 
        /* Mask out interrupts - get Tx & Rx complete only */
+       mci_writel(host, IDSTS, IDMAC_INT_CLR);
        mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI |
                   SDMMC_IDMAC_INT_TI);
 
@@ -1087,7 +1093,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
                        status = host->data_status;
 
                        if (status & DW_MCI_DATA_ERROR_FLAGS) {
-                               if (status & SDMMC_INT_DTO) {
+                               if (status & SDMMC_INT_DRTO) {
                                        data->error = -ETIMEDOUT;
                                } else if (status & SDMMC_INT_DCRC) {
                                        data->error = -EILSEQ;
@@ -1985,19 +1991,6 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 #endif /* CONFIG_MMC_DW_IDMAC */
        }
 
-       host->vmmc = devm_regulator_get(mmc_dev(mmc), "vmmc");
-       if (IS_ERR(host->vmmc)) {
-               pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
-               host->vmmc = NULL;
-       } else {
-               ret = regulator_enable(host->vmmc);
-               if (ret) {
-                       dev_err(host->dev,
-                               "failed to enable regulator: %d\n", ret);
-                       goto err_setup_bus;
-               }
-       }
-
        if (dw_mci_get_cd(mmc))
                set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
        else
@@ -2124,6 +2117,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
        struct device_node *np = dev->of_node;
        const struct dw_mci_drv_data *drv_data = host->drv_data;
        int idx, ret;
+       u32 clock_frequency;
 
        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata) {
@@ -2150,6 +2144,9 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
 
        of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
 
+       if (!of_property_read_u32(np, "clock-frequency", &clock_frequency))
+               pdata->bus_hz = clock_frequency;
+
        if (drv_data && drv_data->parse_dt) {
                ret = drv_data->parse_dt(host);
                if (ret)
@@ -2207,18 +2204,23 @@ int dw_mci_probe(struct dw_mci *host)
        host->ciu_clk = devm_clk_get(host->dev, "ciu");
        if (IS_ERR(host->ciu_clk)) {
                dev_dbg(host->dev, "ciu clock not available\n");
+               host->bus_hz = host->pdata->bus_hz;
        } else {
                ret = clk_prepare_enable(host->ciu_clk);
                if (ret) {
                        dev_err(host->dev, "failed to enable ciu clock\n");
                        goto err_clk_biu;
                }
-       }
 
-       if (IS_ERR(host->ciu_clk))
-               host->bus_hz = host->pdata->bus_hz;
-       else
+               if (host->pdata->bus_hz) {
+                       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",
+                                        host->pdata->bus_hz);
+               }
                host->bus_hz = clk_get_rate(host->ciu_clk);
+       }
 
        if (drv_data && drv_data->setup_clock) {
                ret = drv_data->setup_clock(host);
@@ -2229,11 +2231,29 @@ int dw_mci_probe(struct dw_mci *host)
                }
        }
 
+       host->vmmc = devm_regulator_get(host->dev, "vmmc");
+       if (IS_ERR(host->vmmc)) {
+               ret = PTR_ERR(host->vmmc);
+               if (ret == -EPROBE_DEFER)
+                       goto err_clk_ciu;
+
+               dev_info(host->dev, "no vmmc regulator found: %d\n", ret);
+               host->vmmc = NULL;
+       } else {
+               ret = regulator_enable(host->vmmc);
+               if (ret) {
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(host->dev,
+                                       "regulator_enable fail: %d\n", ret);
+                       goto err_clk_ciu;
+               }
+       }
+
        if (!host->bus_hz) {
                dev_err(host->dev,
                        "Platform data must supply bus speed\n");
                ret = -ENODEV;
-               goto err_clk_ciu;
+               goto err_regulator;
        }
 
        host->quirks = host->pdata->quirks;
@@ -2321,8 +2341,10 @@ int dw_mci_probe(struct dw_mci *host)
        tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
        host->card_workqueue = alloc_workqueue("dw-mci-card",
                        WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1);
-       if (!host->card_workqueue)
+       if (!host->card_workqueue) {
+               ret = -ENOMEM;
                goto err_dmaunmap;
+       }
        INIT_WORK(&host->card_work, dw_mci_work_routine_card);
        ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
                               host->irq_flags, "dw-mci", host);
@@ -2378,6 +2400,7 @@ 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 0b74189..81b2994 100644 (file)
@@ -98,7 +98,7 @@
 #define SDMMC_INT_HLE                  BIT(12)
 #define SDMMC_INT_FRUN                 BIT(11)
 #define SDMMC_INT_HTO                  BIT(10)
-#define SDMMC_INT_DTO                  BIT(9)
+#define SDMMC_INT_DRTO                 BIT(9)
 #define SDMMC_INT_RTO                  BIT(8)
 #define SDMMC_INT_DCRC                 BIT(7)
 #define SDMMC_INT_RCRC                 BIT(6)
 #define SDMMC_INT_ERROR                        0xbfc2
 /* Command register defines */
 #define SDMMC_CMD_START                        BIT(31)
+#define SDMMC_CMD_USE_HOLD_REG BIT(29)
 #define SDMMC_CMD_CCS_EXP              BIT(23)
 #define SDMMC_CMD_CEATA_RD             BIT(22)
 #define SDMMC_CMD_UPD_CLK              BIT(21)
index 2391c6b..0308c9f 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include <linux/mmc/host.h>
+#include <linux/mmc/slot-gpio.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/irq.h>
@@ -120,7 +121,6 @@ struct jz4740_mmc_host {
        int irq;
        int card_detect_irq;
 
-       struct resource *mem;
        void __iomem *base;
        struct mmc_request *req;
        struct mmc_command *cmd;
@@ -231,6 +231,14 @@ static void jz4740_mmc_transfer_check_state(struct jz4740_mmc_host *host,
                        host->req->cmd->error = -EIO;
                        data->error = -EIO;
                }
+       } else if (status & JZ_MMC_STATUS_READ_ERROR_MASK) {
+               if (status & (JZ_MMC_STATUS_TIMEOUT_READ)) {
+                       host->req->cmd->error = -ETIMEDOUT;
+                       data->error = -ETIMEDOUT;
+               } else {
+                       host->req->cmd->error = -EIO;
+                       data->error = -EIO;
+               }
        }
 }
 
@@ -560,11 +568,6 @@ static irqreturn_t jz_mmc_irq(int irq, void *devid)
                                        if (cmd->data)
                                                        cmd->data->error = -EIO;
                                        cmd->error = -EIO;
-                       } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR |
-                                       JZ_MMC_STATUS_CRC_WRITE_ERROR)) {
-                                       if (cmd->data)
-                                                       cmd->data->error = -EIO;
-                                       cmd->error = -EIO;
                        }
 
                        jz4740_mmc_set_irq_enabled(host, irq_reg, false);
@@ -626,7 +629,7 @@ static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                        gpio_set_value(host->pdata->gpio_power,
                                        !host->pdata->power_active_low);
                host->cmdat |= JZ_MMC_CMDAT_INIT;
-               clk_enable(host->clk);
+               clk_prepare_enable(host->clk);
                break;
        case MMC_POWER_ON:
                break;
@@ -634,7 +637,7 @@ static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                if (gpio_is_valid(host->pdata->gpio_power))
                        gpio_set_value(host->pdata->gpio_power,
                                        host->pdata->power_active_low);
-               clk_disable(host->clk);
+               clk_disable_unprepare(host->clk);
                break;
        }
 
@@ -650,35 +653,6 @@ static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        }
 }
 
-static int jz4740_mmc_get_ro(struct mmc_host *mmc)
-{
-       struct jz4740_mmc_host *host = mmc_priv(mmc);
-       if (!gpio_is_valid(host->pdata->gpio_read_only))
-               return -ENOSYS;
-
-       return gpio_get_value(host->pdata->gpio_read_only) ^
-               host->pdata->read_only_active_low;
-}
-
-static int jz4740_mmc_get_cd(struct mmc_host *mmc)
-{
-       struct jz4740_mmc_host *host = mmc_priv(mmc);
-       if (!gpio_is_valid(host->pdata->gpio_card_detect))
-               return -ENOSYS;
-
-       return gpio_get_value(host->pdata->gpio_card_detect) ^
-                       host->pdata->card_detect_active_low;
-}
-
-static irqreturn_t jz4740_mmc_card_detect_irq(int irq, void *devid)
-{
-       struct jz4740_mmc_host *host = devid;
-
-       mmc_detect_change(host->mmc, HZ / 2);
-
-       return IRQ_HANDLED;
-}
-
 static void jz4740_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
 {
        struct jz4740_mmc_host *host = mmc_priv(mmc);
@@ -688,8 +662,8 @@ static void jz4740_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
 static const struct mmc_host_ops jz4740_mmc_ops = {
        .request        = jz4740_mmc_request,
        .set_ios        = jz4740_mmc_set_ios,
-       .get_ro         = jz4740_mmc_get_ro,
-       .get_cd         = jz4740_mmc_get_cd,
+       .get_ro         = mmc_gpio_get_ro,
+       .get_cd         = mmc_gpio_get_cd,
        .enable_sdio_irq = jz4740_mmc_enable_sdio_irq,
 };
 
@@ -724,58 +698,34 @@ static int jz4740_mmc_request_gpio(struct device *dev, int gpio,
        return 0;
 }
 
-static int jz4740_mmc_request_gpios(struct platform_device *pdev)
+static int jz4740_mmc_request_gpios(struct mmc_host *mmc,
+       struct platform_device *pdev)
 {
-       int ret;
        struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
+       int ret = 0;
 
        if (!pdata)
                return 0;
 
-       ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_card_detect,
-                       "MMC detect change", false, 0);
-       if (ret)
-               goto err;
-
-       ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_read_only,
-                       "MMC read only", false, 0);
-       if (ret)
-               goto err_free_gpio_card_detect;
-
-       ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_power,
-                       "MMC read only", true, pdata->power_active_low);
-       if (ret)
-               goto err_free_gpio_read_only;
-
-       return 0;
-
-err_free_gpio_read_only:
-       if (gpio_is_valid(pdata->gpio_read_only))
-               gpio_free(pdata->gpio_read_only);
-err_free_gpio_card_detect:
-       if (gpio_is_valid(pdata->gpio_card_detect))
-               gpio_free(pdata->gpio_card_detect);
-err:
-       return ret;
-}
-
-static int jz4740_mmc_request_cd_irq(struct platform_device *pdev,
-       struct jz4740_mmc_host *host)
-{
-       struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
+       if (!pdata->card_detect_active_low)
+               mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
+       if (!pdata->read_only_active_low)
+               mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
 
-       if (!gpio_is_valid(pdata->gpio_card_detect))
-               return 0;
+       if (gpio_is_valid(pdata->gpio_card_detect)) {
+               ret = mmc_gpio_request_cd(mmc, pdata->gpio_card_detect);
+               if (ret)
+                       return ret;
+       }
 
-       host->card_detect_irq = gpio_to_irq(pdata->gpio_card_detect);
-       if (host->card_detect_irq < 0) {
-               dev_warn(&pdev->dev, "Failed to get card detect irq\n");
-               return 0;
+       if (gpio_is_valid(pdata->gpio_read_only)) {
+               ret = mmc_gpio_request_ro(mmc, pdata->gpio_read_only);
+               if (ret)
+                       return ret;
        }
 
-       return request_irq(host->card_detect_irq, jz4740_mmc_card_detect_irq,
-                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
-                       "MMC card detect", host);
+       return jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_power,
+                       "MMC read only", true, pdata->power_active_low);
 }
 
 static void jz4740_mmc_free_gpios(struct platform_device *pdev)
@@ -787,10 +737,6 @@ static void jz4740_mmc_free_gpios(struct platform_device *pdev)
 
        if (gpio_is_valid(pdata->gpio_power))
                gpio_free(pdata->gpio_power);
-       if (gpio_is_valid(pdata->gpio_read_only))
-               gpio_free(pdata->gpio_read_only);
-       if (gpio_is_valid(pdata->gpio_card_detect))
-               gpio_free(pdata->gpio_card_detect);
 }
 
 static inline size_t jz4740_mmc_num_pins(struct jz4740_mmc_host *host)
@@ -808,6 +754,7 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
        struct mmc_host *mmc;
        struct jz4740_mmc_host *host;
        struct jz4740_mmc_platform_data *pdata;
+       struct resource *res;
 
        pdata = pdev->dev.platform_data;
 
@@ -827,42 +774,28 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
                goto err_free_host;
        }
 
-       host->clk = clk_get(&pdev->dev, "mmc");
+       host->clk = devm_clk_get(&pdev->dev, "mmc");
        if (IS_ERR(host->clk)) {
                ret = PTR_ERR(host->clk);
                dev_err(&pdev->dev, "Failed to get mmc clock\n");
                goto err_free_host;
        }
 
-       host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!host->mem) {
-               ret = -ENOENT;
-               dev_err(&pdev->dev, "Failed to get base platform memory\n");
-               goto err_clk_put;
-       }
-
-       host->mem = request_mem_region(host->mem->start,
-                                       resource_size(host->mem), pdev->name);
-       if (!host->mem) {
-               ret = -EBUSY;
-               dev_err(&pdev->dev, "Failed to request base memory region\n");
-               goto err_clk_put;
-       }
-
-       host->base = ioremap_nocache(host->mem->start, resource_size(host->mem));
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       host->base = devm_ioremap_resource(&pdev->dev, res);
        if (!host->base) {
                ret = -EBUSY;
                dev_err(&pdev->dev, "Failed to ioremap base memory\n");
-               goto err_release_mem_region;
+               goto err_free_host;
        }
 
        ret = jz_gpio_bulk_request(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
        if (ret) {
                dev_err(&pdev->dev, "Failed to request mmc pins: %d\n", ret);
-               goto err_iounmap;
+               goto err_free_host;
        }
 
-       ret = jz4740_mmc_request_gpios(pdev);
+       ret = jz4740_mmc_request_gpios(mmc, pdev);
        if (ret)
                goto err_gpio_bulk_free;
 
@@ -885,17 +818,11 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
        spin_lock_init(&host->lock);
        host->irq_mask = 0xffff;
 
-       ret = jz4740_mmc_request_cd_irq(pdev, host);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to request card detect irq\n");
-               goto err_free_gpios;
-       }
-
        ret = request_threaded_irq(host->irq, jz_mmc_irq, jz_mmc_irq_worker, 0,
                        dev_name(&pdev->dev), host);
        if (ret) {
                dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
-               goto err_free_card_detect_irq;
+               goto err_free_gpios;
        }
 
        jz4740_mmc_reset(host);
@@ -918,21 +845,11 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
 
 err_free_irq:
        free_irq(host->irq, host);
-err_free_card_detect_irq:
-       if (host->card_detect_irq >= 0)
-               free_irq(host->card_detect_irq, host);
 err_free_gpios:
        jz4740_mmc_free_gpios(pdev);
 err_gpio_bulk_free:
        jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-err_iounmap:
-       iounmap(host->base);
-err_release_mem_region:
-       release_mem_region(host->mem->start, resource_size(host->mem));
-err_clk_put:
-       clk_put(host->clk);
 err_free_host:
-       platform_set_drvdata(pdev, NULL);
        mmc_free_host(mmc);
 
        return ret;
@@ -949,24 +866,16 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
        mmc_remove_host(host->mmc);
 
        free_irq(host->irq, host);
-       if (host->card_detect_irq >= 0)
-               free_irq(host->card_detect_irq, host);
 
        jz4740_mmc_free_gpios(pdev);
        jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
 
-       iounmap(host->base);
-       release_mem_region(host->mem->start, resource_size(host->mem));
-
-       clk_put(host->clk);
-
-       platform_set_drvdata(pdev, NULL);
        mmc_free_host(host->mmc);
 
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
 static int jz4740_mmc_suspend(struct device *dev)
 {
@@ -990,13 +899,8 @@ static int jz4740_mmc_resume(struct device *dev)
        return 0;
 }
 
-const struct dev_pm_ops jz4740_mmc_pm_ops = {
-       .suspend        = jz4740_mmc_suspend,
-       .resume         = jz4740_mmc_resume,
-       .poweroff       = jz4740_mmc_suspend,
-       .restore        = jz4740_mmc_resume,
-};
-
+static SIMPLE_DEV_PM_OPS(jz4740_mmc_pm_ops, jz4740_mmc_suspend,
+       jz4740_mmc_resume);
 #define JZ4740_MMC_PM_OPS (&jz4740_mmc_pm_ops)
 #else
 #define JZ4740_MMC_PM_OPS NULL
index 8960fc8..4ddd83f 100644 (file)
@@ -35,7 +35,7 @@
 
 #define DRIVER_NAME    "mvsdio"
 
-static int maxfreq = MVSD_CLOCKRATE_MAX;
+static int maxfreq;
 static int nodma;
 
 struct mvsd_host {
@@ -685,7 +685,6 @@ static int __init mvsd_probe(struct platform_device *pdev)
        const struct mbus_dram_target_info *dram;
        struct resource *r;
        int ret, irq;
-       int gpio_card_detect, gpio_write_protect;
        struct pinctrl *pinctrl;
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -718,6 +717,20 @@ static int __init mvsd_probe(struct platform_device *pdev)
        if (!IS_ERR(host->clk))
                clk_prepare_enable(host->clk);
 
+       mmc->ops = &mvsd_ops;
+
+       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+       mmc->f_min = DIV_ROUND_UP(host->base_clock, MVSD_BASE_DIV_MAX);
+       mmc->f_max = MVSD_CLOCKRATE_MAX;
+
+       mmc->max_blk_size = 2048;
+       mmc->max_blk_count = 65535;
+
+       mmc->max_segs = 1;
+       mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count;
+       mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+
        if (np) {
                if (IS_ERR(host->clk)) {
                        dev_err(&pdev->dev, "DT platforms must have a clock associated\n");
@@ -726,35 +739,38 @@ static int __init mvsd_probe(struct platform_device *pdev)
                }
 
                host->base_clock = clk_get_rate(host->clk) / 2;
-               gpio_card_detect = of_get_named_gpio(np, "cd-gpios", 0);
-               gpio_write_protect = of_get_named_gpio(np, "wp-gpios", 0);
+               ret = mmc_of_parse(mmc);
+               if (ret < 0)
+                       goto out;
        } else {
                const struct mvsdio_platform_data *mvsd_data;
+
                mvsd_data = pdev->dev.platform_data;
                if (!mvsd_data) {
                        ret = -ENXIO;
                        goto out;
                }
+               mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ |
+                           MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
                host->base_clock = mvsd_data->clock / 2;
-               gpio_card_detect = mvsd_data->gpio_card_detect ? : -EINVAL;
-               gpio_write_protect = mvsd_data->gpio_write_protect ? : -EINVAL;
-       }
-
-       mmc->ops = &mvsd_ops;
-
-       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ |
-                   MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
-
-       mmc->f_min = DIV_ROUND_UP(host->base_clock, MVSD_BASE_DIV_MAX);
-       mmc->f_max = maxfreq;
+               /* GPIO 0 regarded as invalid for backward compatibility */
+               if (mvsd_data->gpio_card_detect &&
+                   gpio_is_valid(mvsd_data->gpio_card_detect)) {
+                       ret = mmc_gpio_request_cd(mmc,
+                                                 mvsd_data->gpio_card_detect);
+                       if (ret)
+                               goto out;
+               } else {
+                       mmc->caps |= MMC_CAP_NEEDS_POLL;
+               }
 
-       mmc->max_blk_size = 2048;
-       mmc->max_blk_count = 65535;
+               if (mvsd_data->gpio_write_protect &&
+                   gpio_is_valid(mvsd_data->gpio_write_protect))
+                       mmc_gpio_request_ro(mmc, mvsd_data->gpio_write_protect);
+       }
 
-       mmc->max_segs = 1;
-       mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count;
-       mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+       if (maxfreq)
+               mmc->f_max = maxfreq;
 
        spin_lock_init(&host->lock);
 
@@ -777,15 +793,6 @@ static int __init mvsd_probe(struct platform_device *pdev)
                goto out;
        }
 
-       if (gpio_is_valid(gpio_card_detect)) {
-               ret = mmc_gpio_request_cd(mmc, gpio_card_detect);
-               if (ret)
-                       goto out;
-       } else
-               mmc->caps |= MMC_CAP_NEEDS_POLL;
-
-       mmc_gpio_request_ro(mmc, gpio_write_protect);
-
        setup_timer(&host->timer, mvsd_timeout_timer, (unsigned long)host);
        platform_set_drvdata(pdev, mmc);
        ret = mmc_add_host(mmc);
@@ -793,10 +800,10 @@ static int __init mvsd_probe(struct platform_device *pdev)
                goto out;
 
        if (!(mmc->caps & MMC_CAP_NEEDS_POLL))
-               dev_notice(&pdev->dev, "using GPIO %d for card detection\n",
-                          gpio_card_detect);
+               dev_notice(&pdev->dev, "using GPIO for card detection\n");
        else
-               dev_notice(&pdev->dev, "lacking card detect (fall back to polling)\n");
+               dev_notice(&pdev->dev,
+                          "lacking card detect (fall back to polling)\n");
        return 0;
 
 out:
@@ -827,7 +834,6 @@ static int __exit mvsd_remove(struct platform_device *pdev)
                clk_disable_unprepare(host->clk);
        mmc_free_host(mmc);
 
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
index d503635..c174c6a 100644 (file)
@@ -1067,7 +1067,9 @@ static int mxcmci_probe(struct platform_device *pdev)
                goto out_release_mem;
        }
 
-       mmc_of_parse(mmc);
+       ret = mmc_of_parse(mmc);
+       if (ret)
+               goto out_free;
        mmc->ops = &mxcmci_ops;
 
        /* For devicetree parsing, the bus width is read from devicetree */
@@ -1219,8 +1221,6 @@ static int mxcmci_remove(struct platform_device *pdev)
        struct mmc_host *mmc = platform_get_drvdata(pdev);
        struct mxcmci_host *host = mmc_priv(mmc);
 
-       platform_set_drvdata(pdev, NULL);
-
        mmc_remove_host(mmc);
 
        if (host->vcc)
index 4278a17..f38d75f 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
 #include <linux/module.h>
-#include <linux/pinctrl/consumer.h>
 #include <linux/stmp_device.h>
 #include <linux/spi/mxs-spi.h>
 
@@ -580,7 +579,6 @@ static int mxs_mmc_probe(struct platform_device *pdev)
        struct mxs_mmc_host *host;
        struct mmc_host *mmc;
        struct resource *iores;
-       struct pinctrl *pinctrl;
        int ret = 0, irq_err;
        struct regulator *reg_vmmc;
        enum of_gpio_flags flags;
@@ -620,12 +618,6 @@ static int mxs_mmc_probe(struct platform_device *pdev)
                }
        }
 
-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl)) {
-               ret = PTR_ERR(pinctrl);
-               goto out_mmc_free;
-       }
-
        ssp->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(ssp->clk)) {
                ret = PTR_ERR(ssp->clk);
@@ -639,6 +631,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
        if (!ssp->dmach) {
                dev_err(mmc_dev(host->mmc),
                        "%s: failed to request dma\n", __func__);
+               ret = -ENODEV;
                goto out_clk_put;
        }
 
@@ -708,8 +701,6 @@ static int mxs_mmc_remove(struct platform_device *pdev)
 
        mmc_remove_host(mmc);
 
-       platform_set_drvdata(pdev, NULL);
-
        if (ssp->dmach)
                dma_release_channel(ssp->dmach);
 
index 4254975..b94f38e 100644 (file)
@@ -1413,33 +1413,17 @@ static int mmc_omap_probe(struct platform_device *pdev)
        else
                sig = host->id == 0 ? OMAP_DMA_MMC_TX : OMAP_DMA_MMC2_TX;
        host->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
-#if 0
-       if (!host->dma_tx) {
-               dev_err(host->dev, "unable to obtain TX DMA engine channel %u\n",
-                       sig);
-               goto err_dma;
-       }
-#else
        if (!host->dma_tx)
                dev_warn(host->dev, "unable to obtain TX DMA engine channel %u\n",
                        sig);
-#endif
        if (mmc_omap2())
                sig = host->id == 0 ? OMAP24XX_DMA_MMC1_RX : OMAP24XX_DMA_MMC2_RX;
        else
                sig = host->id == 0 ? OMAP_DMA_MMC_RX : OMAP_DMA_MMC2_RX;
        host->dma_rx = dma_request_channel(mask, omap_dma_filter_fn, &sig);
-#if 0
-       if (!host->dma_rx) {
-               dev_err(host->dev, "unable to obtain RX DMA engine channel %u\n",
-                       sig);
-               goto err_dma;
-       }
-#else
        if (!host->dma_rx)
                dev_warn(host->dev, "unable to obtain RX DMA engine channel %u\n",
                        sig);
-#endif
 
        ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host);
        if (ret)
@@ -1500,8 +1484,6 @@ static int mmc_omap_remove(struct platform_device *pdev)
        struct mmc_omap_host *host = platform_get_drvdata(pdev);
        int i;
 
-       platform_set_drvdata(pdev, NULL);
-
        BUG_ON(host == NULL);
 
        for (i = 0; i < host->nr_slots; i++)
index eccedc7..1865321 100644 (file)
@@ -2047,7 +2047,6 @@ err_irq:
        }
 err1:
        iounmap(host->base);
-       platform_set_drvdata(pdev, NULL);
        mmc_free_host(mmc);
 err_alloc:
        omap_hsmmc_gpio_free(pdata);
@@ -2093,7 +2092,6 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res)
                release_mem_region(res->start, resource_size(res));
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index 2b2f65a..847b199 100644 (file)
@@ -834,8 +834,6 @@ static int pxamci_remove(struct platform_device *pdev)
        struct mmc_host *mmc = platform_get_drvdata(pdev);
        int gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
 
-       platform_set_drvdata(pdev, NULL);
-
        if (mmc) {
                struct pxamci_host *host = mmc_priv(mmc);
 
index ad13f42..82a35b9 100644 (file)
@@ -1316,8 +1316,6 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
        mmc_remove_host(mmc);
        mmc_free_host(mmc);
 
-       platform_set_drvdata(pdev, NULL);
-
        dev_dbg(&(pdev->dev),
                ": Realtek PCI-E SDMMC controller has been removed\n");
 
index 706d9cb..cdd4ce0 100644 (file)
 #include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/err.h>
+#include <linux/gpio.h>
 #include <linux/interrupt.h>
 #include <linux/acpi.h>
+#include <linux/acpi_gpio.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
+#include <linux/delay.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/pm.h>
@@ -83,12 +86,37 @@ static int sdhci_acpi_enable_dma(struct sdhci_host *host)
        return 0;
 }
 
+static void sdhci_acpi_int_hw_reset(struct sdhci_host *host)
+{
+       u8 reg;
+
+       reg = sdhci_readb(host, SDHCI_POWER_CONTROL);
+       reg |= 0x10;
+       sdhci_writeb(host, reg, SDHCI_POWER_CONTROL);
+       /* For eMMC, minimum is 1us but give it 9us for good measure */
+       udelay(9);
+       reg &= ~0x10;
+       sdhci_writeb(host, reg, SDHCI_POWER_CONTROL);
+       /* For eMMC, minimum is 200us but give it 300us for good measure */
+       usleep_range(300, 1000);
+}
+
 static const struct sdhci_ops sdhci_acpi_ops_dflt = {
        .enable_dma = sdhci_acpi_enable_dma,
 };
 
+static const struct sdhci_ops sdhci_acpi_ops_int = {
+       .enable_dma = sdhci_acpi_enable_dma,
+       .hw_reset   = sdhci_acpi_int_hw_reset,
+};
+
+static const struct sdhci_acpi_chip sdhci_acpi_chip_int = {
+       .ops = &sdhci_acpi_ops_int,
+};
+
 static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
-       .caps    = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE,
+       .chip    = &sdhci_acpi_chip_int,
+       .caps    = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | MMC_CAP_HW_RESET,
        .caps2   = MMC_CAP2_HC_ERASE_SZ,
        .flags   = SDHCI_ACPI_RUNTIME_PM,
 };
@@ -101,6 +129,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
 };
 
 static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
+       .flags   = SDHCI_ACPI_SD_CD | SDHCI_ACPI_RUNTIME_PM,
+       .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON,
 };
 
 struct sdhci_acpi_uid_slot {
@@ -161,6 +191,59 @@ static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(acpi_handle handle,
        return slot;
 }
 
+#ifdef CONFIG_PM_RUNTIME
+
+static irqreturn_t sdhci_acpi_sd_cd(int irq, void *dev_id)
+{
+       mmc_detect_change(dev_id, msecs_to_jiffies(200));
+       return IRQ_HANDLED;
+}
+
+static int sdhci_acpi_add_own_cd(struct device *dev, int gpio,
+                                struct mmc_host *mmc)
+{
+       unsigned long flags;
+       int err, irq;
+
+       if (gpio < 0) {
+               err = gpio;
+               goto out;
+       }
+
+       err = devm_gpio_request_one(dev, gpio, GPIOF_DIR_IN, "sd_cd");
+       if (err)
+               goto out;
+
+       irq = gpio_to_irq(gpio);
+       if (irq < 0) {
+               err = irq;
+               goto out_free;
+       }
+
+       flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
+       err = devm_request_irq(dev, irq, sdhci_acpi_sd_cd, flags, "sd_cd", mmc);
+       if (err)
+               goto out_free;
+
+       return 0;
+
+out_free:
+       devm_gpio_free(dev, gpio);
+out:
+       dev_warn(dev, "failed to setup card detect wake up\n");
+       return err;
+}
+
+#else
+
+static int sdhci_acpi_add_own_cd(struct device *dev, int gpio,
+                                struct mmc_host *mmc)
+{
+       return 0;
+}
+
+#endif
+
 static int sdhci_acpi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -171,7 +254,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        struct resource *iomem;
        resource_size_t len;
        const char *hid;
-       int err;
+       int err, gpio;
 
        if (acpi_bus_get_device(handle, &device))
                return -ENODEV;
@@ -196,6 +279,8 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        if (IS_ERR(host))
                return PTR_ERR(host);
 
+       gpio = acpi_get_gpio_by_index(dev, 0, NULL);
+
        c = sdhci_priv(host);
        c->host = host;
        c->slot = sdhci_acpi_get_slot(handle, hid);
@@ -251,6 +336,11 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        if (err)
                goto err_free;
 
+       if (sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD)) {
+               if (sdhci_acpi_add_own_cd(dev, gpio, host->mmc))
+                       c->use_runtime_pm = false;
+       }
+
        if (c->use_runtime_pm) {
                pm_runtime_set_active(dev);
                pm_suspend_ignore_children(dev, 1);
@@ -262,7 +352,6 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        return 0;
 
 err_free:
-       platform_set_drvdata(pdev, NULL);
        sdhci_free_host(c->host);
        return err;
 }
@@ -281,7 +370,6 @@ static int sdhci_acpi_remove(struct platform_device *pdev)
 
        dead = (sdhci_readl(c->host, SDHCI_INT_STATUS) == ~0);
        sdhci_remove_host(c->host, dead);
-       platform_set_drvdata(pdev, NULL);
        sdhci_free_host(c->host);
 
        return 0;
diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c
new file mode 100644 (file)
index 0000000..87175f9
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2013 Broadcom Corporation
+ *
+ * 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 version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/highmem.h>
+#include <linux/platform_device.h>
+#include <linux/mmc/host.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/version.h>
+#include <linux/mmc/slot-gpio.h>
+
+#include "sdhci-pltfm.h"
+#include "sdhci.h"
+
+#define SDHCI_SOFT_RESET                       0x01000000
+#define KONA_SDHOST_CORECTRL                   0x8000
+#define KONA_SDHOST_CD_PINCTRL                 0x00000008
+#define KONA_SDHOST_STOP_HCLK                  0x00000004
+#define KONA_SDHOST_RESET                      0x00000002
+#define KONA_SDHOST_EN                         0x00000001
+
+#define KONA_SDHOST_CORESTAT                   0x8004
+#define KONA_SDHOST_WP                         0x00000002
+#define KONA_SDHOST_CD_SW                      0x00000001
+
+#define KONA_SDHOST_COREIMR                    0x8008
+#define KONA_SDHOST_IP                         0x00000001
+
+#define KONA_SDHOST_COREISR                    0x800C
+#define KONA_SDHOST_COREIMSR                   0x8010
+#define KONA_SDHOST_COREDBG1                   0x8014
+#define KONA_SDHOST_COREGPO_MASK               0x8018
+
+#define SD_DETECT_GPIO_DEBOUNCE_128MS          128
+
+#define KONA_MMC_AUTOSUSPEND_DELAY             (50)
+
+struct sdhci_bcm_kona_dev {
+       struct mutex    write_lock; /* protect back to back writes */
+};
+
+
+static int sdhci_bcm_kona_sd_reset(struct sdhci_host *host)
+{
+       unsigned int val;
+       unsigned long timeout;
+
+       /* This timeout should be sufficent for core to reset */
+       timeout = jiffies + msecs_to_jiffies(100);
+
+       /* reset the host using the top level reset */
+       val = sdhci_readl(host, KONA_SDHOST_CORECTRL);
+       val |= KONA_SDHOST_RESET;
+       sdhci_writel(host, val, KONA_SDHOST_CORECTRL);
+
+       while (!(sdhci_readl(host, KONA_SDHOST_CORECTRL) & KONA_SDHOST_RESET)) {
+               if (time_is_before_jiffies(timeout)) {
+                       pr_err("Error: sd host is stuck in reset!!!\n");
+                       return -EFAULT;
+               }
+       }
+
+       /* bring the host out of reset */
+       val = sdhci_readl(host, KONA_SDHOST_CORECTRL);
+       val &= ~KONA_SDHOST_RESET;
+
+       /*
+        * Back-to-Back register write needs a delay of 1ms at bootup (min 10uS)
+        * Back-to-Back writes to same register needs delay when SD bus clock
+        * is very low w.r.t AHB clock, mainly during boot-time and during card
+        * insert-removal.
+        */
+       usleep_range(1000, 5000);
+       sdhci_writel(host, val, KONA_SDHOST_CORECTRL);
+
+       return 0;
+}
+
+static void sdhci_bcm_kona_sd_init(struct sdhci_host *host)
+{
+       unsigned int val;
+
+       /* enable the interrupt from the IP core */
+       val = sdhci_readl(host, KONA_SDHOST_COREIMR);
+       val |= KONA_SDHOST_IP;
+       sdhci_writel(host, val, KONA_SDHOST_COREIMR);
+
+       /* Enable the AHB clock gating module to the host */
+       val = sdhci_readl(host, KONA_SDHOST_CORECTRL);
+       val |= KONA_SDHOST_EN;
+
+       /*
+        * Back-to-Back register write needs a delay of 1ms at bootup (min 10uS)
+        * Back-to-Back writes to same register needs delay when SD bus clock
+        * is very low w.r.t AHB clock, mainly during boot-time and during card
+        * insert-removal.
+        */
+       usleep_range(1000, 5000);
+       sdhci_writel(host, val, KONA_SDHOST_CORECTRL);
+}
+
+/*
+ * Software emulation of the SD card insertion/removal. Set insert=1 for insert
+ * and insert=0 for removal. The card detection is done by GPIO. For Broadcom
+ * IP to function properly the bit 0 of CORESTAT register needs to be set/reset
+ * to generate the CD IRQ handled in sdhci.c which schedules card_tasklet.
+ */
+static int sdhci_bcm_kona_sd_card_emulate(struct sdhci_host *host, int insert)
+{
+       struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host);
+       struct sdhci_bcm_kona_dev *kona_dev = sdhci_pltfm_priv(pltfm_priv);
+       u32 val;
+
+       /*
+        * Back-to-Back register write needs a delay of min 10uS.
+        * Back-to-Back writes to same register needs delay when SD bus clock
+        * is very low w.r.t AHB clock, mainly during boot-time and during card
+        * insert-removal.
+        * We keep 20uS
+        */
+       mutex_lock(&kona_dev->write_lock);
+       udelay(20);
+       val = sdhci_readl(host, KONA_SDHOST_CORESTAT);
+
+       if (insert) {
+               int ret;
+
+               ret = mmc_gpio_get_ro(host->mmc);
+               if (ret >= 0)
+                       val = (val & ~KONA_SDHOST_WP) |
+                               ((ret) ? KONA_SDHOST_WP : 0);
+
+               val |= KONA_SDHOST_CD_SW;
+               sdhci_writel(host, val, KONA_SDHOST_CORESTAT);
+       } else {
+               val &= ~KONA_SDHOST_CD_SW;
+               sdhci_writel(host, val, KONA_SDHOST_CORESTAT);
+       }
+       mutex_unlock(&kona_dev->write_lock);
+
+       return 0;
+}
+
+/*
+ * SD card interrupt event callback
+ */
+void sdhci_bcm_kona_card_event(struct sdhci_host *host)
+{
+       if (mmc_gpio_get_cd(host->mmc) > 0) {
+               dev_dbg(mmc_dev(host->mmc),
+                       "card inserted\n");
+               sdhci_bcm_kona_sd_card_emulate(host, 1);
+       } else {
+               dev_dbg(mmc_dev(host->mmc),
+                       "card removed\n");
+               sdhci_bcm_kona_sd_card_emulate(host, 0);
+       }
+}
+
+/*
+ * Get the base clock. Use central clock source for now. Not sure if different
+ * clock speed to each dev is allowed
+ */
+static unsigned int sdhci_bcm_kona_get_max_clk(struct sdhci_host *host)
+{
+       struct sdhci_bcm_kona_dev *kona_dev;
+       struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host);
+       kona_dev = sdhci_pltfm_priv(pltfm_priv);
+
+       return host->mmc->f_max;
+}
+
+static unsigned int sdhci_bcm_kona_get_timeout_clock(struct sdhci_host *host)
+{
+       return sdhci_bcm_kona_get_max_clk(host);
+}
+
+static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host,
+                               u8 power_mode)
+{
+       /*
+        *  JEDEC and SD spec specify supplying 74 continuous clocks to
+        * device after power up. With minimum bus (100KHz) that
+        * that translates to 740us
+        */
+       if (power_mode != MMC_POWER_OFF)
+               udelay(740);
+}
+
+static struct sdhci_ops sdhci_bcm_kona_ops = {
+       .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,
+       .card_event = sdhci_bcm_kona_card_event,
+};
+
+static struct sdhci_pltfm_data sdhci_pltfm_data_kona = {
+       .ops    = &sdhci_bcm_kona_ops,
+       .quirks = SDHCI_QUIRK_NO_CARD_NO_RESET |
+               SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_32BIT_DMA_ADDR |
+               SDHCI_QUIRK_32BIT_DMA_SIZE | SDHCI_QUIRK_32BIT_ADMA_SIZE |
+               SDHCI_QUIRK_FORCE_BLK_SZ_2048 |
+               SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+};
+
+static const struct of_device_id sdhci_bcm_kona_of_match[] __initdata = {
+       { .compatible = "bcm,kona-sdhci"},
+       {}
+};
+MODULE_DEVICE_TABLE(of, sdhci_bcm_kona_of_match);
+
+static int __init sdhci_bcm_kona_probe(struct platform_device *pdev)
+{
+       struct sdhci_bcm_kona_dev *kona_dev = NULL;
+       struct sdhci_pltfm_host *pltfm_priv;
+       struct device *dev = &pdev->dev;
+       struct sdhci_host *host;
+       int ret;
+
+       ret = 0;
+
+       host = sdhci_pltfm_init(pdev, &sdhci_pltfm_data_kona,
+                       sizeof(*kona_dev));
+       if (IS_ERR(host))
+               return PTR_ERR(host);
+
+       dev_dbg(dev, "%s: inited. IOADDR=%p\n", __func__, host->ioaddr);
+
+       pltfm_priv = sdhci_priv(host);
+
+       kona_dev = sdhci_pltfm_priv(pltfm_priv);
+       mutex_init(&kona_dev->write_lock);
+
+       mmc_of_parse(host->mmc);
+
+       if (!host->mmc->f_max) {
+               dev_err(&pdev->dev, "Missing max-freq for SDHCI cfg\n");
+               ret = -ENXIO;
+               goto err_pltfm_free;
+       }
+
+       dev_dbg(dev, "non-removable=%c\n",
+               (host->mmc->caps & MMC_CAP_NONREMOVABLE) ? 'Y' : 'N');
+       dev_dbg(dev, "cd_gpio %c, wp_gpio %c\n",
+               (mmc_gpio_get_cd(host->mmc) != -ENOSYS) ? 'Y' : 'N',
+               (mmc_gpio_get_ro(host->mmc) != -ENOSYS) ? 'Y' : 'N');
+
+       if (host->mmc->caps | MMC_CAP_NONREMOVABLE)
+               host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+
+       dev_dbg(dev, "is_8bit=%c\n",
+               (host->mmc->caps | MMC_CAP_8_BIT_DATA) ? 'Y' : 'N');
+
+       ret = sdhci_bcm_kona_sd_reset(host);
+       if (ret)
+               goto err_pltfm_free;
+
+       sdhci_bcm_kona_sd_init(host);
+
+       ret = sdhci_add_host(host);
+       if (ret) {
+               dev_err(dev, "Failed sdhci_add_host\n");
+               goto err_reset;
+       }
+
+       /* if device is eMMC, emulate card insert right here */
+       if (host->mmc->caps | MMC_CAP_NONREMOVABLE) {
+               ret = sdhci_bcm_kona_sd_card_emulate(host, 1);
+               if (ret) {
+                       dev_err(dev,
+                               "unable to emulate card insertion\n");
+                       goto err_remove_host;
+               }
+       }
+       /*
+        * Since the card detection GPIO interrupt is configured to be
+        * edge sensitive, check the initial GPIO value here, emulate
+        * only if the card is present
+        */
+       if (mmc_gpio_get_cd(host->mmc) > 0)
+               sdhci_bcm_kona_sd_card_emulate(host, 1);
+
+       dev_dbg(dev, "initialized properly\n");
+       return 0;
+
+err_remove_host:
+       sdhci_remove_host(host, 0);
+
+err_reset:
+       sdhci_bcm_kona_sd_reset(host);
+
+err_pltfm_free:
+       sdhci_pltfm_free(pdev);
+
+       dev_err(dev, "Probing of sdhci-pltfm failed: %d\n", ret);
+       return ret;
+}
+
+static int __exit sdhci_bcm_kona_remove(struct platform_device *pdev)
+{
+       struct sdhci_host *host = platform_get_drvdata(pdev);
+       int dead;
+       u32 scratch;
+
+       dead = 0;
+       scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
+       if (scratch == (u32)-1)
+               dead = 1;
+       sdhci_remove_host(host, dead);
+
+       sdhci_free_host(host);
+
+       return 0;
+}
+
+static struct platform_driver sdhci_bcm_kona_driver = {
+       .driver         = {
+               .name   = "sdhci-kona",
+               .owner  = THIS_MODULE,
+               .pm     = SDHCI_PLTFM_PMOPS,
+               .of_match_table = of_match_ptr(sdhci_bcm_kona_of_match),
+       },
+       .probe          = sdhci_bcm_kona_probe,
+       .remove         = __exit_p(sdhci_bcm_kona_remove),
+};
+module_platform_driver(sdhci_bcm_kona_driver);
+
+MODULE_DESCRIPTION("SDHCI driver for Broadcom Kona platform");
+MODULE_AUTHOR("Broadcom");
+MODULE_LICENSE("GPL v2");
index d49bc95..0584a1c 100644 (file)
@@ -148,7 +148,7 @@ static int bcm2835_sdhci_probe(struct platform_device *pdev)
        struct sdhci_pltfm_host *pltfm_host;
        int ret;
 
-       host = sdhci_pltfm_init(pdev, &bcm2835_sdhci_pdata);
+       host = sdhci_pltfm_init(pdev, &bcm2835_sdhci_pdata, 0);
        if (IS_ERR(host))
                return PTR_ERR(host);
 
index 8ebb6b6..f2cc266 100644 (file)
@@ -96,7 +96,7 @@ static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
 
 static int sdhci_cns3xxx_probe(struct platform_device *pdev)
 {
-       return sdhci_pltfm_register(pdev, &sdhci_cns3xxx_pdata);
+       return sdhci_pltfm_register(pdev, &sdhci_cns3xxx_pdata, 0);
 }
 
 static int sdhci_cns3xxx_remove(struct platform_device *pdev)
index 15e7803..8424839 100644 (file)
@@ -130,7 +130,7 @@ static int sdhci_dove_probe(struct platform_device *pdev)
                gpio_direction_input(priv->gpio_cd);
        }
 
-       host = sdhci_pltfm_init(pdev, &sdhci_dove_pdata);
+       host = sdhci_pltfm_init(pdev, &sdhci_dove_pdata, 0);
        if (IS_ERR(host)) {
                ret = PTR_ERR(host);
                goto err_sdhci_pltfm_init;
index d5f0d59..1dd5ba8 100644 (file)
@@ -384,6 +384,20 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
        }
 }
 
+static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host)
+{
+       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;
+
+       u32 f_host = clk_get_rate(pltfm_host->clk);
+
+       if (boarddata->f_max && (boarddata->f_max < f_host))
+               return boarddata->f_max;
+       else
+               return f_host;
+}
+
 static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -391,6 +405,14 @@ static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
        return clk_get_rate(pltfm_host->clk) / 256 / 16;
 }
 
+static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
+                                        unsigned int clock)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+       esdhc_set_clock(host, clock, clk_get_rate(pltfm_host->clk));
+}
+
 static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -438,8 +460,8 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
        .write_l = esdhc_writel_le,
        .write_w = esdhc_writew_le,
        .write_b = esdhc_writeb_le,
-       .set_clock = esdhc_set_clock,
-       .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+       .set_clock = esdhc_pltfm_set_clock,
+       .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,
@@ -482,6 +504,8 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
 
        of_property_read_u32(np, "bus-width", &boarddata->max_bus_width);
 
+       of_property_read_u32(np, "max-frequency", &boarddata->f_max);
+
        return 0;
 }
 #else
@@ -503,7 +527,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
        int err;
        struct pltfm_imx_data *imx_data;
 
-       host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata);
+       host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata, 0);
        if (IS_ERR(host))
                return PTR_ERR(host);
 
index d25f9ab..a2a0642 100644 (file)
 /* pltfm-specific */
 #define ESDHC_HOST_CONTROL_LE  0x20
 
+/*
+ * P2020 interpretation of the SDHCI_HOST_CONTROL register
+ */
+#define ESDHC_CTRL_4BITBUS          (0x1 << 1)
+#define ESDHC_CTRL_8BITBUS          (0x2 << 1)
+#define ESDHC_CTRL_BUSWIDTH_MASK    (0x3 << 1)
+
 /* OF-specific */
 #define ESDHC_DMA_SYSCTL       0x40c
 #define ESDHC_DMA_SNOOP                0x00000040
 
 #define ESDHC_HOST_CONTROL_RES 0x05
 
-static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
+static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock,
+                                  unsigned int host_clock)
 {
        int pre_div = 2;
        int div = 1;
@@ -56,14 +64,14 @@ static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
                | ESDHC_CLOCK_MASK);
        sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
 
-       while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
+       while (host_clock / pre_div / 16 > clock && pre_div < 256)
                pre_div *= 2;
 
-       while (host->max_clk / pre_div / div > clock && div < 16)
+       while (host_clock / pre_div / div > clock && div < 16)
                div++;
 
        dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
-               clock, host->max_clk / pre_div / div);
+               clock, host_clock / pre_div / div);
 
        pre_div >>= 1;
        div--;
index 5e68adc..15039e2 100644 (file)
@@ -13,6 +13,7 @@
  * your option) any later version.
  */
 
+#include <linux/err.h>
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/delay.h>
@@ -120,6 +121,13 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
        if (reg == SDHCI_HOST_CONTROL) {
                u32 dma_bits;
 
+               /*
+                * If host control register is not standard, exit
+                * this function
+                */
+               if (host->quirks2 & SDHCI_QUIRK2_BROKEN_HOST_CONTROL)
+                       return;
+
                /* DMA select is 22,23 bits in Protocol Control Register */
                dma_bits = (val & SDHCI_CTRL_DMA_MASK) << 5;
                clrsetbits_be32(host->ioaddr + reg , SDHCI_CTRL_DMA_MASK << 5,
@@ -200,7 +208,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
        }
 
        /* Set the clock */
-       esdhc_set_clock(host, clock);
+       esdhc_set_clock(host, clock, host->max_clk);
 }
 
 #ifdef CONFIG_PM
@@ -230,6 +238,30 @@ 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)
+{
+       u32 ctrl;
+
+       switch (width) {
+       case MMC_BUS_WIDTH_8:
+               ctrl = ESDHC_CTRL_8BITBUS;
+               break;
+
+       case MMC_BUS_WIDTH_4:
+               ctrl = ESDHC_CTRL_4BITBUS;
+               break;
+
+       default:
+               ctrl = 0;
+               break;
+       }
+
+       clrsetbits_be32(host->ioaddr + SDHCI_HOST_CONTROL,
+                       ESDHC_CTRL_BUSWIDTH_MASK, ctrl);
+
+       return 0;
+}
+
 static const struct sdhci_ops sdhci_esdhc_ops = {
        .read_l = esdhc_readl,
        .read_w = esdhc_readw,
@@ -247,6 +279,7 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
        .platform_resume = esdhc_of_resume,
 #endif
        .adma_workaround = esdhci_of_adma_workaround,
+       .platform_bus_width = esdhc_pltfm_bus_width,
 };
 
 static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {
@@ -262,7 +295,33 @@ static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {
 
 static int sdhci_esdhc_probe(struct platform_device *pdev)
 {
-       return sdhci_pltfm_register(pdev, &sdhci_esdhc_pdata);
+       struct sdhci_host *host;
+       struct device_node *np;
+       int ret;
+
+       host = sdhci_pltfm_init(pdev, &sdhci_esdhc_pdata, 0);
+       if (IS_ERR(host))
+               return PTR_ERR(host);
+
+       sdhci_get_of_property(pdev);
+
+       np = pdev->dev.of_node;
+       if (of_device_is_compatible(np, "fsl,p2020-esdhc")) {
+               /*
+                * Freescale messed up with P2020 as it has a non-standard
+                * host control register
+                */
+               host->quirks2 |= SDHCI_QUIRK2_BROKEN_HOST_CONTROL;
+       }
+
+       /* call to generic mmc_of_parse to support additional capabilities */
+       mmc_of_parse(host->mmc);
+
+       ret = sdhci_add_host(host);
+       if (ret)
+               sdhci_pltfm_free(pdev);
+
+       return ret;
 }
 
 static int sdhci_esdhc_remove(struct platform_device *pdev)
index 200a6a9..57c514a 100644 (file)
@@ -68,7 +68,7 @@ static const struct sdhci_pltfm_data sdhci_hlwd_pdata = {
 
 static int sdhci_hlwd_probe(struct platform_device *pdev)
 {
-       return sdhci_pltfm_register(pdev, &sdhci_hlwd_pdata);
+       return sdhci_pltfm_register(pdev, &sdhci_hlwd_pdata, 0);
 }
 
 static int sdhci_hlwd_remove(struct platform_device *pdev)
index 701d06d..d7d6bc8 100644 (file)
@@ -36,6 +36,7 @@
 #define PCI_DEVICE_ID_INTEL_BYT_EMMC   0x0f14
 #define PCI_DEVICE_ID_INTEL_BYT_SDIO   0x0f15
 #define PCI_DEVICE_ID_INTEL_BYT_SD     0x0f16
+#define PCI_DEVICE_ID_INTEL_BYT_EMMC2  0x0f50
 
 /*
  * PCI registers
@@ -77,6 +78,8 @@ struct sdhci_pci_slot {
        int                     rst_n_gpio;
        int                     cd_gpio;
        int                     cd_irq;
+
+       void (*hw_reset)(struct sdhci_host *host);
 };
 
 struct sdhci_pci_chip {
@@ -307,10 +310,27 @@ static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {
        .probe_slot     = pch_hc_probe_slot,
 };
 
+static void sdhci_pci_int_hw_reset(struct sdhci_host *host)
+{
+       u8 reg;
+
+       reg = sdhci_readb(host, SDHCI_POWER_CONTROL);
+       reg |= 0x10;
+       sdhci_writeb(host, reg, SDHCI_POWER_CONTROL);
+       /* For eMMC, minimum is 1us but give it 9us for good measure */
+       udelay(9);
+       reg &= ~0x10;
+       sdhci_writeb(host, reg, SDHCI_POWER_CONTROL);
+       /* For eMMC, minimum is 200us but give it 300us for good measure */
+       usleep_range(300, 1000);
+}
+
 static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
 {
-       slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE;
+       slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
+                                MMC_CAP_HW_RESET;
        slot->host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ;
+       slot->hw_reset = sdhci_pci_int_hw_reset;
        return 0;
 }
 
@@ -332,6 +352,8 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
 };
 
 static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
+       .quirks2        = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON,
+       .allow_runtime_pm = true,
 };
 
 /* O2Micro extra registers */
@@ -910,6 +932,14 @@ static const struct pci_device_id pci_ids[] = {
        },
 
        {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_BYT_EMMC2,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_byt_emmc,
+       },
+
+       {
                .vendor         = PCI_VENDOR_ID_O2,
                .device         = PCI_DEVICE_ID_O2_8120,
                .subvendor      = PCI_ANY_ID,
@@ -1014,7 +1044,7 @@ static int sdhci_pci_bus_width(struct sdhci_host *host, int width)
        return 0;
 }
 
-static void sdhci_pci_hw_reset(struct sdhci_host *host)
+static void sdhci_pci_gpio_hw_reset(struct sdhci_host *host)
 {
        struct sdhci_pci_slot *slot = sdhci_priv(host);
        int rst_n_gpio = slot->rst_n_gpio;
@@ -1029,6 +1059,14 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host)
        usleep_range(300, 1000);
 }
 
+static void sdhci_pci_hw_reset(struct sdhci_host *host)
+{
+       struct sdhci_pci_slot *slot = sdhci_priv(host);
+
+       if (slot->hw_reset)
+               slot->hw_reset(host);
+}
+
 static const struct sdhci_ops sdhci_pci_ops = {
        .enable_dma     = sdhci_pci_enable_dma,
        .platform_bus_width     = sdhci_pci_bus_width,
@@ -1326,6 +1364,7 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
                if (!gpio_request(slot->rst_n_gpio, "eMMC_reset")) {
                        gpio_direction_output(slot->rst_n_gpio, 1);
                        slot->host->mmc->caps |= MMC_CAP_HW_RESET;
+                       slot->hw_reset = sdhci_pci_gpio_hw_reset;
                } else {
                        dev_warn(&pdev->dev, "failed to request rst_n_gpio\n");
                        slot->rst_n_gpio = -EINVAL;
index cd0f1f6..e2065a4 100644 (file)
@@ -115,10 +115,10 @@ void sdhci_get_of_property(struct platform_device *pdev) {}
 EXPORT_SYMBOL_GPL(sdhci_get_of_property);
 
 struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
-                                   const struct sdhci_pltfm_data *pdata)
+                                   const struct sdhci_pltfm_data *pdata,
+                                   size_t priv_size)
 {
        struct sdhci_host *host;
-       struct sdhci_pltfm_host *pltfm_host;
        struct device_node *np = pdev->dev.of_node;
        struct resource *iomem;
        int ret;
@@ -134,24 +134,27 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
 
        /* Some PCI-based MFD need the parent here */
        if (pdev->dev.parent != &platform_bus && !np)
-               host = sdhci_alloc_host(pdev->dev.parent, sizeof(*pltfm_host));
+               host = sdhci_alloc_host(pdev->dev.parent,
+                       sizeof(struct sdhci_pltfm_host) + priv_size);
        else
-               host = sdhci_alloc_host(&pdev->dev, sizeof(*pltfm_host));
+               host = sdhci_alloc_host(&pdev->dev,
+                       sizeof(struct sdhci_pltfm_host) + priv_size);
 
        if (IS_ERR(host)) {
                ret = PTR_ERR(host);
                goto err;
        }
 
-       pltfm_host = sdhci_priv(host);
-
        host->hw_name = dev_name(&pdev->dev);
        if (pdata && pdata->ops)
                host->ops = pdata->ops;
        else
                host->ops = &sdhci_pltfm_ops;
-       if (pdata)
+       if (pdata) {
                host->quirks = pdata->quirks;
+               host->quirks2 = pdata->quirks2;
+       }
+
        host->irq = platform_get_irq(pdev, 0);
 
        if (!request_mem_region(iomem->start, resource_size(iomem),
@@ -197,17 +200,17 @@ void sdhci_pltfm_free(struct platform_device *pdev)
        iounmap(host->ioaddr);
        release_mem_region(iomem->start, resource_size(iomem));
        sdhci_free_host(host);
-       platform_set_drvdata(pdev, NULL);
 }
 EXPORT_SYMBOL_GPL(sdhci_pltfm_free);
 
 int sdhci_pltfm_register(struct platform_device *pdev,
-                        const struct sdhci_pltfm_data *pdata)
+                       const struct sdhci_pltfm_data *pdata,
+                       size_t priv_size)
 {
        struct sdhci_host *host;
        int ret = 0;
 
-       host = sdhci_pltfm_init(pdev, pdata);
+       host = sdhci_pltfm_init(pdev, pdata, priv_size);
        if (IS_ERR(host))
                return PTR_ERR(host);
 
index 1210ed1..e15ced7 100644 (file)
@@ -18,6 +18,7 @@
 struct sdhci_pltfm_data {
        const struct sdhci_ops *ops;
        unsigned int quirks;
+       unsigned int quirks2;
 };
 
 struct sdhci_pltfm_host {
@@ -27,6 +28,8 @@ struct sdhci_pltfm_host {
        /* migrate from sdhci_of_host */
        unsigned int clock;
        u16 xfer_mode_shadow;
+
+       unsigned long private[0] ____cacheline_aligned;
 };
 
 #ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
@@ -91,15 +94,22 @@ static inline void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
 extern void sdhci_get_of_property(struct platform_device *pdev);
 
 extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
-                                         const struct sdhci_pltfm_data *pdata);
+                                         const struct sdhci_pltfm_data *pdata,
+                                         size_t priv_size);
 extern void sdhci_pltfm_free(struct platform_device *pdev);
 
 extern int sdhci_pltfm_register(struct platform_device *pdev,
-                               const struct sdhci_pltfm_data *pdata);
+                               const struct sdhci_pltfm_data *pdata,
+                               size_t priv_size);
 extern int sdhci_pltfm_unregister(struct platform_device *pdev);
 
 extern unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host);
 
+static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host)
+{
+       return (void *)host->private;
+}
+
 #ifdef CONFIG_PM
 extern const struct dev_pm_ops sdhci_pltfm_pmops;
 #define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops)
index 6a3f702..d51e061 100644 (file)
@@ -175,7 +175,7 @@ static int sdhci_pxav2_probe(struct platform_device *pdev)
        if (!pxa)
                return -ENOMEM;
 
-       host = sdhci_pltfm_init(pdev, NULL);
+       host = sdhci_pltfm_init(pdev, NULL, 0);
        if (IS_ERR(host)) {
                kfree(pxa);
                return PTR_ERR(host);
@@ -253,8 +253,6 @@ static int sdhci_pxav2_remove(struct platform_device *pdev)
        sdhci_pltfm_free(pdev);
        kfree(pxa);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index 1ae358e..bf99359 100644 (file)
@@ -230,7 +230,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
        if (!pxa)
                return -ENOMEM;
 
-       host = sdhci_pltfm_init(pdev, &sdhci_pxav3_pdata);
+       host = sdhci_pltfm_init(pdev, &sdhci_pxav3_pdata, 0);
        if (IS_ERR(host)) {
                kfree(pxa);
                return PTR_ERR(host);
@@ -252,7 +252,9 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
 
        match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev);
        if (match) {
-               mmc_of_parse(host->mmc);
+               ret = mmc_of_parse(host->mmc);
+               if (ret)
+                       goto err_of_parse;
                sdhci_get_of_property(pdev);
                pdata = pxav3_get_mmc_pdata(dev);
        } else if (pdata) {
@@ -285,18 +287,15 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
                }
        }
 
-       pm_runtime_set_active(&pdev->dev);
        pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
        pm_runtime_set_autosuspend_delay(&pdev->dev, PXAV3_RPM_DELAY_MS);
        pm_runtime_use_autosuspend(&pdev->dev);
        pm_suspend_ignore_children(&pdev->dev, 1);
-       pm_runtime_get_noresume(&pdev->dev);
 
        ret = sdhci_add_host(host);
        if (ret) {
                dev_err(&pdev->dev, "failed to add host\n");
-               pm_runtime_forbid(&pdev->dev);
-               pm_runtime_disable(&pdev->dev);
                goto err_add_host;
        }
 
@@ -313,10 +312,13 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
 
        return 0;
 
+err_of_parse:
+err_cd_req:
 err_add_host:
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
        clk_disable_unprepare(clk);
        clk_put(clk);
-err_cd_req:
 err_clk_get:
        sdhci_pltfm_free(pdev);
        kfree(pxa);
@@ -339,8 +341,6 @@ static int sdhci_pxav3_remove(struct platform_device *pdev)
        sdhci_pltfm_free(pdev);
        kfree(pxa);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index c6f6246..926aaf6 100644 (file)
@@ -745,7 +745,6 @@ static int sdhci_s3c_remove(struct platform_device *pdev)
        clk_disable_unprepare(sc->clk_io);
 
        sdhci_free_host(host);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index 09805af..62a4a83 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/mmc/slot-gpio.h>
-#include <linux/pinctrl/consumer.h>
 #include "sdhci-pltfm.h"
 
 struct sdhci_sirf_priv {
@@ -24,7 +23,7 @@ struct sdhci_sirf_priv {
 static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct sdhci_sirf_priv *priv = pltfm_host->priv;
+       struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
        return clk_get_rate(priv->clk);
 }
 
@@ -46,47 +45,35 @@ static int sdhci_sirf_probe(struct platform_device *pdev)
        struct sdhci_host *host;
        struct sdhci_pltfm_host *pltfm_host;
        struct sdhci_sirf_priv *priv;
-       struct pinctrl *pinctrl;
+       struct clk *clk;
+       int gpio_cd;
        int ret;
 
-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl)) {
-               dev_err(&pdev->dev, "unable to get pinmux");
-               return PTR_ERR(pinctrl);
-       }
-
-       priv = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_sirf_priv),
-               GFP_KERNEL);
-       if (!priv) {
-               dev_err(&pdev->dev, "unable to allocate private data");
-               return -ENOMEM;
-       }
-
-       priv->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(priv->clk)) {
+       clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(clk)) {
                dev_err(&pdev->dev, "unable to get clock");
-               return PTR_ERR(priv->clk);
+               return PTR_ERR(clk);
        }
 
-       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 (pdev->dev.of_node)
+               gpio_cd = of_get_named_gpio(pdev->dev.of_node, "cd-gpios", 0);
+       else
+               gpio_cd = -EINVAL;
 
-       host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata);
-       if (IS_ERR(host)) {
-               ret = PTR_ERR(host);
-               goto err_sdhci_pltfm_init;
-       }
+       host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata, sizeof(struct sdhci_sirf_priv));
+       if (IS_ERR(host))
+               return PTR_ERR(host);
 
        pltfm_host = sdhci_priv(host);
-       pltfm_host->priv = priv;
+       priv = sdhci_pltfm_priv(pltfm_host);
+       priv->clk = clk;
+       priv->gpio_cd = gpio_cd;
 
        sdhci_get_of_property(pdev);
 
-       clk_prepare_enable(priv->clk);
+       ret = clk_prepare_enable(priv->clk);
+       if (ret)
+               goto err_clk_prepare;
 
        ret = sdhci_add_host(host);
        if (ret)
@@ -111,8 +98,8 @@ err_request_cd:
        sdhci_remove_host(host, 0);
 err_sdhci_add:
        clk_disable_unprepare(priv->clk);
+err_clk_prepare:
        sdhci_pltfm_free(pdev);
-err_sdhci_pltfm_init:
        return ret;
 }
 
@@ -120,7 +107,7 @@ static int sdhci_sirf_remove(struct platform_device *pdev)
 {
        struct sdhci_host *host = platform_get_drvdata(pdev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct sdhci_sirf_priv *priv = pltfm_host->priv;
+       struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
 
        sdhci_pltfm_unregister(pdev);
 
@@ -136,7 +123,7 @@ static int sdhci_sirf_suspend(struct device *dev)
 {
        struct sdhci_host *host = dev_get_drvdata(dev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct sdhci_sirf_priv *priv = pltfm_host->priv;
+       struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
        int ret;
 
        ret = sdhci_suspend_host(host);
@@ -152,7 +139,7 @@ static int sdhci_sirf_resume(struct device *dev)
 {
        struct sdhci_host *host = dev_get_drvdata(dev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct sdhci_sirf_priv *priv = pltfm_host->priv;
+       struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
        int ret;
 
        ret = clk_enable(priv->clk);
index 7ae5b3a..2dba9f8 100644 (file)
@@ -258,7 +258,6 @@ static int sdhci_probe(struct platform_device *pdev)
        return 0;
 
 set_drvdata:
-       platform_set_drvdata(pdev, NULL);
        sdhci_remove_host(host, 1);
 free_host:
        sdhci_free_host(host);
@@ -278,7 +277,6 @@ static int sdhci_remove(struct platform_device *pdev)
        int dead = 0;
        u32 scratch;
 
-       platform_set_drvdata(pdev, NULL);
        scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
        if (scratch == (u32)-1)
                dead = 1;
index e0dba74..5b7b2eb 100644 (file)
@@ -205,7 +205,7 @@ static const struct of_device_id sdhci_tegra_dt_match[] = {
 };
 MODULE_DEVICE_TABLE(of, sdhci_tegra_dt_match);
 
-static void sdhci_tegra_parse_dt(struct device *dev)
+static int sdhci_tegra_parse_dt(struct device *dev)
 {
        struct device_node *np = dev->of_node;
        struct sdhci_host *host = dev_get_drvdata(dev);
@@ -213,7 +213,7 @@ static void sdhci_tegra_parse_dt(struct device *dev)
        struct sdhci_tegra *tegra_host = pltfm_host->priv;
 
        tegra_host->power_gpio = of_get_named_gpio(np, "power-gpios", 0);
-       mmc_of_parse(host->mmc);
+       return mmc_of_parse(host->mmc);
 }
 
 static int sdhci_tegra_probe(struct platform_device *pdev)
@@ -231,7 +231,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
                return -EINVAL;
        soc_data = match->data;
 
-       host = sdhci_pltfm_init(pdev, soc_data->pdata);
+       host = sdhci_pltfm_init(pdev, soc_data->pdata, 0);
        if (IS_ERR(host))
                return PTR_ERR(host);
        pltfm_host = sdhci_priv(host);
@@ -245,7 +245,9 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
        tegra_host->soc_data = soc_data;
        pltfm_host->priv = tegra_host;
 
-       sdhci_tegra_parse_dt(&pdev->dev);
+       rc = sdhci_tegra_parse_dt(&pdev->dev);
+       if (rc)
+               goto err_parse_dt;
 
        if (gpio_is_valid(tegra_host->power_gpio)) {
                rc = gpio_request(tegra_host->power_gpio, "sdhci_power");
@@ -279,6 +281,7 @@ err_clk_get:
        if (gpio_is_valid(tegra_host->power_gpio))
                gpio_free(tegra_host->power_gpio);
 err_power_req:
+err_parse_dt:
 err_alloc_tegra_host:
        sdhci_pltfm_free(pdev);
        return rc;
index 2ea429c..a78bd4f 100644 (file)
@@ -58,6 +58,8 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
 #ifdef CONFIG_PM_RUNTIME
 static int sdhci_runtime_pm_get(struct sdhci_host *host);
 static int sdhci_runtime_pm_put(struct sdhci_host *host);
+static void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
+static void sdhci_runtime_pm_bus_off(struct sdhci_host *host);
 #else
 static inline int sdhci_runtime_pm_get(struct sdhci_host *host)
 {
@@ -67,6 +69,12 @@ static inline int sdhci_runtime_pm_put(struct sdhci_host *host)
 {
        return 0;
 }
+static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
+{
+}
+static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
+{
+}
 #endif
 
 static void sdhci_dumpregs(struct sdhci_host *host)
@@ -192,8 +200,12 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
 
        sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
 
-       if (mask & SDHCI_RESET_ALL)
+       if (mask & SDHCI_RESET_ALL) {
                host->clock = 0;
+               /* Reset-all turns off SD Bus Power */
+               if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
+                       sdhci_runtime_pm_bus_off(host);
+       }
 
        /* Wait max 100 ms */
        timeout = 100;
@@ -1268,6 +1280,8 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
 
        if (pwr == 0) {
                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;
        }
 
@@ -1289,6 +1303,9 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
 
        sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
 
+       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
@@ -1526,16 +1543,15 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                        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)
-                               ctrl_2 |= SDHCI_CTRL_HS_SDR200;
+                       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_SDR104)
-                               ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
                        else if (ios->timing == MMC_TIMING_UHS_DDR50)
                                ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
                        sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
@@ -1846,7 +1862,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
         */
        if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) &&
            (host->flags & SDHCI_SDR50_NEEDS_TUNING ||
-            host->flags & SDHCI_HS200_NEEDS_TUNING))
+            host->flags & SDHCI_SDR104_NEEDS_TUNING))
                requires_tuning_nonuhs = true;
 
        if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) ||
@@ -2046,11 +2062,14 @@ static void sdhci_card_event(struct mmc_host *mmc)
        struct sdhci_host *host = mmc_priv(mmc);
        unsigned long flags;
 
+       /* First check if client has provided their own card event */
+       if (host->ops->card_event)
+               host->ops->card_event(host);
+
        spin_lock_irqsave(&host->lock, flags);
 
        /* Check host->mrq first in case we are runtime suspended */
-       if (host->mrq &&
-           !(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
+       if (host->mrq && !sdhci_do_get_cd(host)) {
                pr_err("%s: Card removed during transfer!\n",
                        mmc_hostname(host->mmc));
                pr_err("%s: Resetting controller.\n",
@@ -2625,6 +2644,22 @@ static int sdhci_runtime_pm_put(struct sdhci_host *host)
        return pm_runtime_put_autosuspend(host->mmc->parent);
 }
 
+static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
+{
+       if (host->runtime_suspended || host->bus_on)
+               return;
+       host->bus_on = true;
+       pm_runtime_get_noresume(host->mmc->parent);
+}
+
+static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
+{
+       if (host->runtime_suspended || !host->bus_on)
+               return;
+       host->bus_on = false;
+       pm_runtime_put_noidle(host->mmc->parent);
+}
+
 int sdhci_runtime_suspend_host(struct sdhci_host *host)
 {
        unsigned long flags;
@@ -2962,9 +2997,13 @@ int sdhci_add_host(struct sdhci_host *host)
                mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
 
        /* SDR104 supports also implies SDR50 support */
-       if (caps[1] & SDHCI_SUPPORT_SDR104)
+       if (caps[1] & SDHCI_SUPPORT_SDR104) {
                mmc->caps |= MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50;
-       else if (caps[1] & SDHCI_SUPPORT_SDR50)
+               /* SD3.0: SDR104 is supported so (for eMMC) the caps2
+                * field can be promoted to support HS200.
+                */
+               mmc->caps2 |= MMC_CAP2_HS200;
+       } else if (caps[1] & SDHCI_SUPPORT_SDR50)
                mmc->caps |= MMC_CAP_UHS_SDR50;
 
        if (caps[1] & SDHCI_SUPPORT_DDR50)
@@ -2974,9 +3013,9 @@ int sdhci_add_host(struct sdhci_host *host)
        if (caps[1] & SDHCI_USE_SDR50_TUNING)
                host->flags |= SDHCI_SDR50_NEEDS_TUNING;
 
-       /* Does the host need tuning for HS200? */
+       /* Does the host need tuning for SDR104 / HS200? */
        if (mmc->caps2 & MMC_CAP2_HS200)
-               host->flags |= SDHCI_HS200_NEEDS_TUNING;
+               host->flags |= SDHCI_SDR104_NEEDS_TUNING;
 
        /* Driver Type(s) (A, C, D) supported by the host */
        if (caps[1] & SDHCI_DRIVER_TYPE_A)
index 379e09d..b037f18 100644 (file)
@@ -294,6 +294,7 @@ struct sdhci_ops {
        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);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
index ba76a53..6706b5e 100644 (file)
@@ -1244,7 +1244,8 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
        u32 state;
 
        state = sh_mmcif_readl(host->addr, MMCIF_CE_INT);
-       sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
+       sh_mmcif_writel(host->addr, MMCIF_CE_INT,
+                       ~(state & sh_mmcif_readl(host->addr, MMCIF_CE_INT_MASK)));
        sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state & MASK_CLEAN);
 
        if (state & ~MASK_CLEAN)
@@ -1369,7 +1370,11 @@ static int sh_mmcif_probe(struct platform_device *pdev)
                ret = -ENOMEM;
                goto ealloch;
        }
-       mmc_of_parse(mmc);
+
+       ret = mmc_of_parse(mmc);
+       if (ret < 0)
+               goto eofparse;
+
        host            = mmc_priv(mmc);
        host->mmc       = mmc;
        host->addr      = reg;
@@ -1464,6 +1469,7 @@ eclkupdate:
        clk_put(host->hclk);
 eclkget:
        pm_runtime_disable(&pdev->dev);
+eofparse:
        mmc_free_host(mmc);
 ealloch:
        iounmap(reg);
@@ -1501,8 +1507,6 @@ static int sh_mmcif_remove(struct platform_device *pdev)
        if (irq[1] >= 0)
                free_irq(irq[1], host);
 
-       platform_set_drvdata(pdev, NULL);
-
        clk_disable(host->hclk);
        mmc_free_host(host->mmc);
        pm_runtime_put_sync(&pdev->dev);
index fe90853..ebea749 100644 (file)
@@ -46,14 +46,12 @@ static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = {
 struct sh_mobile_sdhi {
        struct clk *clk;
        struct tmio_mmc_data mmc_data;
-       struct sh_dmae_slave param_tx;
-       struct sh_dmae_slave param_rx;
        struct tmio_mmc_dma dma_priv;
 };
 
 static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int *f)
 {
-       struct mmc_host *mmc = dev_get_drvdata(&pdev->dev);
+       struct mmc_host *mmc = platform_get_drvdata(pdev);
        struct tmio_mmc_host *host = mmc_priv(mmc);
        struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
        int ret = clk_enable(priv->clk);
@@ -66,7 +64,7 @@ static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int
 
 static void sh_mobile_sdhi_clk_disable(struct platform_device *pdev)
 {
-       struct mmc_host *mmc = dev_get_drvdata(&pdev->dev);
+       struct mmc_host *mmc = platform_get_drvdata(pdev);
        struct tmio_mmc_host *host = mmc_priv(mmc);
        struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
        clk_disable(priv->clk);
@@ -121,7 +119,7 @@ static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
 
 static void sh_mobile_sdhi_cd_wakeup(const struct platform_device *pdev)
 {
-       mmc_detect_change(dev_get_drvdata(&pdev->dev), msecs_to_jiffies(100));
+       mmc_detect_change(platform_get_drvdata(pdev), msecs_to_jiffies(100));
 }
 
 static const struct sh_mobile_sdhi_ops sdhi_ops = {
@@ -146,6 +144,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
        struct tmio_mmc_host *host;
        int irq, ret, i = 0;
        bool multiplexed_isr = true;
+       struct tmio_mmc_dma *dma_priv;
 
        priv = devm_kzalloc(&pdev->dev, sizeof(struct sh_mobile_sdhi), GFP_KERNEL);
        if (priv == NULL) {
@@ -154,6 +153,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
        }
 
        mmc_data = &priv->mmc_data;
+       dma_priv = &priv->dma_priv;
 
        if (p) {
                if (p->init) {
@@ -186,15 +186,23 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
                        mmc_data->get_cd = sh_mobile_sdhi_get_cd;
 
                if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) {
-                       priv->param_tx.shdma_slave.slave_id = p->dma_slave_tx;
-                       priv->param_rx.shdma_slave.slave_id = p->dma_slave_rx;
-                       priv->dma_priv.chan_priv_tx = &priv->param_tx.shdma_slave;
-                       priv->dma_priv.chan_priv_rx = &priv->param_rx.shdma_slave;
-                       priv->dma_priv.alignment_shift = 1; /* 2-byte alignment */
-                       mmc_data->dma = &priv->dma_priv;
+                       /*
+                        * Yes, we have to provide slave IDs twice to TMIO:
+                        * once as a filter parameter and once for channel
+                        * configuration as an explicit slave ID
+                        */
+                       dma_priv->chan_priv_tx = (void *)p->dma_slave_tx;
+                       dma_priv->chan_priv_rx = (void *)p->dma_slave_rx;
+                       dma_priv->slave_id_tx = p->dma_slave_tx;
+                       dma_priv->slave_id_rx = p->dma_slave_rx;
                }
        }
 
+       dma_priv->alignment_shift = 1; /* 2-byte alignment */
+       dma_priv->filter = shdma_chan_filter;
+
+       mmc_data->dma = dma_priv;
+
        /*
         * All SDHI blocks support 2-byte and larger block sizes in 4-bit
         * bus width mode.
@@ -265,8 +273,10 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
                }
 
                /* There must be at least one IRQ source */
-               if (!i)
+               if (!i) {
+                       ret = irq;
                        goto eirq;
+               }
        }
 
        dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n",
index 139212e..8860d4d 100644 (file)
@@ -112,8 +112,6 @@ static int tmio_mmc_remove(struct platform_device *pdev)
        const struct mfd_cell *cell = mfd_get_cell(pdev);
        struct mmc_host *mmc = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        if (mmc) {
                struct tmio_mmc_host *host = mmc_priv(mmc);
                free_irq(platform_get_irq(pdev, 0), host);
index d857f5c..86fd21e 100644 (file)
 
 struct tmio_mmc_data;
 
+/*
+ * We differentiate between the following 3 power states:
+ * 1. card slot powered off, controller stopped. This is used, when either there
+ *    is no card in the slot, or the card really has to be powered down.
+ * 2. card slot powered on, controller stopped. This is used, when a card is in
+ *    the slot, but no activity is currently taking place. This is a power-
+ *    saving mode with card-state preserved. This state can be entered, e.g.
+ *    when MMC clock-gating is used.
+ * 3. card slot powered on, controller running. This is the actual active state.
+ */
+enum tmio_mmc_power {
+       TMIO_MMC_OFF_STOP,      /* card power off, controller stopped */
+       TMIO_MMC_ON_STOP,       /* card power on, controller stopped */
+       TMIO_MMC_ON_RUN,        /* card power on, controller running */
+};
+
 struct tmio_mmc_host {
        void __iomem *ctl;
        unsigned long bus_shift;
@@ -48,8 +64,8 @@ struct tmio_mmc_host {
        struct mmc_data         *data;
        struct mmc_host         *mmc;
 
-       /* Controller power state */
-       bool                    power;
+       /* Controller and card power state */
+       enum tmio_mmc_power     power;
 
        /* Callbacks for clock / power control */
        void (*set_pwr)(struct platform_device *host, int state);
@@ -85,6 +101,7 @@ struct tmio_mmc_host {
        unsigned long           last_req_ts;
        struct mutex            ios_lock;       /* protect set_ios() context */
        bool                    native_hotplug;
+       bool                    resuming;
 };
 
 int tmio_mmc_host_probe(struct tmio_mmc_host **host,
index fff9286..47bdb8f 100644 (file)
@@ -261,42 +261,62 @@ out:
        spin_unlock_irq(&host->lock);
 }
 
-/* It might be necessary to make filter MFD specific */
-static bool tmio_mmc_filter(struct dma_chan *chan, void *arg)
-{
-       dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg);
-       chan->private = arg;
-       return true;
-}
-
 void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata)
 {
        /* We can only either use DMA for both Tx and Rx or not use it at all */
-       if (!pdata->dma)
+       if (!pdata->dma || (!host->pdev->dev.of_node &&
+               (!pdata->dma->chan_priv_tx || !pdata->dma->chan_priv_rx)))
                return;
 
        if (!host->chan_tx && !host->chan_rx) {
+               struct resource *res = platform_get_resource(host->pdev,
+                                                            IORESOURCE_MEM, 0);
+               struct dma_slave_config cfg = {};
                dma_cap_mask_t mask;
+               int ret;
+
+               if (!res)
+                       return;
 
                dma_cap_zero(mask);
                dma_cap_set(DMA_SLAVE, mask);
 
-               host->chan_tx = dma_request_channel(mask, tmio_mmc_filter,
-                                                   pdata->dma->chan_priv_tx);
+               host->chan_tx = dma_request_slave_channel_compat(mask,
+                                       pdata->dma->filter, pdata->dma->chan_priv_tx,
+                                       &host->pdev->dev, "tx");
                dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__,
                        host->chan_tx);
 
                if (!host->chan_tx)
                        return;
 
-               host->chan_rx = dma_request_channel(mask, tmio_mmc_filter,
-                                                   pdata->dma->chan_priv_rx);
+               if (pdata->dma->chan_priv_tx)
+                       cfg.slave_id = pdata->dma->slave_id_tx;
+               cfg.direction = DMA_MEM_TO_DEV;
+               cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->bus_shift);
+               cfg.src_addr = 0;
+               ret = dmaengine_slave_config(host->chan_tx, &cfg);
+               if (ret < 0)
+                       goto ecfgtx;
+
+               host->chan_rx = dma_request_slave_channel_compat(mask,
+                                       pdata->dma->filter, pdata->dma->chan_priv_rx,
+                                       &host->pdev->dev, "rx");
                dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__,
                        host->chan_rx);
 
                if (!host->chan_rx)
                        goto ereqrx;
 
+               if (pdata->dma->chan_priv_rx)
+                       cfg.slave_id = pdata->dma->slave_id_rx;
+               cfg.direction = DMA_DEV_TO_MEM;
+               cfg.src_addr = cfg.dst_addr;
+               cfg.dst_addr = 0;
+               ret = dmaengine_slave_config(host->chan_rx, &cfg);
+               if (ret < 0)
+                       goto ecfgrx;
+
                host->bounce_buf = (u8 *)__get_free_page(GFP_KERNEL | GFP_DMA);
                if (!host->bounce_buf)
                        goto ebouncebuf;
@@ -310,9 +330,11 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat
        return;
 
 ebouncebuf:
+ecfgrx:
        dma_release_channel(host->chan_rx);
        host->chan_rx = NULL;
 ereqrx:
+ecfgtx:
        dma_release_channel(host->chan_tx);
        host->chan_tx = NULL;
 }
index f508ecb..b72edb7 100644 (file)
@@ -859,32 +859,45 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
         * is kept positive, so no suspending actually takes place.
         */
        if (ios->power_mode == MMC_POWER_ON && ios->clock) {
-               if (!host->power) {
+               if (host->power != TMIO_MMC_ON_RUN) {
                        tmio_mmc_clk_update(mmc);
                        pm_runtime_get_sync(dev);
+                       if (host->resuming) {
+                               tmio_mmc_reset(host);
+                               host->resuming = false;
+                       }
                }
+               if (host->power == TMIO_MMC_OFF_STOP)
+                       tmio_mmc_reset(host);
                tmio_mmc_set_clock(host, ios->clock);
-               if (!host->power) {
+               if (host->power == TMIO_MMC_OFF_STOP)
                        /* power up SD card and the bus */
                        tmio_mmc_power_on(host, ios->vdd);
-                       host->power = true;
-               }
+               host->power = TMIO_MMC_ON_RUN;
                /* start bus clock */
                tmio_mmc_clk_start(host);
        } else if (ios->power_mode != MMC_POWER_UP) {
-               if (host->power) {
-                       struct tmio_mmc_data *pdata = host->pdata;
-                       if (ios->power_mode == MMC_POWER_OFF)
+               struct tmio_mmc_data *pdata = host->pdata;
+               unsigned int old_power = host->power;
+
+               if (old_power != TMIO_MMC_OFF_STOP) {
+                       if (ios->power_mode == MMC_POWER_OFF) {
                                tmio_mmc_power_off(host);
+                               host->power = TMIO_MMC_OFF_STOP;
+                       } else {
+                               host->power = TMIO_MMC_ON_STOP;
+                       }
+               }
+
+               if (old_power == TMIO_MMC_ON_RUN) {
                        tmio_mmc_clk_stop(host);
-                       host->power = false;
                        pm_runtime_put(dev);
                        if (pdata->clk_disable)
                                pdata->clk_disable(host->pdev);
                }
        }
 
-       if (host->power) {
+       if (host->power != TMIO_MMC_OFF_STOP) {
                switch (ios->bus_width) {
                case MMC_BUS_WIDTH_1:
                        sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0);
@@ -988,7 +1001,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host,
        if (!mmc)
                return -ENOMEM;
 
-       mmc_of_parse(mmc);
+       ret = mmc_of_parse(mmc);
+       if (ret < 0)
+               goto host_free;
 
        pdata->dev = &pdev->dev;
        _host = mmc_priv(mmc);
@@ -1025,7 +1040,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host,
                                  mmc->caps & MMC_CAP_NONREMOVABLE ||
                                  mmc->slot.cd_irq >= 0);
 
-       _host->power = false;
+       _host->power = TMIO_MMC_OFF_STOP;
        pm_runtime_enable(&pdev->dev);
        ret = pm_runtime_resume(&pdev->dev);
        if (ret < 0)
@@ -1154,10 +1169,10 @@ int tmio_mmc_host_resume(struct device *dev)
        struct mmc_host *mmc = dev_get_drvdata(dev);
        struct tmio_mmc_host *host = mmc_priv(mmc);
 
-       tmio_mmc_reset(host);
        tmio_mmc_enable_dma(host, true);
 
        /* The MMC core will perform the complete set up */
+       host->resuming = true;
        return mmc_resume_host(mmc);
 }
 EXPORT_SYMBOL(tmio_mmc_host_resume);
@@ -1175,7 +1190,6 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
        struct mmc_host *mmc = dev_get_drvdata(dev);
        struct tmio_mmc_host *host = mmc_priv(mmc);
 
-       tmio_mmc_reset(host);
        tmio_mmc_enable_dma(host, true);
 
        return 0;
index 442f576..34231d5 100644 (file)
@@ -927,8 +927,6 @@ static int wmt_mci_remove(struct platform_device *pdev)
 
        mmc_free_host(mmc);
 
-       platform_set_drvdata(pdev, NULL);
-
        dev_info(&pdev->dev, "WMT MCI device removed\n");
 
        return 0;
index 99bf3e6..ce35113 100644 (file)
@@ -81,10 +81,15 @@ int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base);
 void tmio_core_mmc_pwr(void __iomem *cnf, int shift, int state);
 void tmio_core_mmc_clk_div(void __iomem *cnf, int shift, int state);
 
+struct dma_chan;
+
 struct tmio_mmc_dma {
        void *chan_priv_tx;
        void *chan_priv_rx;
+       int slave_id_tx;
+       int slave_id_rx;
        int alignment_shift;
+       bool (*filter)(struct dma_chan *chan, void *arg);
 };
 
 struct tmio_mmc_host;
index f31725b..842de3e 100644 (file)
@@ -94,7 +94,11 @@ struct mmc_ext_csd {
        u8                      raw_ext_csd_structure;  /* 194 */
        u8                      raw_card_type;          /* 196 */
        u8                      out_of_int_time;        /* 198 */
-       u8                      raw_s_a_timeout;                /* 217 */
+       u8                      raw_pwr_cl_52_195;      /* 200 */
+       u8                      raw_pwr_cl_26_195;      /* 201 */
+       u8                      raw_pwr_cl_52_360;      /* 202 */
+       u8                      raw_pwr_cl_26_360;      /* 203 */
+       u8                      raw_s_a_timeout;        /* 217 */
        u8                      raw_hc_erase_gap_size;  /* 221 */
        u8                      raw_erase_timeout_mult; /* 223 */
        u8                      raw_hc_erase_grp_size;  /* 224 */
@@ -102,6 +106,10 @@ struct mmc_ext_csd {
        u8                      raw_sec_erase_mult;     /* 230 */
        u8                      raw_sec_feature_support;/* 231 */
        u8                      raw_trim_mult;          /* 232 */
+       u8                      raw_pwr_cl_200_195;     /* 236 */
+       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_bkops_status;       /* 246 */
        u8                      raw_sectors[4];         /* 212 - 4 bytes */
 
@@ -512,6 +520,7 @@ struct mmc_driver {
        void (*remove)(struct mmc_card *);
        int (*suspend)(struct mmc_card *);
        int (*resume)(struct mmc_card *);
+       void (*shutdown)(struct mmc_card *);
 };
 
 extern int mmc_register_driver(struct mmc_driver *);
index 39613b9..443243b 100644 (file)
@@ -96,6 +96,8 @@ struct mmc_command {
  */
 
        unsigned int            cmd_timeout_ms; /* in milliseconds */
+       /* Set this flag only for blocking sanitize request */
+       bool                    sanitize_busy;
 
        struct mmc_data         *data;          /* data segment associated with cmd */
        struct mmc_request      *mrq;           /* associated request */
@@ -188,6 +190,9 @@ extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort);
 extern void mmc_release_host(struct mmc_host *host);
 extern int mmc_try_claim_host(struct mmc_host *host);
 
+extern void mmc_get_card(struct mmc_card *card);
+extern void mmc_put_card(struct mmc_card *card);
+
 extern int mmc_flush_cache(struct mmc_card *);
 
 extern int mmc_detect_card_removed(struct mmc_host *host);
index e326ae2..3b0c33a 100644 (file)
@@ -239,7 +239,7 @@ struct mmc_host {
 #define MMC_CAP_SPI            (1 << 4)        /* Talks only SPI protocols */
 #define MMC_CAP_NEEDS_POLL     (1 << 5)        /* Needs polling for card-detection */
 #define MMC_CAP_8_BIT_DATA     (1 << 6)        /* Can the host do 8 bit transfers */
-
+#define MMC_CAP_AGGRESSIVE_PM  (1 << 7)        /* Suspend (e)MMC/SD at idle  */
 #define MMC_CAP_NONREMOVABLE   (1 << 8)        /* Nonremovable e.g. eMMC */
 #define MMC_CAP_WAIT_WHILE_BUSY        (1 << 9)        /* Waits while card is busy */
 #define MMC_CAP_ERASE          (1 << 10)       /* Allow erase/trim commands */
@@ -264,7 +264,7 @@ struct mmc_host {
 
 #define MMC_CAP2_BOOTPART_NOACC        (1 << 0)        /* Boot partition no access */
 #define MMC_CAP2_CACHE_CTRL    (1 << 1)        /* Allow cache control */
-#define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)      /* Notify poweroff supported */
+#define MMC_CAP2_FULL_PWR_CYCLE        (1 << 2)        /* Can do full power cycle */
 #define MMC_CAP2_NO_MULTI_READ (1 << 3)        /* Multiblock reads don't work */
 #define MMC_CAP2_NO_SLEEP_CMD  (1 << 4)        /* Don't allow sleep command */
 #define MMC_CAP2_HS200_1_8V_SDR        (1 << 5)        /* can support */
@@ -272,7 +272,6 @@ struct mmc_host {
 #define MMC_CAP2_HS200         (MMC_CAP2_HS200_1_8V_SDR | \
                                 MMC_CAP2_HS200_1_2V_SDR)
 #define MMC_CAP2_BROKEN_VOLTAGE        (1 << 7)        /* Use the broken voltage */
-#define MMC_CAP2_DETECT_ON_ERR (1 << 8)        /* On I/O err check card removal */
 #define MMC_CAP2_HC_ERASE_SZ   (1 << 9)        /* High-capacity erase size */
 #define MMC_CAP2_CD_ACTIVE_HIGH        (1 << 10)       /* Card-detect signal active high */
 #define MMC_CAP2_RO_ACTIVE_HIGH        (1 << 11)       /* Write-protect signal active high */
@@ -281,6 +280,7 @@ 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_SANITIZE      (1 << 15)               /* Support Sanitize */
 
        mmc_pm_flag_t           pm_caps;        /* supported pm features */
 
@@ -369,7 +369,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *);
 int mmc_add_host(struct mmc_host *);
 void mmc_remove_host(struct mmc_host *);
 void mmc_free_host(struct mmc_host *);
-void mmc_of_parse(struct mmc_host *host);
+int mmc_of_parse(struct mmc_host *host);
 
 static inline void *mmc_priv(struct mmc_host *host)
 {
@@ -425,10 +425,6 @@ static inline int mmc_regulator_get_supply(struct mmc_host *mmc)
 }
 #endif
 
-int mmc_card_awake(struct mmc_host *host);
-int mmc_card_sleep(struct mmc_host *host);
-int mmc_card_can_sleep(struct mmc_host *host);
-
 int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *);
 
 /* Module parameter */
index b838ffc..e3c6a74 100644 (file)
@@ -95,6 +95,9 @@ struct sdhci_host {
 /* The system physically doesn't support 1.8v, even if the host does */
 #define SDHCI_QUIRK2_NO_1_8_V                          (1<<2)
 #define SDHCI_QUIRK2_PRESET_VALUE_BROKEN               (1<<3)
+#define SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON              (1<<4)
+/* Controller has a non-standard host control register */
+#define SDHCI_QUIRK2_BROKEN_HOST_CONTROL               (1<<5)
 
        int irq;                /* Device IRQ */
        void __iomem *ioaddr;   /* Mapped address */
@@ -126,7 +129,7 @@ struct sdhci_host {
 #define SDHCI_AUTO_CMD23       (1<<7)  /* Auto CMD23 support */
 #define SDHCI_PV_ENABLED       (1<<8)  /* Preset value enabled */
 #define SDHCI_SDIO_IRQ_ENABLED (1<<9)  /* SDIO irq enabled */
-#define SDHCI_HS200_NEEDS_TUNING (1<<10)       /* HS200 needs tuning */
+#define SDHCI_SDR104_NEEDS_TUNING (1<<10)      /* SDR104/HS200 needs tuning */
 #define SDHCI_USING_RETUNING_TIMER (1<<11)     /* Host is using a retuning timer for the card */
 
        unsigned int version;   /* SDHCI spec. version */
@@ -139,6 +142,7 @@ struct sdhci_host {
        u8 pwr;                 /* Current voltage */
 
        bool runtime_suspended; /* Host is runtime suspended */
+       bool bus_on;            /* Bus power prevents runtime suspend */
 
        struct mmc_request *mrq;        /* Current request */
        struct mmc_command *cmd;        /* Current command */
index b4a0521..d44912d 100644 (file)
@@ -40,5 +40,6 @@ struct esdhc_platform_data {
        enum wp_types wp_type;
        enum cd_types cd_type;
        int max_bus_width;
+       unsigned int f_max;
 };
 #endif /* __ASM_ARCH_IMX_ESDHC_H */