]> Pileus Git - ~andy/linux/commitdiff
Merge tag 'mmc-updates-for-3.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 11 Dec 2012 19:19:09 +0000 (11:19 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 11 Dec 2012 19:19:09 +0000 (11:19 -0800)
Pull MMC updates from Chris Ball:
 "MMC highlights for 3.8:

  Core:
   - Expose access to the eMMC RPMB ("Replay Protected Memory Block")
     area by extending the existing mmc_block ioctl.
   - Add SDIO powered-suspend DT properties to the core MMC DT binding.
   - Add no-1-8-v DT flag for boards where the SD controller reports
     that it supports 1.8V but the board itself has no way to switch to
     1.8V.
   - More work on switching to 1.8V UHS support using a vqmmc regulator.
   - Fix up a case where the slot-gpio helper may fail to reset the host
     controller properly if a card was removed during a transfer.
   - Fix several cases where a broken device could cause an infinite
     loop while we wait for a register to update.

  Drivers:
   - at91-mci: Remove obsolete driver, atmel-mci handles these devices
     now.
   - sdhci-dove: Allow using GPIOs for card-detect notifications.
   - sdhci-esdhc: Fix for recovering from ADMA errors on broken silicon.
   - sdhci-s3c: Add pinctrl support.
   - wmt-sdmmc: New driver for WonderMedia SD/MMC controllers."

* tag 'mmc-updates-for-3.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (65 commits)
  mmc: sdhci: implement the .card_event() method
  mmc: extend the slot-gpio card-detection to use host's .card_event() method
  mmc: add a card-event host operation
  mmc: sdhci-s3c: Fix compilation warning
  mmc: sdhci-pci: Enable SDHCI_CAN_DO_HISPD for Ricoh SDHCI controller
  mmc: sdhci-dove: allow GPIOs to be used for card detection on Dove
  mmc: sdhci-dove: use two-stage initialization for sdhci-pltfm
  mmc: sdhci-dove: use devm_clk_get()
  mmc: eSDHC: Recover from ADMA errors
  mmc: dw_mmc: remove duplicated buswidth code
  mmc: dw_mmc: relocate where dw_mci_setup_bus() is called from
  mmc: Limit MMC speed to 52MHz if not HS200
  mmc: dw_mmc: use devres functions in dw_mmc
  mmc: sh_mmcif: remove unneeded clock connection ID
  mmc: sh_mobile_sdhi: remove unneeded clock connection ID
  mmc: sh_mobile_sdhi: fix clock frequency printing
  mmc: Remove redundant null check before kfree in bus.c
  mmc: Remove redundant null check before kfree in sdio_bus.c
  mmc: sdhci-imx-esdhc: use more devm_* functions
  mmc: dt: add no-1-8-v device tree flag
  ...

52 files changed:
Documentation/devicetree/bindings/mmc/mmc.txt
Documentation/devicetree/bindings/mmc/samsung-sdhci.txt
Documentation/devicetree/bindings/mmc/synopsis-dw-mshc.txt [moved from Documentation/devicetree/bindings/mmc/synposis-dw-mshc.txt with 100% similarity]
Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
Documentation/devicetree/bindings/mmc/vt8500-sdmmc.txt [new file with mode: 0644]
Documentation/mmc/mmc-dev-attrs.txt
MAINTAINERS
arch/arm/mach-at91/include/mach/board.h
arch/arm/plat-omap/include/plat/mmc.h
drivers/mmc/card/block.c
drivers/mmc/card/queue.c
drivers/mmc/core/bus.c
drivers/mmc/core/core.c
drivers/mmc/core/debugfs.c
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/sdio_bus.c
drivers/mmc/core/sdio_io.c
drivers/mmc/core/sdio_ops.c
drivers/mmc/core/slot-gpio.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/at91_mci.c [deleted file]
drivers/mmc/host/at91_mci.h [deleted file]
drivers/mmc/host/dw_mmc-pci.c
drivers/mmc/host/dw_mmc-pltfm.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/mxcmmc.c
drivers/mmc/host/mxs-mmc.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/sdhci-dove.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-pltfm.c
drivers/mmc/host/sdhci-pxav3.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci-spear.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/vub300.c
drivers/mmc/host/wmt-sdmmc.c [new file with mode: 0644]
include/linux/mmc/card.h
include/linux/mmc/core.h
include/linux/mmc/dw_mmc.h
include/linux/mmc/host.h
include/linux/mmc/mmc.h
include/linux/mmc/mxs-mmc.h [deleted file]
include/linux/mmc/sdhci.h
include/linux/platform_data/pxa_sdhci.h

index 8e2e0ba2f486c57ca3505e44fa85effd369c4495..a591c6741d75b2cd4cf9efd85641ff3a6787c408 100644 (file)
@@ -21,6 +21,12 @@ Optional properties:
 - cd-inverted: when present, polarity on the cd gpio line is inverted
 - wp-inverted: when present, polarity on the wp gpio line is inverted
 - max-frequency: maximum operating clock frequency
+- no-1-8-v: when present, denotes that 1.8v card voltage is not supported on
+  this system, even if the controller claims it is.
+
+Optional SDIO properties:
+- keep-power-in-suspend: Preserves card power during a suspend/resume cycle
+- enable-sdio-wakeup: Enables wake up of host system on SDIO IRQ assertion
 
 Example:
 
@@ -33,4 +39,6 @@ sdhci@ab000000 {
        cd-inverted;
        wp-gpios = <&gpio 70 0>;
        max-frequency = <50000000>;
+       keep-power-in-suspend;
+       enable-sdio-wakeup;
 }
index 630a7d7f47183bb9b1bf8d3510b3119a4fa5314c..97e9e315400d9b098476ca861918bf266784b81f 100644 (file)
@@ -12,10 +12,6 @@ is used. The Samsung's SDHCI controller bindings extends this as listed below.
 [A] The property "samsung,cd-pinmux-gpio" can be used as stated in the
     "Optional Board Specific Properties" section below.
 
-[B] If core card-detect bindings and "samsung,cd-pinmux-gpio" property
-    is not specified, it is assumed that there is no card detection
-    mechanism used.
-
 Required SoC Specific Properties:
 - compatible: should be one of the following
   - "samsung,s3c6410-sdhci": For controllers compatible with s3c6410 sdhci
@@ -24,14 +20,18 @@ Required SoC Specific Properties:
     controller.
 
 Required Board Specific Properties:
-- gpios: Should specify the gpios used for clock, command and data lines. The
-  gpio specifier format depends on the gpio controller.
+- Samsung GPIO variant (will be completely replaced by pinctrl):
+  - gpios: Should specify the gpios used for clock, command and data lines. The
+    gpio specifier format depends on the gpio controller.
+- Pinctrl variant (preferred if available):
+  - pinctrl-0: Should specify pin control groups used for this controller.
+  - pinctrl-names: Should contain only one value - "default".
 
 Optional Board Specific Properties:
 - samsung,cd-pinmux-gpio: Specifies the card detect line that is routed
   through a pinmux to the card-detect pin of the card slot. This property
   should be used only if none of the mmc core card-detect properties are
-  used.
+  used. Only for Samsung GPIO variant.
 
 Example:
        sdhci@12530000 {
@@ -40,12 +40,18 @@ Example:
                interrupts = <0 75 0>;
                bus-width = <4>;
                cd-gpios = <&gpk2 2 2 3 3>;
+
+               /* Samsung GPIO variant */
                gpios = <&gpk2 0 2 0 3>,  /* clock line */
                        <&gpk2 1 2 0 3>,  /* command line */
                        <&gpk2 3 2 3 3>,  /* data line 0 */
                        <&gpk2 4 2 3 3>,  /* data line 1 */
                        <&gpk2 5 2 3 3>,  /* data line 2 */
                        <&gpk2 6 2 3 3>;  /* data line 3 */
+
+               /* Pinctrl variant */
+               pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4>;
+               pinctrl-names = "default";
        };
 
        Note: This example shows both SoC specific and board specific properties
index be76a23b34c408133bb1d397c2c3395cac59c66a..ed271fc255b23c5d3595f1a1725687cb74d077be 100644 (file)
@@ -19,6 +19,7 @@ ti,dual-volt: boolean, supports dual voltage cards
 "supply-name" examples are "vmmc", "vmmc_aux" etc
 ti,non-removable: non-removable slot (like eMMC)
 ti,needs-special-reset: Requires a special softreset sequence
+ti,needs-special-hs-handling: HSMMC IP needs special setting for handling High Speed
 
 Example:
        mmc1: mmc@0x4809c000 {
diff --git a/Documentation/devicetree/bindings/mmc/vt8500-sdmmc.txt b/Documentation/devicetree/bindings/mmc/vt8500-sdmmc.txt
new file mode 100644 (file)
index 0000000..d7fb6ab
--- /dev/null
@@ -0,0 +1,23 @@
+* Wondermedia WM8505/WM8650 SD/MMC Host Controller
+
+This file documents differences between the core properties described
+by mmc.txt and the properties used by the wmt-sdmmc driver.
+
+Required properties:
+- compatible: Should be "wm,wm8505-sdhc".
+- interrupts: Two interrupts are required - regular irq and dma irq.
+
+Optional properties:
+- sdon-inverted: SD_ON bit is inverted on the controller
+
+Examples:
+
+sdhc@d800a000 {
+       compatible = "wm,wm8505-sdhc";
+       reg = <0xd800a000 0x1000>;
+       interrupts = <20 21>;
+       clocks = <&sdhc>;
+       bus-width = <4>;
+       sdon-inverted;
+};
+
index 22ae8441489fcef3fe8f21ff4322dc3a8b85e5e6..0d98fac8893b5ea1806781e8cef2fec4c654c805 100644 (file)
@@ -25,6 +25,8 @@ All attributes are read-only.
        serial                  Product Serial Number (from CID Register)
        erase_size              Erase group size
        preferred_erase_size    Preferred erase size
+       raw_rpmb_size_mult      RPMB partition size
+       rel_sectors             Reliable write sector count
 
 Note on Erase Size and Preferred Erase Size:
 
@@ -65,6 +67,11 @@ Note on Erase Size and Preferred Erase Size:
 
        "preferred_erase_size" is in bytes.
 
+Note on raw_rpmb_size_mult:
+       "raw_rpmb_size_mult" is a mutliple of 128kB block.
+       RPMB size in byte is calculated by using the following equation:
+       RPMB partition size = 128kB x raw_rpmb_size_mult
+
 SD/MMC/SDIO Clock Gating Attribute
 ==================================
 
index 9386a63ea8f63b653b683379ea54c7bd91eb72ec..3d3abbacc1a32823af34de166e8b5d867eb5dbfa 100644 (file)
@@ -1237,6 +1237,7 @@ F:        drivers/video/wm8505fb*
 F:     drivers/video/wmt_ge_rops.*
 F:     drivers/tty/serial/vt8500_serial.c
 F:     drivers/rtc/rtc-vt8500-c
+F:     drivers/mmc/host/wmt-sdmmc.c
 
 ARM/ZIPIT Z2 SUPPORT
 M:     Marek Vasut <marek.vasut@gmail.com>
@@ -1368,14 +1369,6 @@ S:       Maintained
 F:     drivers/atm/
 F:     include/linux/atm*
 
-ATMEL AT91 MCI DRIVER
-M:     Ludovic Desroches <ludovic.desroches@atmel.com>
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.atmel.com/products/AT91/
-W:     http://www.at91.com/
-S:     Maintained
-F:     drivers/mmc/host/at91_mci.c
-
 ATMEL AT91 / AT32 MCI DRIVER
 M:     Ludovic Desroches <ludovic.desroches@atmel.com>
 S:     Maintained
index c55a4364ffb433867aa150485880f7467081625f..a0d92a960f46c31654bb1777a9e034babb8a6615 100644 (file)
@@ -70,16 +70,6 @@ struct at91_cf_data {
 extern void __init at91_add_device_cf(struct at91_cf_data *data);
 
  /* MMC / SD */
-  /* at91_mci platform config */
-struct at91_mmc_data {
-       int             det_pin;        /* card detect IRQ */
-       unsigned        slot_b:1;       /* uses Slot B */
-       unsigned        wire4:1;        /* (SD) supports DAT0..DAT3 */
-       int             wp_pin;         /* (SD) writeprotect detect */
-       int             vcc_pin;        /* power switching (high == on) */
-};
-extern void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data);
-
   /* atmel-mci platform config */
 extern void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data);
 
index 8b4e4f2da2f5456c1d05321a641e5e473214fd62..346af5b490be0f02e187b3c080b3140f6192941a 100644 (file)
@@ -126,6 +126,7 @@ struct omap_mmc_platform_data {
                /* we can put the features above into this variable */
 #define HSMMC_HAS_PBIAS                (1 << 0)
 #define HSMMC_HAS_UPDATED_RESET        (1 << 1)
+#define HSMMC_HAS_HSPE_SUPPORT (1 << 2)
                unsigned features;
 
                int switch_pin;                 /* gpio (card detect) */
index 172a768036d87d700c018d36cdfdf9dc7093ae4d..21056b9ef0a0f97bf9f1e71de1e78a3253cd5284 100644 (file)
@@ -57,6 +57,7 @@ MODULE_ALIAS("mmc:block");
 #define INAND_CMD38_ARG_SECERASE 0x80
 #define INAND_CMD38_ARG_SECTRIM1 0x81
 #define INAND_CMD38_ARG_SECTRIM2 0x88
+#define MMC_BLK_TIMEOUT_MS  (10 * 60 * 1000)        /* 10 minute timeout */
 
 static DEFINE_MUTEX(block_mutex);
 
@@ -126,6 +127,10 @@ enum mmc_blk_status {
 module_param(perdev_minors, int, 0444);
 MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
 
+static inline int mmc_blk_part_switch(struct mmc_card *card,
+                                     struct mmc_blk_data *md);
+static int get_card_status(struct mmc_card *card, u32 *status, int retries);
+
 static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
 {
        struct mmc_blk_data *md;
@@ -357,6 +362,38 @@ out:
        return ERR_PTR(err);
 }
 
+static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status,
+                                      u32 retries_max)
+{
+       int err;
+       u32 retry_count = 0;
+
+       if (!status || !retries_max)
+               return -EINVAL;
+
+       do {
+               err = get_card_status(card, status, 5);
+               if (err)
+                       break;
+
+               if (!R1_STATUS(*status) &&
+                               (R1_CURRENT_STATE(*status) != R1_STATE_PRG))
+                       break; /* RPMB programming operation complete */
+
+               /*
+                * Rechedule to give the MMC device a chance to continue
+                * processing the previous command without being polled too
+                * frequently.
+                */
+               usleep_range(1000, 5000);
+       } while (++retry_count < retries_max);
+
+       if (retry_count == retries_max)
+               err = -EPERM;
+
+       return err;
+}
+
 static int mmc_blk_ioctl_cmd(struct block_device *bdev,
        struct mmc_ioc_cmd __user *ic_ptr)
 {
@@ -368,6 +405,8 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
        struct mmc_request mrq = {NULL};
        struct scatterlist sg;
        int err;
+       int is_rpmb = false;
+       u32 status = 0;
 
        /*
         * The caller must have CAP_SYS_RAWIO, and must be calling this on the
@@ -387,6 +426,9 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
                goto cmd_err;
        }
 
+       if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
+               is_rpmb = true;
+
        card = md->queue.card;
        if (IS_ERR(card)) {
                err = PTR_ERR(card);
@@ -437,12 +479,23 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
 
        mmc_claim_host(card->host);
 
+       err = mmc_blk_part_switch(card, md);
+       if (err)
+               goto cmd_rel_host;
+
        if (idata->ic.is_acmd) {
                err = mmc_app_cmd(card->host, card);
                if (err)
                        goto cmd_rel_host;
        }
 
+       if (is_rpmb) {
+               err = mmc_set_blockcount(card, data.blocks,
+                       idata->ic.write_flag & (1 << 31));
+               if (err)
+                       goto cmd_rel_host;
+       }
+
        mmc_wait_for_req(card->host, &mrq);
 
        if (cmd.error) {
@@ -478,6 +531,18 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
                }
        }
 
+       if (is_rpmb) {
+               /*
+                * Ensure RPMB command has completed by polling CMD13
+                * "Send Status".
+                */
+               err = ioctl_rpmb_card_status_poll(card, &status, 5);
+               if (err)
+                       dev_err(mmc_dev(card->host),
+                                       "%s: Card Status=0x%08X, error %d\n",
+                                       __func__, status, err);
+       }
+
 cmd_rel_host:
        mmc_release_host(card->host);
 
@@ -1034,6 +1099,9 @@ static int mmc_blk_err_check(struct mmc_card *card,
         */
        if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
                u32 status;
+               unsigned long timeout;
+
+               timeout = jiffies + msecs_to_jiffies(MMC_BLK_TIMEOUT_MS);
                do {
                        int err = get_card_status(card, &status, 5);
                        if (err) {
@@ -1041,6 +1109,17 @@ static int mmc_blk_err_check(struct mmc_card *card,
                                       req->rq_disk->disk_name, err);
                                return MMC_BLK_CMD_ERR;
                        }
+
+                       /* Timeout if the device never becomes ready for data
+                        * and never leaves the program state.
+                        */
+                       if (time_after(jiffies, timeout)) {
+                               pr_err("%s: Card stuck in programming state!"\
+                                       " %s %s\n", mmc_hostname(card->host),
+                                       req->rq_disk->disk_name, __func__);
+
+                               return MMC_BLK_CMD_ERR;
+                       }
                        /*
                         * Some cards mishandle the status bits,
                         * so make sure to check both the busy
@@ -1504,6 +1583,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
        md->disk->queue = md->queue.queue;
        md->disk->driverfs_dev = parent;
        set_disk_ro(md->disk, md->read_only || default_ro);
+       if (area_type & MMC_BLK_DATA_AREA_RPMB)
+               md->disk->flags |= GENHD_FL_NO_PART_SCAN;
 
        /*
         * As discussed on lkml, GENHD_FL_REMOVABLE should:
index e360a979857d297e1468a7c9aa41b86a975a2f82..fadf52eb5d70d410bc0055d379b248413e680d6b 100644 (file)
@@ -68,6 +68,16 @@ static int mmc_queue_thread(void *d)
                if (req || mq->mqrq_prev->req) {
                        set_current_state(TASK_RUNNING);
                        mq->issue_fn(mq, req);
+
+                       /*
+                        * Current request becomes previous request
+                        * and vice versa.
+                        */
+                       mq->mqrq_prev->brq.mrq.data = NULL;
+                       mq->mqrq_prev->req = NULL;
+                       tmp = mq->mqrq_prev;
+                       mq->mqrq_prev = mq->mqrq_cur;
+                       mq->mqrq_cur = tmp;
                } else {
                        if (kthread_should_stop()) {
                                set_current_state(TASK_RUNNING);
@@ -77,13 +87,6 @@ static int mmc_queue_thread(void *d)
                        schedule();
                        down(&mq->thread_sem);
                }
-
-               /* Current request becomes previous request and vice versa. */
-               mq->mqrq_prev->brq.mrq.data = NULL;
-               mq->mqrq_prev->req = NULL;
-               tmp = mq->mqrq_prev;
-               mq->mqrq_prev = mq->mqrq_cur;
-               mq->mqrq_cur = tmp;
        } while (1);
        up(&mq->thread_sem);
 
index 9b68933f27e783260242d5568b860cabaf8c6f0e..420cb6753c1e74c48a604b27cd9fc54752390085 100644 (file)
@@ -225,8 +225,7 @@ static void mmc_release_card(struct device *dev)
 
        sdio_free_common_cis(card);
 
-       if (card->info)
-               kfree(card->info);
+       kfree(card->info);
 
        kfree(card);
 }
index 06c42cfb7c34d9fa972c48eeb257e5e8b50b43b8..aaed7687cf094fd9659dae2892b89c9ccd89c138 100644 (file)
@@ -42,6 +42,9 @@
 #include "sd_ops.h"
 #include "sdio_ops.h"
 
+/* If the device is not responding */
+#define MMC_CORE_TIMEOUT_MS    (10 * 60 * 1000) /* 10 minute timeout */
+
 /*
  * Background operations can take a long time, depending on the housekeeping
  * operations the card has to perform.
@@ -1631,6 +1634,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
 {
        struct mmc_command cmd = {0};
        unsigned int qty = 0;
+       unsigned long timeout;
        int err;
 
        /*
@@ -1708,6 +1712,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
        if (mmc_host_is_spi(card->host))
                goto out;
 
+       timeout = jiffies + msecs_to_jiffies(MMC_CORE_TIMEOUT_MS);
        do {
                memset(&cmd, 0, sizeof(struct mmc_command));
                cmd.opcode = MMC_SEND_STATUS;
@@ -1721,8 +1726,19 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
                        err = -EIO;
                        goto out;
                }
+
+               /* Timeout if the device never becomes ready for data and
+                * never leaves the program state.
+                */
+               if (time_after(jiffies, timeout)) {
+                       pr_err("%s: Card stuck in programming state! %s\n",
+                               mmc_hostname(card->host), __func__);
+                       err =  -EIO;
+                       goto out;
+               }
+
        } while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
-                R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG);
+                (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG));
 out:
        return err;
 }
@@ -1942,6 +1958,20 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 }
 EXPORT_SYMBOL(mmc_set_blocklen);
 
+int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
+                       bool is_rel_write)
+{
+       struct mmc_command cmd = {0};
+
+       cmd.opcode = MMC_SET_BLOCK_COUNT;
+       cmd.arg = blockcount & 0x0000FFFF;
+       if (is_rel_write)
+               cmd.arg |= 1 << 31;
+       cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+       return mmc_wait_for_cmd(card->host, &cmd, 5);
+}
+EXPORT_SYMBOL(mmc_set_blockcount);
+
 static void mmc_hw_reset_for_init(struct mmc_host *host)
 {
        if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
index d96c643dde1c1b38eeeeaa0504d92f2d960b4088..35c2f85b1956ead16a75673d6e29e0aa137aaaed 100644 (file)
@@ -144,6 +144,22 @@ static int mmc_ios_show(struct seq_file *s, void *data)
        }
        seq_printf(s, "timing spec:\t%u (%s)\n", ios->timing, str);
 
+       switch (ios->signal_voltage) {
+       case MMC_SIGNAL_VOLTAGE_330:
+               str = "3.30 V";
+               break;
+       case MMC_SIGNAL_VOLTAGE_180:
+               str = "1.80 V";
+               break;
+       case MMC_SIGNAL_VOLTAGE_120:
+               str = "1.20 V";
+               break;
+       default:
+               str = "invalid";
+               break;
+       }
+       seq_printf(s, "signal voltage:\t%u (%s)\n", ios->chip_select, str);
+
        return 0;
 }
 
index 7cc46382fd644643f0323184709c551060fd9fa0..e6e39111e05b416623f830060fd8fca86f44edf5 100644 (file)
@@ -239,7 +239,7 @@ static void mmc_select_card_type(struct mmc_card *card)
 {
        struct mmc_host *host = card->host;
        u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
-       unsigned int caps = host->caps, caps2 = host->caps2;
+       u32 caps = host->caps, caps2 = host->caps2;
        unsigned int hs_max_dtr = 0;
 
        if (card_type & EXT_CSD_CARD_TYPE_26)
@@ -491,6 +491,17 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
 
                card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
                card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION];
+
+               /*
+                * RPMB regions are defined in multiples of 128K.
+                */
+               card->ext_csd.raw_rpmb_size_mult = ext_csd[EXT_CSD_RPMB_MULT];
+               if (ext_csd[EXT_CSD_RPMB_MULT]) {
+                       mmc_part_add(card, ext_csd[EXT_CSD_RPMB_MULT] << 17,
+                               EXT_CSD_PART_CONFIG_ACC_RPMB,
+                               "rpmb", 0, false,
+                               MMC_BLK_DATA_AREA_RPMB);
+               }
        }
 
        card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT];
@@ -615,6 +626,8 @@ MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
 MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
                card->ext_csd.enhanced_area_offset);
 MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
+MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult);
+MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);
 
 static struct attribute *mmc_std_attrs[] = {
        &dev_attr_cid.attr,
@@ -630,6 +643,8 @@ static struct attribute *mmc_std_attrs[] = {
        &dev_attr_serial.attr,
        &dev_attr_enhanced_area_offset.attr,
        &dev_attr_enhanced_area_size.attr,
+       &dev_attr_raw_rpmb_size_mult.attr,
+       &dev_attr_rel_sectors.attr,
        NULL,
 };
 
@@ -1051,6 +1066,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
                if (max_dtr > card->ext_csd.hs_max_dtr)
                        max_dtr = card->ext_csd.hs_max_dtr;
+               if (mmc_card_highspeed(card) && (max_dtr > 52000000))
+                       max_dtr = 52000000;
        } else if (max_dtr > card->csd.max_dtr) {
                max_dtr = card->csd.max_dtr;
        }
index a0e172042e658da3e3053ba851fc7c5bce2a631b..6d8f7012d73a6a3134a4b944ba774f3ec886ad0f 100644 (file)
@@ -21,6 +21,8 @@
 #include "core.h"
 #include "mmc_ops.h"
 
+#define MMC_OPS_TIMEOUT_MS     (10 * 60 * 1000) /* 10 minute timeout */
+
 static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
 {
        int err;
@@ -409,6 +411,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
 {
        int err;
        struct mmc_command cmd = {0};
+       unsigned long timeout;
        u32 status;
 
        BUG_ON(!card);
@@ -437,6 +440,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                return 0;
 
        /* Must check status to be sure of no errors */
+       timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);
        do {
                err = mmc_send_status(card, &status);
                if (err)
@@ -445,6 +449,13 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                        break;
                if (mmc_host_is_spi(card->host))
                        break;
+
+               /* Timeout if the device never leaves the program state. */
+               if (time_after(jiffies, timeout)) {
+                       pr_err("%s: Card stuck in programming state! %s\n",
+                               mmc_hostname(card->host), __func__);
+                       return -ETIMEDOUT;
+               }
        } while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
 
        if (mmc_host_is_spi(card->host)) {
index 6bf68799fe9733c18643d4e65f57c313abcd5b0b..5e57048e2c1d2c0fbb202600f9bfa45ffa0355c4 100644 (file)
@@ -193,7 +193,21 @@ static int sdio_bus_remove(struct device *dev)
 }
 
 #ifdef CONFIG_PM
+
+#ifdef CONFIG_PM_SLEEP
+static int pm_no_operation(struct device *dev)
+{
+       /*
+        * Prevent the PM core from calling SDIO device drivers' suspend
+        * callback routines, which it is not supposed to do, by using this
+        * empty function as the bus type suspend callaback for SDIO.
+        */
+       return 0;
+}
+#endif
+
 static const struct dev_pm_ops sdio_bus_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(pm_no_operation, pm_no_operation)
        SET_RUNTIME_PM_OPS(
                pm_generic_runtime_suspend,
                pm_generic_runtime_resume,
@@ -258,8 +272,7 @@ static void sdio_release_func(struct device *dev)
 
        sdio_free_func_cis(func);
 
-       if (func->info)
-               kfree(func->info);
+       kfree(func->info);
 
        kfree(func);
 }
index 8f6f5ac131fc43cd44e544151826d0e0ad29ac61..78cb4d5d9d58184754973a5e3eee1c64a635deb5 100644 (file)
@@ -188,8 +188,7 @@ EXPORT_SYMBOL_GPL(sdio_set_block_size);
  */
 static inline unsigned int sdio_max_byte_size(struct sdio_func *func)
 {
-       unsigned mval = min(func->card->host->max_seg_size,
-                           func->card->host->max_blk_size);
+       unsigned mval = func->card->host->max_blk_size;
 
        if (mmc_blksz_for_byte_mode(func->card))
                mval = min(mval, func->cur_blksize);
@@ -311,11 +310,8 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
        /* Do the bulk of the transfer using block mode (if supported). */
        if (func->card->cccr.multi_block && (size > sdio_max_byte_size(func))) {
                /* Blocks per command is limited by host count, host transfer
-                * size (we only use a single sg entry) and the maximum for
-                * IO_RW_EXTENDED of 511 blocks. */
-               max_blocks = min(func->card->host->max_blk_count,
-                       func->card->host->max_seg_size / func->cur_blksize);
-               max_blocks = min(max_blocks, 511u);
+                * size and the maximum for IO_RW_EXTENDED of 511 blocks. */
+               max_blocks = min(func->card->host->max_blk_count, 511u);
 
                while (remainder >= func->cur_blksize) {
                        unsigned blocks;
index d29e20630eed9249d339240d8e3ddd114d606a0a..62508b457c4f0c8563486f6d4d536135ddf80753 100644 (file)
@@ -124,7 +124,10 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
        struct mmc_request mrq = {NULL};
        struct mmc_command cmd = {0};
        struct mmc_data data = {0};
-       struct scatterlist sg;
+       struct scatterlist sg, *sg_ptr;
+       struct sg_table sgtable;
+       unsigned int nents, left_size, i;
+       unsigned int seg_size = card->host->max_seg_size;
 
        BUG_ON(!card);
        BUG_ON(fn > 7);
@@ -152,15 +155,36 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
        /* Code in host drivers/fwk assumes that "blocks" always is >=1 */
        data.blocks = blocks ? blocks : 1;
        data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
-       data.sg = &sg;
-       data.sg_len = 1;
 
-       sg_init_one(&sg, buf, data.blksz * data.blocks);
+       left_size = data.blksz * data.blocks;
+       nents = (left_size - 1) / seg_size + 1;
+       if (nents > 1) {
+               if (sg_alloc_table(&sgtable, nents, GFP_KERNEL))
+                       return -ENOMEM;
+
+               data.sg = sgtable.sgl;
+               data.sg_len = nents;
+
+               for_each_sg(data.sg, sg_ptr, data.sg_len, i) {
+                       sg_set_page(sg_ptr, virt_to_page(buf + (i * seg_size)),
+                                       min(seg_size, left_size),
+                                       offset_in_page(buf + (i * seg_size)));
+                       left_size = left_size - seg_size;
+               }
+       } else {
+               data.sg = &sg;
+               data.sg_len = 1;
+
+               sg_init_one(&sg, buf, left_size);
+       }
 
        mmc_set_data_timeout(&data, card);
 
        mmc_wait_for_req(card->host, &mrq);
 
+       if (nents > 1)
+               sg_free_table(&sgtable);
+
        if (cmd.error)
                return cmd.error;
        if (data.error)
index 08c6b3dfe080497509e9f431d0ababdc51626b29..16a1c0b6f2648bee603cac262002b8fed37bf253 100644 (file)
@@ -27,7 +27,13 @@ struct mmc_gpio {
 static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
 {
        /* Schedule a card detection after a debounce timeout */
-       mmc_detect_change(dev_id, msecs_to_jiffies(100));
+       struct mmc_host *host = dev_id;
+
+       if (host->ops->card_event)
+               host->ops->card_event(host);
+
+       mmc_detect_change(host, msecs_to_jiffies(200));
+
        return IRQ_HANDLED;
 }
 
index 9bf10e7bbfaffaafed7a373cb320cfb76c5e7fce..83eb1e06ff7626e25f5fc6535abe80164bd11ce3 100644 (file)
@@ -270,26 +270,8 @@ config MMC_AU1X
 
          If unsure, say N.
 
-choice
-       prompt "Atmel SD/MMC Driver"
-       depends on AVR32 || ARCH_AT91
-       default MMC_ATMELMCI if AVR32
-       help
-         Choose which driver to use for the Atmel MCI Silicon
-
-config MMC_AT91
-       tristate "AT91 SD/MMC Card Interface support (DEPRECATED)"
-       depends on ARCH_AT91
-       help
-         This selects the AT91 MCI controller. This driver will
-         be removed soon (for more information have a look to
-         Documentation/feature-removal-schedule.txt). Please use
-         MMC_ATMEL_MCI.
-
-         If unsure, say N.
-
 config MMC_ATMELMCI
-       tristate "Atmel Multimedia Card Interface support"
+       tristate "Atmel SD/MMC Driver (Multimedia Card Interface)"
        depends on AVR32 || ARCH_AT91
        help
          This selects the Atmel Multimedia Card Interface driver. If
@@ -298,8 +280,6 @@ config MMC_ATMELMCI
 
          If unsure, say N.
 
-endchoice
-
 config MMC_ATMELMCI_DMA
        bool "Atmel MCI DMA support"
        depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE
@@ -621,3 +601,14 @@ config MMC_USHC
 
          Note: These controllers only support SDIO cards and do not
          support MMC or SD memory cards.
+
+config MMC_WMT
+       tristate "Wondermedia SD/MMC Host Controller support"
+       depends on ARCH_VT8500
+       default y
+       help
+         This selects support for the SD/MMC Host Controller on
+         Wondermedia WM8505/WM8650 based SoCs.
+
+         To compile this driver as a module, choose M here: the
+         module will be called wmt-sdmmc.
index 17ad0a7ba40b4bfcb79c665df49c4798747cece3..39d5e123470934d45c41151f366355f46770c647 100644 (file)
@@ -17,7 +17,6 @@ obj-$(CONFIG_MMC_WBSD)                += wbsd.o
 obj-$(CONFIG_MMC_AU1X)         += au1xmmc.o
 obj-$(CONFIG_MMC_OMAP)         += omap.o
 obj-$(CONFIG_MMC_OMAP_HS)      += omap_hsmmc.o
-obj-$(CONFIG_MMC_AT91)         += at91_mci.o
 obj-$(CONFIG_MMC_ATMELMCI)     += atmel-mci.o
 obj-$(CONFIG_MMC_TIFM_SD)      += tifm_sd.o
 obj-$(CONFIG_MMC_MSM)          += msm_sdcc.o
@@ -45,6 +44,7 @@ obj-$(CONFIG_MMC_SH_MMCIF)    += sh_mmcif.o
 obj-$(CONFIG_MMC_JZ4740)       += jz4740_mmc.o
 obj-$(CONFIG_MMC_VUB300)       += vub300.o
 obj-$(CONFIG_MMC_USHC)         += ushc.o
+obj-$(CONFIG_MMC_WMT)          += wmt-sdmmc.o
 
 obj-$(CONFIG_MMC_SDHCI_PLTFM)          += sdhci-pltfm.o
 obj-$(CONFIG_MMC_SDHCI_CNS3XXX)                += sdhci-cns3xxx.o
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
deleted file mode 100644 (file)
index 74bed0f..0000000
+++ /dev/null
@@ -1,1219 +0,0 @@
-/*
- *  linux/drivers/mmc/host/at91_mci.c - ATMEL AT91 MCI Driver
- *
- *  Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved
- *
- *  Copyright (C) 2006 Malcolm Noyes
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
-   This is the AT91 MCI driver that has been tested with both MMC cards
-   and SD-cards.  Boards that support write protect are now supported.
-   The CCAT91SBC001 board does not support SD cards.
-
-   The three entry points are at91_mci_request, at91_mci_set_ios
-   and at91_mci_get_ro.
-
-   SET IOS
-     This configures the device to put it into the correct mode and clock speed
-     required.
-
-   MCI REQUEST
-     MCI request processes the commands sent in the mmc_request structure. This
-     can consist of a processing command and a stop command in the case of
-     multiple block transfers.
-
-     There are three main types of request, commands, reads and writes.
-
-     Commands are straight forward. The command is submitted to the controller and
-     the request function returns. When the controller generates an interrupt to indicate
-     the command is finished, the response to the command are read and the mmc_request_done
-     function called to end the request.
-
-     Reads and writes work in a similar manner to normal commands but involve the PDC (DMA)
-     controller to manage the transfers.
-
-     A read is done from the controller directly to the scatterlist passed in from the request.
-     Due to a bug in the AT91RM9200 controller, when a read is completed, all the words are byte
-     swapped in the scatterlist buffers.  AT91SAM926x are not affected by this bug.
-
-     The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY
-
-     A write is slightly different in that the bytes to write are read from the scatterlist
-     into a dma memory buffer (this is in case the source buffer should be read only). The
-     entire write buffer is then done from this single dma memory buffer.
-
-     The sequence of write interrupts is: ENDTX, TXBUFE, NOTBUSY, CMDRDY
-
-   GET RO
-     Gets the status of the write protect pin, if available.
-*/
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk.h>
-#include <linux/atmel_pdc.h>
-#include <linux/gfp.h>
-#include <linux/highmem.h>
-
-#include <linux/mmc/host.h>
-#include <linux/mmc/sdio.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/gpio.h>
-
-#include <mach/board.h>
-#include <mach/cpu.h>
-
-#include "at91_mci.h"
-
-#define DRIVER_NAME "at91_mci"
-
-static inline int at91mci_is_mci1rev2xx(void)
-{
-       return (   cpu_is_at91sam9260()
-               || cpu_is_at91sam9263()
-               || cpu_is_at91sam9rl()
-               || cpu_is_at91sam9g10()
-               || cpu_is_at91sam9g20()
-               );
-}
-
-#define FL_SENT_COMMAND        (1 << 0)
-#define FL_SENT_STOP   (1 << 1)
-
-#define AT91_MCI_ERRORS        (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE       \
-               | AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE               \
-               | AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)
-
-#define at91_mci_read(host, reg)       __raw_readl((host)->baseaddr + (reg))
-#define at91_mci_write(host, reg, val) __raw_writel((val), (host)->baseaddr + (reg))
-
-#define MCI_BLKSIZE            512
-#define MCI_MAXBLKSIZE                 4095
-#define MCI_BLKATONCE          256
-#define MCI_BUFSIZE            (MCI_BLKSIZE * MCI_BLKATONCE)
-
-/*
- * Low level type for this driver
- */
-struct at91mci_host
-{
-       struct mmc_host *mmc;
-       struct mmc_command *cmd;
-       struct mmc_request *request;
-
-       void __iomem *baseaddr;
-       int irq;
-
-       struct at91_mmc_data *board;
-       int present;
-
-       struct clk *mci_clk;
-
-       /*
-        * Flag indicating when the command has been sent. This is used to
-        * work out whether or not to send the stop
-        */
-       unsigned int flags;
-       /* flag for current bus settings */
-       u32 bus_mode;
-
-       /* DMA buffer used for transmitting */
-       unsigned int* buffer;
-       dma_addr_t physical_address;
-       unsigned int total_length;
-
-       /* Latest in the scatterlist that has been enabled for transfer, but not freed */
-       int in_use_index;
-
-       /* Latest in the scatterlist that has been enabled for transfer */
-       int transfer_index;
-
-       /* Timer for timeouts */
-       struct timer_list timer;
-};
-
-/*
- * Reset the controller and restore most of the state
- */
-static void at91_reset_host(struct at91mci_host *host)
-{
-       unsigned long flags;
-       u32 mr;
-       u32 sdcr;
-       u32 dtor;
-       u32 imr;
-
-       local_irq_save(flags);
-       imr = at91_mci_read(host, AT91_MCI_IMR);
-
-       at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
-
-       /* save current state */
-       mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff;
-       sdcr = at91_mci_read(host, AT91_MCI_SDCR);
-       dtor = at91_mci_read(host, AT91_MCI_DTOR);
-
-       /* reset the controller */
-       at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
-
-       /* restore state */
-       at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
-       at91_mci_write(host, AT91_MCI_MR, mr);
-       at91_mci_write(host, AT91_MCI_SDCR, sdcr);
-       at91_mci_write(host, AT91_MCI_DTOR, dtor);
-       at91_mci_write(host, AT91_MCI_IER, imr);
-
-       /* make sure sdio interrupts will fire */
-       at91_mci_read(host, AT91_MCI_SR);
-
-       local_irq_restore(flags);
-}
-
-static void at91_timeout_timer(unsigned long data)
-{
-       struct at91mci_host *host;
-
-       host = (struct at91mci_host *)data;
-
-       if (host->request) {
-               dev_err(host->mmc->parent, "Timeout waiting end of packet\n");
-
-               if (host->cmd && host->cmd->data) {
-                       host->cmd->data->error = -ETIMEDOUT;
-               } else {
-                       if (host->cmd)
-                               host->cmd->error = -ETIMEDOUT;
-                       else
-                               host->request->cmd->error = -ETIMEDOUT;
-               }
-
-               at91_reset_host(host);
-               mmc_request_done(host->mmc, host->request);
-       }
-}
-
-/*
- * Copy from sg to a dma block - used for transfers
- */
-static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data)
-{
-       unsigned int len, i, size;
-       unsigned *dmabuf = host->buffer;
-
-       size = data->blksz * data->blocks;
-       len = data->sg_len;
-
-       /* MCI1 rev2xx Data Write Operation and number of bytes erratum */
-       if (at91mci_is_mci1rev2xx())
-               if (host->total_length == 12)
-                       memset(dmabuf, 0, 12);
-
-       /*
-        * Just loop through all entries. Size might not
-        * be the entire list though so make sure that
-        * we do not transfer too much.
-        */
-       for (i = 0; i < len; i++) {
-               struct scatterlist *sg;
-               int amount;
-               unsigned int *sgbuffer;
-
-               sg = &data->sg[i];
-
-               sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset;
-               amount = min(size, sg->length);
-               size -= amount;
-
-               if (cpu_is_at91rm9200()) {      /* AT91RM9200 errata */
-                       int index;
-
-                       for (index = 0; index < (amount / 4); index++)
-                               *dmabuf++ = swab32(sgbuffer[index]);
-               } else {
-                       char *tmpv = (char *)dmabuf;
-                       memcpy(tmpv, sgbuffer, amount);
-                       tmpv += amount;
-                       dmabuf = (unsigned *)tmpv;
-               }
-
-               kunmap_atomic(sgbuffer);
-
-               if (size == 0)
-                       break;
-       }
-
-       /*
-        * Check that we didn't get a request to transfer
-        * more data than can fit into the SG list.
-        */
-       BUG_ON(size != 0);
-}
-
-/*
- * Handle after a dma read
- */
-static void at91_mci_post_dma_read(struct at91mci_host *host)
-{
-       struct mmc_command *cmd;
-       struct mmc_data *data;
-       unsigned int len, i, size;
-       unsigned *dmabuf = host->buffer;
-
-       pr_debug("post dma read\n");
-
-       cmd = host->cmd;
-       if (!cmd) {
-               pr_debug("no command\n");
-               return;
-       }
-
-       data = cmd->data;
-       if (!data) {
-               pr_debug("no data\n");
-               return;
-       }
-
-       size = data->blksz * data->blocks;
-       len = data->sg_len;
-
-       at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_ENDRX);
-       at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF);
-
-       for (i = 0; i < len; i++) {
-               struct scatterlist *sg;
-               int amount;
-               unsigned int *sgbuffer;
-
-               sg = &data->sg[i];
-
-               sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset;
-               amount = min(size, sg->length);
-               size -= amount;
-
-               if (cpu_is_at91rm9200()) {      /* AT91RM9200 errata */
-                       int index;
-                       for (index = 0; index < (amount / 4); index++)
-                               sgbuffer[index] = swab32(*dmabuf++);
-               } else {
-                       char *tmpv = (char *)dmabuf;
-                       memcpy(sgbuffer, tmpv, amount);
-                       tmpv += amount;
-                       dmabuf = (unsigned *)tmpv;
-               }
-
-               flush_kernel_dcache_page(sg_page(sg));
-               kunmap_atomic(sgbuffer);
-               data->bytes_xfered += amount;
-               if (size == 0)
-                       break;
-       }
-
-       pr_debug("post dma read done\n");
-}
-
-/*
- * Handle transmitted data
- */
-static void at91_mci_handle_transmitted(struct at91mci_host *host)
-{
-       struct mmc_command *cmd;
-       struct mmc_data *data;
-
-       pr_debug("Handling the transmit\n");
-
-       /* Disable the transfer */
-       at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
-
-       /* Now wait for cmd ready */
-       at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE);
-
-       cmd = host->cmd;
-       if (!cmd) return;
-
-       data = cmd->data;
-       if (!data) return;
-
-       if (cmd->data->blocks > 1) {
-               pr_debug("multiple write : wait for BLKE...\n");
-               at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE);
-       } else
-               at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
-}
-
-/*
- * Update bytes transfered count during a write operation
- */
-static void at91_mci_update_bytes_xfered(struct at91mci_host *host)
-{
-       struct mmc_data *data;
-
-       /* always deal with the effective request (and not the current cmd) */
-
-       if (host->request->cmd && host->request->cmd->error != 0)
-               return;
-
-       if (host->request->data) {
-               data = host->request->data;
-               if (data->flags & MMC_DATA_WRITE) {
-                       /* card is in IDLE mode now */
-                       pr_debug("-> bytes_xfered %d, total_length = %d\n",
-                               data->bytes_xfered, host->total_length);
-                       data->bytes_xfered = data->blksz * data->blocks;
-               }
-       }
-}
-
-
-/*Handle after command sent ready*/
-static int at91_mci_handle_cmdrdy(struct at91mci_host *host)
-{
-       if (!host->cmd)
-               return 1;
-       else if (!host->cmd->data) {
-               if (host->flags & FL_SENT_STOP) {
-                       /*After multi block write, we must wait for NOTBUSY*/
-                       at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
-               } else return 1;
-       } else if (host->cmd->data->flags & MMC_DATA_WRITE) {
-               /*After sendding multi-block-write command, start DMA transfer*/
-               at91_mci_write(host, AT91_MCI_IER, AT91_MCI_TXBUFE | AT91_MCI_BLKE);
-               at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
-       }
-
-       /* command not completed, have to wait */
-       return 0;
-}
-
-
-/*
- * Enable the controller
- */
-static void at91_mci_enable(struct at91mci_host *host)
-{
-       unsigned int mr;
-
-       at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
-       at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
-       at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);
-       mr = AT91_MCI_PDCMODE | 0x34a;
-
-       if (at91mci_is_mci1rev2xx())
-               mr |= AT91_MCI_RDPROOF | AT91_MCI_WRPROOF;
-
-       at91_mci_write(host, AT91_MCI_MR, mr);
-
-       /* use Slot A or B (only one at same time) */
-       at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b);
-}
-
-/*
- * Disable the controller
- */
-static void at91_mci_disable(struct at91mci_host *host)
-{
-       at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
-}
-
-/*
- * Send a command
- */
-static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd)
-{
-       unsigned int cmdr, mr;
-       unsigned int block_length;
-       struct mmc_data *data = cmd->data;
-
-       unsigned int blocks;
-       unsigned int ier = 0;
-
-       host->cmd = cmd;
-
-       /* Needed for leaving busy state before CMD1 */
-       if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {
-               pr_debug("Clearing timeout\n");
-               at91_mci_write(host, AT91_MCI_ARGR, 0);
-               at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD);
-               while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
-                       /* spin */
-                       pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR));
-               }
-       }
-
-       cmdr = cmd->opcode;
-
-       if (mmc_resp_type(cmd) == MMC_RSP_NONE)
-               cmdr |= AT91_MCI_RSPTYP_NONE;
-       else {
-               /* if a response is expected then allow maximum response latancy */
-               cmdr |= AT91_MCI_MAXLAT;
-               /* set 136 bit response for R2, 48 bit response otherwise */
-               if (mmc_resp_type(cmd) == MMC_RSP_R2)
-                       cmdr |= AT91_MCI_RSPTYP_136;
-               else
-                       cmdr |= AT91_MCI_RSPTYP_48;
-       }
-
-       if (data) {
-
-               if (cpu_is_at91rm9200() || cpu_is_at91sam9261()) {
-                       if (data->blksz & 0x3) {
-                               pr_debug("Unsupported block size\n");
-                               cmd->error = -EINVAL;
-                               mmc_request_done(host->mmc, host->request);
-                               return;
-                       }
-                       if (data->flags & MMC_DATA_STREAM) {
-                               pr_debug("Stream commands not supported\n");
-                               cmd->error = -EINVAL;
-                               mmc_request_done(host->mmc, host->request);
-                               return;
-                       }
-               }
-
-               block_length = data->blksz;
-               blocks = data->blocks;
-
-               /* always set data start - also set direction flag for read */
-               if (data->flags & MMC_DATA_READ)
-                       cmdr |= (AT91_MCI_TRDIR | AT91_MCI_TRCMD_START);
-               else if (data->flags & MMC_DATA_WRITE)
-                       cmdr |= AT91_MCI_TRCMD_START;
-
-               if (cmd->opcode == SD_IO_RW_EXTENDED) {
-                       cmdr |= AT91_MCI_TRTYP_SDIO_BLOCK;
-               } else {
-                       if (data->flags & MMC_DATA_STREAM)
-                               cmdr |= AT91_MCI_TRTYP_STREAM;
-                       if (data->blocks > 1)
-                               cmdr |= AT91_MCI_TRTYP_MULTIPLE;
-               }
-       }
-       else {
-               block_length = 0;
-               blocks = 0;
-       }
-
-       if (host->flags & FL_SENT_STOP)
-               cmdr |= AT91_MCI_TRCMD_STOP;
-
-       if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
-               cmdr |= AT91_MCI_OPDCMD;
-
-       /*
-        * Set the arguments and send the command
-        */
-       pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n",
-               cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR));
-
-       if (!data) {
-               at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS);
-               at91_mci_write(host, ATMEL_PDC_RPR, 0);
-               at91_mci_write(host, ATMEL_PDC_RCR, 0);
-               at91_mci_write(host, ATMEL_PDC_RNPR, 0);
-               at91_mci_write(host, ATMEL_PDC_RNCR, 0);
-               at91_mci_write(host, ATMEL_PDC_TPR, 0);
-               at91_mci_write(host, ATMEL_PDC_TCR, 0);
-               at91_mci_write(host, ATMEL_PDC_TNPR, 0);
-               at91_mci_write(host, ATMEL_PDC_TNCR, 0);
-               ier = AT91_MCI_CMDRDY;
-       } else {
-               /* zero block length and PDC mode */
-               mr = at91_mci_read(host, AT91_MCI_MR) & 0x5fff;
-               mr |= (data->blksz & 0x3) ? AT91_MCI_PDCFBYTE : 0;
-               mr |= (block_length << 16);
-               mr |= AT91_MCI_PDCMODE;
-               at91_mci_write(host, AT91_MCI_MR, mr);
-
-               if (!(cpu_is_at91rm9200() || cpu_is_at91sam9261()))
-                       at91_mci_write(host, AT91_MCI_BLKR,
-                               AT91_MCI_BLKR_BCNT(blocks) |
-                               AT91_MCI_BLKR_BLKLEN(block_length));
-
-               /*
-                * Disable the PDC controller
-                */
-               at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
-
-               if (cmdr & AT91_MCI_TRCMD_START) {
-                       data->bytes_xfered = 0;
-                       host->transfer_index = 0;
-                       host->in_use_index = 0;
-                       if (cmdr & AT91_MCI_TRDIR) {
-                               /*
-                                * Handle a read
-                                */
-                               host->total_length = 0;
-
-                               at91_mci_write(host, ATMEL_PDC_RPR, host->physical_address);
-                               at91_mci_write(host, ATMEL_PDC_RCR, (data->blksz & 0x3) ?
-                                       (blocks * block_length) : (blocks * block_length) / 4);
-                               at91_mci_write(host, ATMEL_PDC_RNPR, 0);
-                               at91_mci_write(host, ATMEL_PDC_RNCR, 0);
-
-                               ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */;
-                       }
-                       else {
-                               /*
-                                * Handle a write
-                                */
-                               host->total_length = block_length * blocks;
-                               /*
-                                * MCI1 rev2xx Data Write Operation and
-                                * number of bytes erratum
-                                */
-                               if (at91mci_is_mci1rev2xx())
-                                       if (host->total_length < 12)
-                                               host->total_length = 12;
-
-                               at91_mci_sg_to_dma(host, data);
-
-                               pr_debug("Transmitting %d bytes\n", host->total_length);
-
-                               at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address);
-                               at91_mci_write(host, ATMEL_PDC_TCR, (data->blksz & 0x3) ?
-                                               host->total_length : host->total_length / 4);
-
-                               ier = AT91_MCI_CMDRDY;
-                       }
-               }
-       }
-
-       /*
-        * Send the command and then enable the PDC - not the other way round as
-        * the data sheet says
-        */
-
-       at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
-       at91_mci_write(host, AT91_MCI_CMDR, cmdr);
-
-       if (cmdr & AT91_MCI_TRCMD_START) {
-               if (cmdr & AT91_MCI_TRDIR)
-                       at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);
-       }
-
-       /* Enable selected interrupts */
-       at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier);
-}
-
-/*
- * Process the next step in the request
- */
-static void at91_mci_process_next(struct at91mci_host *host)
-{
-       if (!(host->flags & FL_SENT_COMMAND)) {
-               host->flags |= FL_SENT_COMMAND;
-               at91_mci_send_command(host, host->request->cmd);
-       }
-       else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) {
-               host->flags |= FL_SENT_STOP;
-               at91_mci_send_command(host, host->request->stop);
-       } else {
-               del_timer(&host->timer);
-               /* the at91rm9200 mci controller hangs after some transfers,
-                * and the workaround is to reset it after each transfer.
-                */
-               if (cpu_is_at91rm9200())
-                       at91_reset_host(host);
-               mmc_request_done(host->mmc, host->request);
-       }
-}
-
-/*
- * Handle a command that has been completed
- */
-static void at91_mci_completed_command(struct at91mci_host *host, unsigned int status)
-{
-       struct mmc_command *cmd = host->cmd;
-       struct mmc_data *data = cmd->data;
-
-       at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
-
-       cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0));
-       cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1));
-       cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2));
-       cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3));
-
-       pr_debug("Status = %08X/%08x [%08X %08X %08X %08X]\n",
-                status, at91_mci_read(host, AT91_MCI_SR),
-                cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
-
-       if (status & AT91_MCI_ERRORS) {
-               if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) {
-                       cmd->error = 0;
-               }
-               else {
-                       if (status & (AT91_MCI_DTOE | AT91_MCI_DCRCE)) {
-                               if (data) {
-                                       if (status & AT91_MCI_DTOE)
-                                               data->error = -ETIMEDOUT;
-                                       else if (status & AT91_MCI_DCRCE)
-                                               data->error = -EILSEQ;
-                               }
-                       } else {
-                               if (status & AT91_MCI_RTOE)
-                                       cmd->error = -ETIMEDOUT;
-                               else if (status & AT91_MCI_RCRCE)
-                                       cmd->error = -EILSEQ;
-                               else
-                                       cmd->error = -EIO;
-                       }
-
-                       pr_debug("Error detected and set to %d/%d (cmd = %d, retries = %d)\n",
-                               cmd->error, data ? data->error : 0,
-                                cmd->opcode, cmd->retries);
-               }
-       }
-       else
-               cmd->error = 0;
-
-       at91_mci_process_next(host);
-}
-
-/*
- * Handle an MMC request
- */
-static void at91_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
-       struct at91mci_host *host = mmc_priv(mmc);
-       host->request = mrq;
-       host->flags = 0;
-
-       /* more than 1s timeout needed with slow SD cards */
-       mod_timer(&host->timer, jiffies +  msecs_to_jiffies(2000));
-
-       at91_mci_process_next(host);
-}
-
-/*
- * Set the IOS
- */
-static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-       int clkdiv;
-       struct at91mci_host *host = mmc_priv(mmc);
-       unsigned long at91_master_clock = clk_get_rate(host->mci_clk);
-
-       host->bus_mode = ios->bus_mode;
-
-       if (ios->clock == 0) {
-               /* Disable the MCI controller */
-               at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS);
-               clkdiv = 0;
-       }
-       else {
-               /* Enable the MCI controller */
-               at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
-
-               if ((at91_master_clock % (ios->clock * 2)) == 0)
-                       clkdiv = ((at91_master_clock / ios->clock) / 2) - 1;
-               else
-                       clkdiv = (at91_master_clock / ios->clock) / 2;
-
-               pr_debug("clkdiv = %d. mcck = %ld\n", clkdiv,
-                       at91_master_clock / (2 * (clkdiv + 1)));
-       }
-       if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) {
-               pr_debug("MMC: Setting controller bus width to 4\n");
-               at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) | AT91_MCI_SDCBUS);
-       }
-       else {
-               pr_debug("MMC: Setting controller bus width to 1\n");
-               at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
-       }
-
-       /* Set the clock divider */
-       at91_mci_write(host, AT91_MCI_MR, (at91_mci_read(host, AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv);
-
-       /* maybe switch power to the card */
-       if (gpio_is_valid(host->board->vcc_pin)) {
-               switch (ios->power_mode) {
-                       case MMC_POWER_OFF:
-                               gpio_set_value(host->board->vcc_pin, 0);
-                               break;
-                       case MMC_POWER_UP:
-                               gpio_set_value(host->board->vcc_pin, 1);
-                               break;
-                       case MMC_POWER_ON:
-                               break;
-                       default:
-                               WARN_ON(1);
-               }
-       }
-}
-
-/*
- * Handle an interrupt
- */
-static irqreturn_t at91_mci_irq(int irq, void *devid)
-{
-       struct at91mci_host *host = devid;
-       int completed = 0;
-       unsigned int int_status, int_mask;
-
-       int_status = at91_mci_read(host, AT91_MCI_SR);
-       int_mask = at91_mci_read(host, AT91_MCI_IMR);
-
-       pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask,
-               int_status & int_mask);
-
-       int_status = int_status & int_mask;
-
-       if (int_status & AT91_MCI_ERRORS) {
-               completed = 1;
-
-               if (int_status & AT91_MCI_UNRE)
-                       pr_debug("MMC: Underrun error\n");
-               if (int_status & AT91_MCI_OVRE)
-                       pr_debug("MMC: Overrun error\n");
-               if (int_status & AT91_MCI_DTOE)
-                       pr_debug("MMC: Data timeout\n");
-               if (int_status & AT91_MCI_DCRCE)
-                       pr_debug("MMC: CRC error in data\n");
-               if (int_status & AT91_MCI_RTOE)
-                       pr_debug("MMC: Response timeout\n");
-               if (int_status & AT91_MCI_RENDE)
-                       pr_debug("MMC: Response end bit error\n");
-               if (int_status & AT91_MCI_RCRCE)
-                       pr_debug("MMC: Response CRC error\n");
-               if (int_status & AT91_MCI_RDIRE)
-                       pr_debug("MMC: Response direction error\n");
-               if (int_status & AT91_MCI_RINDE)
-                       pr_debug("MMC: Response index error\n");
-       } else {
-               /* Only continue processing if no errors */
-
-               if (int_status & AT91_MCI_TXBUFE) {
-                       pr_debug("TX buffer empty\n");
-                       at91_mci_handle_transmitted(host);
-               }
-
-               if (int_status & AT91_MCI_ENDRX) {
-                       pr_debug("ENDRX\n");
-                       at91_mci_post_dma_read(host);
-               }
-
-               if (int_status & AT91_MCI_RXBUFF) {
-                       pr_debug("RX buffer full\n");
-                       at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
-                       at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_RXBUFF | AT91_MCI_ENDRX);
-                       completed = 1;
-               }
-
-               if (int_status & AT91_MCI_ENDTX)
-                       pr_debug("Transmit has ended\n");
-
-               if (int_status & AT91_MCI_NOTBUSY) {
-                       pr_debug("Card is ready\n");
-                       at91_mci_update_bytes_xfered(host);
-                       completed = 1;
-               }
-
-               if (int_status & AT91_MCI_DTIP)
-                       pr_debug("Data transfer in progress\n");
-
-               if (int_status & AT91_MCI_BLKE) {
-                       pr_debug("Block transfer has ended\n");
-                       if (host->request->data && host->request->data->blocks > 1) {
-                               /* multi block write : complete multi write
-                                * command and send stop */
-                               completed = 1;
-                       } else {
-                               at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
-                       }
-               }
-
-               if (int_status & AT91_MCI_SDIOIRQA)
-                       mmc_signal_sdio_irq(host->mmc);
-
-               if (int_status & AT91_MCI_SDIOIRQB)
-                       mmc_signal_sdio_irq(host->mmc);
-
-               if (int_status & AT91_MCI_TXRDY)
-                       pr_debug("Ready to transmit\n");
-
-               if (int_status & AT91_MCI_RXRDY)
-                       pr_debug("Ready to receive\n");
-
-               if (int_status & AT91_MCI_CMDRDY) {
-                       pr_debug("Command ready\n");
-                       completed = at91_mci_handle_cmdrdy(host);
-               }
-       }
-
-       if (completed) {
-               pr_debug("Completed command\n");
-               at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
-               at91_mci_completed_command(host, int_status);
-       } else
-               at91_mci_write(host, AT91_MCI_IDR, int_status & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t at91_mmc_det_irq(int irq, void *_host)
-{
-       struct at91mci_host *host = _host;
-       int present;
-
-       /* entering this ISR means that we have configured det_pin:
-        * we can use its value in board structure */
-       present = !gpio_get_value(host->board->det_pin);
-
-       /*
-        * we expect this irq on both insert and remove,
-        * and use a short delay to debounce.
-        */
-       if (present != host->present) {
-               host->present = present;
-               pr_debug("%s: card %s\n", mmc_hostname(host->mmc),
-                       present ? "insert" : "remove");
-               if (!present) {
-                       pr_debug("****** Resetting SD-card bus width ******\n");
-                       at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
-               }
-               /* 0.5s needed because of early card detect switch firing */
-               mmc_detect_change(host->mmc, msecs_to_jiffies(500));
-       }
-       return IRQ_HANDLED;
-}
-
-static int at91_mci_get_ro(struct mmc_host *mmc)
-{
-       struct at91mci_host *host = mmc_priv(mmc);
-
-       if (gpio_is_valid(host->board->wp_pin))
-               return !!gpio_get_value(host->board->wp_pin);
-       /*
-        * Board doesn't support read only detection; let the mmc core
-        * decide what to do.
-        */
-       return -ENOSYS;
-}
-
-static void at91_mci_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
-       struct at91mci_host *host = mmc_priv(mmc);
-
-       pr_debug("%s: sdio_irq %c : %s\n", mmc_hostname(host->mmc),
-               host->board->slot_b ? 'B':'A', enable ? "enable" : "disable");
-       at91_mci_write(host, enable ? AT91_MCI_IER : AT91_MCI_IDR,
-               host->board->slot_b ? AT91_MCI_SDIOIRQB : AT91_MCI_SDIOIRQA);
-
-}
-
-static const struct mmc_host_ops at91_mci_ops = {
-       .request        = at91_mci_request,
-       .set_ios        = at91_mci_set_ios,
-       .get_ro         = at91_mci_get_ro,
-       .enable_sdio_irq = at91_mci_enable_sdio_irq,
-};
-
-/*
- * Probe for the device
- */
-static int __init at91_mci_probe(struct platform_device *pdev)
-{
-       struct mmc_host *mmc;
-       struct at91mci_host *host;
-       struct resource *res;
-       int ret;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENXIO;
-
-       if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME))
-               return -EBUSY;
-
-       mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
-       if (!mmc) {
-               ret = -ENOMEM;
-               dev_dbg(&pdev->dev, "couldn't allocate mmc host\n");
-               goto fail6;
-       }
-
-       mmc->ops = &at91_mci_ops;
-       mmc->f_min = 375000;
-       mmc->f_max = 25000000;
-       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-       mmc->caps = 0;
-
-       mmc->max_blk_size  = MCI_MAXBLKSIZE;
-       mmc->max_blk_count = MCI_BLKATONCE;
-       mmc->max_req_size  = MCI_BUFSIZE;
-       mmc->max_segs      = MCI_BLKATONCE;
-       mmc->max_seg_size  = MCI_BUFSIZE;
-
-       host = mmc_priv(mmc);
-       host->mmc = mmc;
-       host->bus_mode = 0;
-       host->board = pdev->dev.platform_data;
-       if (host->board->wire4) {
-               if (at91mci_is_mci1rev2xx())
-                       mmc->caps |= MMC_CAP_4_BIT_DATA;
-               else
-                       dev_warn(&pdev->dev, "4 wire bus mode not supported"
-                               " - using 1 wire\n");
-       }
-
-       host->buffer = dma_alloc_coherent(&pdev->dev, MCI_BUFSIZE,
-                                       &host->physical_address, GFP_KERNEL);
-       if (!host->buffer) {
-               ret = -ENOMEM;
-               dev_err(&pdev->dev, "Can't allocate transmit buffer\n");
-               goto fail5;
-       }
-
-       /* Add SDIO capability when available */
-       if (at91mci_is_mci1rev2xx()) {
-               /* at91mci MCI1 rev2xx sdio interrupt erratum */
-               if (host->board->wire4 || !host->board->slot_b)
-                       mmc->caps |= MMC_CAP_SDIO_IRQ;
-       }
-
-       /*
-        * Reserve GPIOs ... board init code makes sure these pins are set
-        * up as GPIOs with the right direction (input, except for vcc)
-        */
-       if (gpio_is_valid(host->board->det_pin)) {
-               ret = gpio_request(host->board->det_pin, "mmc_detect");
-               if (ret < 0) {
-                       dev_dbg(&pdev->dev, "couldn't claim card detect pin\n");
-                       goto fail4b;
-               }
-       }
-       if (gpio_is_valid(host->board->wp_pin)) {
-               ret = gpio_request(host->board->wp_pin, "mmc_wp");
-               if (ret < 0) {
-                       dev_dbg(&pdev->dev, "couldn't claim wp sense pin\n");
-                       goto fail4;
-               }
-       }
-       if (gpio_is_valid(host->board->vcc_pin)) {
-               ret = gpio_request(host->board->vcc_pin, "mmc_vcc");
-               if (ret < 0) {
-                       dev_dbg(&pdev->dev, "couldn't claim vcc switch pin\n");
-                       goto fail3;
-               }
-       }
-
-       /*
-        * Get Clock
-        */
-       host->mci_clk = clk_get(&pdev->dev, "mci_clk");
-       if (IS_ERR(host->mci_clk)) {
-               ret = -ENODEV;
-               dev_dbg(&pdev->dev, "no mci_clk?\n");
-               goto fail2;
-       }
-
-       /*
-        * Map I/O region
-        */
-       host->baseaddr = ioremap(res->start, resource_size(res));
-       if (!host->baseaddr) {
-               ret = -ENOMEM;
-               goto fail1;
-       }
-
-       /*
-        * Reset hardware
-        */
-       clk_enable(host->mci_clk);              /* Enable the peripheral clock */
-       at91_mci_disable(host);
-       at91_mci_enable(host);
-
-       /*
-        * Allocate the MCI interrupt
-        */
-       host->irq = platform_get_irq(pdev, 0);
-       ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED,
-                       mmc_hostname(mmc), host);
-       if (ret) {
-               dev_dbg(&pdev->dev, "request MCI interrupt failed\n");
-               goto fail0;
-       }
-
-       setup_timer(&host->timer, at91_timeout_timer, (unsigned long)host);
-
-       platform_set_drvdata(pdev, mmc);
-
-       /*
-        * Add host to MMC layer
-        */
-       if (gpio_is_valid(host->board->det_pin)) {
-               host->present = !gpio_get_value(host->board->det_pin);
-       }
-       else
-               host->present = -1;
-
-       mmc_add_host(mmc);
-
-       /*
-        * monitor card insertion/removal if we can
-        */
-       if (gpio_is_valid(host->board->det_pin)) {
-               ret = request_irq(gpio_to_irq(host->board->det_pin),
-                               at91_mmc_det_irq, 0, mmc_hostname(mmc), host);
-               if (ret)
-                       dev_warn(&pdev->dev, "request MMC detect irq failed\n");
-               else
-                       device_init_wakeup(&pdev->dev, 1);
-       }
-
-       pr_debug("Added MCI driver\n");
-
-       return 0;
-
-fail0:
-       clk_disable(host->mci_clk);
-       iounmap(host->baseaddr);
-fail1:
-       clk_put(host->mci_clk);
-fail2:
-       if (gpio_is_valid(host->board->vcc_pin))
-               gpio_free(host->board->vcc_pin);
-fail3:
-       if (gpio_is_valid(host->board->wp_pin))
-               gpio_free(host->board->wp_pin);
-fail4:
-       if (gpio_is_valid(host->board->det_pin))
-               gpio_free(host->board->det_pin);
-fail4b:
-       if (host->buffer)
-               dma_free_coherent(&pdev->dev, MCI_BUFSIZE,
-                               host->buffer, host->physical_address);
-fail5:
-       mmc_free_host(mmc);
-fail6:
-       release_mem_region(res->start, resource_size(res));
-       dev_err(&pdev->dev, "probe failed, err %d\n", ret);
-       return ret;
-}
-
-/*
- * Remove a device
- */
-static int __exit at91_mci_remove(struct platform_device *pdev)
-{
-       struct mmc_host *mmc = platform_get_drvdata(pdev);
-       struct at91mci_host *host;
-       struct resource *res;
-
-       if (!mmc)
-               return -1;
-
-       host = mmc_priv(mmc);
-
-       if (host->buffer)
-               dma_free_coherent(&pdev->dev, MCI_BUFSIZE,
-                               host->buffer, host->physical_address);
-
-       if (gpio_is_valid(host->board->det_pin)) {
-               if (device_can_wakeup(&pdev->dev))
-                       free_irq(gpio_to_irq(host->board->det_pin), host);
-               device_init_wakeup(&pdev->dev, 0);
-               gpio_free(host->board->det_pin);
-       }
-
-       at91_mci_disable(host);
-       del_timer_sync(&host->timer);
-       mmc_remove_host(mmc);
-       free_irq(host->irq, host);
-
-       clk_disable(host->mci_clk);                     /* Disable the peripheral clock */
-       clk_put(host->mci_clk);
-
-       if (gpio_is_valid(host->board->vcc_pin))
-               gpio_free(host->board->vcc_pin);
-       if (gpio_is_valid(host->board->wp_pin))
-               gpio_free(host->board->wp_pin);
-
-       iounmap(host->baseaddr);
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, resource_size(res));
-
-       mmc_free_host(mmc);
-       platform_set_drvdata(pdev, NULL);
-       pr_debug("MCI Removed\n");
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
-{
-       struct mmc_host *mmc = platform_get_drvdata(pdev);
-       struct at91mci_host *host = mmc_priv(mmc);
-       int ret = 0;
-
-       if (gpio_is_valid(host->board->det_pin) && device_may_wakeup(&pdev->dev))
-               enable_irq_wake(host->board->det_pin);
-
-       if (mmc)
-               ret = mmc_suspend_host(mmc);
-
-       return ret;
-}
-
-static int at91_mci_resume(struct platform_device *pdev)
-{
-       struct mmc_host *mmc = platform_get_drvdata(pdev);
-       struct at91mci_host *host = mmc_priv(mmc);
-       int ret = 0;
-
-       if (gpio_is_valid(host->board->det_pin) && device_may_wakeup(&pdev->dev))
-               disable_irq_wake(host->board->det_pin);
-
-       if (mmc)
-               ret = mmc_resume_host(mmc);
-
-       return ret;
-}
-#else
-#define at91_mci_suspend       NULL
-#define at91_mci_resume                NULL
-#endif
-
-static struct platform_driver at91_mci_driver = {
-       .remove         = __exit_p(at91_mci_remove),
-       .suspend        = at91_mci_suspend,
-       .resume         = at91_mci_resume,
-       .driver         = {
-               .name   = DRIVER_NAME,
-               .owner  = THIS_MODULE,
-       },
-};
-
-static int __init at91_mci_init(void)
-{
-       return platform_driver_probe(&at91_mci_driver, at91_mci_probe);
-}
-
-static void __exit at91_mci_exit(void)
-{
-       platform_driver_unregister(&at91_mci_driver);
-}
-
-module_init(at91_mci_init);
-module_exit(at91_mci_exit);
-
-MODULE_DESCRIPTION("AT91 Multimedia Card Interface driver");
-MODULE_AUTHOR("Nick Randell");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:at91_mci");
diff --git a/drivers/mmc/host/at91_mci.h b/drivers/mmc/host/at91_mci.h
deleted file mode 100644 (file)
index eec3a6b..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * drivers/mmc/host/at91_mci.h
- *
- * Copyright (C) 2005 Ivan Kokshaysky
- * Copyright (C) SAN People
- *
- * MultiMedia Card Interface (MCI) registers.
- * Based on AT91RM9200 datasheet revision F.
- *
- * 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.
- */
-
-#ifndef AT91_MCI_H
-#define AT91_MCI_H
-
-#define AT91_MCI_CR            0x00            /* Control Register */
-#define                AT91_MCI_MCIEN          (1 <<  0)       /* Multi-Media Interface Enable */
-#define                AT91_MCI_MCIDIS         (1 <<  1)       /* Multi-Media Interface Disable */
-#define                AT91_MCI_PWSEN          (1 <<  2)       /* Power Save Mode Enable */
-#define                AT91_MCI_PWSDIS         (1 <<  3)       /* Power Save Mode Disable */
-#define                AT91_MCI_SWRST          (1 <<  7)       /* Software Reset */
-
-#define AT91_MCI_MR            0x04            /* Mode Register */
-#define                AT91_MCI_CLKDIV         (0xff  <<  0)   /* Clock Divider */
-#define                AT91_MCI_PWSDIV         (7     <<  8)   /* Power Saving Divider */
-#define                AT91_MCI_RDPROOF        (1     << 11)   /* Read Proof Enable [SAM926[03] only] */
-#define                AT91_MCI_WRPROOF        (1     << 12)   /* Write Proof Enable [SAM926[03] only] */
-#define                AT91_MCI_PDCFBYTE       (1     << 13)   /* PDC Force Byte Transfer [SAM926[03] only] */
-#define                AT91_MCI_PDCPADV        (1     << 14)   /* PDC Padding Value */
-#define                AT91_MCI_PDCMODE        (1     << 15)   /* PDC-orientated Mode */
-#define                AT91_MCI_BLKLEN         (0xfff << 18)   /* Data Block Length */
-
-#define AT91_MCI_DTOR          0x08            /* Data Timeout Register */
-#define                AT91_MCI_DTOCYC         (0xf << 0)      /* Data Timeout Cycle Number */
-#define                AT91_MCI_DTOMUL         (7   << 4)      /* Data Timeout Multiplier */
-#define                AT91_MCI_DTOMUL_1               (0 <<  4)
-#define                AT91_MCI_DTOMUL_16              (1 <<  4)
-#define                AT91_MCI_DTOMUL_128             (2 <<  4)
-#define                AT91_MCI_DTOMUL_256             (3 <<  4)
-#define                AT91_MCI_DTOMUL_1K              (4 <<  4)
-#define                AT91_MCI_DTOMUL_4K              (5 <<  4)
-#define                AT91_MCI_DTOMUL_64K             (6 <<  4)
-#define                AT91_MCI_DTOMUL_1M              (7 <<  4)
-
-#define AT91_MCI_SDCR          0x0c            /* SD Card Register */
-#define                AT91_MCI_SDCSEL         (3 << 0)        /* SD Card Selector */
-#define                AT91_MCI_SDCBUS         (1 << 7)        /* 1-bit or 4-bit bus */
-
-#define AT91_MCI_ARGR          0x10            /* Argument Register */
-
-#define AT91_MCI_CMDR          0x14            /* Command Register */
-#define                AT91_MCI_CMDNB          (0x3f << 0)     /* Command Number */
-#define                AT91_MCI_RSPTYP         (3    << 6)     /* Response Type */
-#define                        AT91_MCI_RSPTYP_NONE    (0 <<  6)
-#define                        AT91_MCI_RSPTYP_48      (1 <<  6)
-#define                        AT91_MCI_RSPTYP_136     (2 <<  6)
-#define                AT91_MCI_SPCMD          (7    << 8)     /* Special Command */
-#define                        AT91_MCI_SPCMD_NONE     (0 <<  8)
-#define                        AT91_MCI_SPCMD_INIT     (1 <<  8)
-#define                        AT91_MCI_SPCMD_SYNC     (2 <<  8)
-#define                        AT91_MCI_SPCMD_ICMD     (4 <<  8)
-#define                        AT91_MCI_SPCMD_IRESP    (5 <<  8)
-#define                AT91_MCI_OPDCMD         (1 << 11)       /* Open Drain Command */
-#define                AT91_MCI_MAXLAT         (1 << 12)       /* Max Latency for Command to Response */
-#define                AT91_MCI_TRCMD          (3 << 16)       /* Transfer Command */
-#define                        AT91_MCI_TRCMD_NONE     (0 << 16)
-#define                        AT91_MCI_TRCMD_START    (1 << 16)
-#define                        AT91_MCI_TRCMD_STOP     (2 << 16)
-#define                AT91_MCI_TRDIR          (1 << 18)       /* Transfer Direction */
-#define                AT91_MCI_TRTYP          (3 << 19)       /* Transfer Type */
-#define                        AT91_MCI_TRTYP_BLOCK    (0 << 19)
-#define                        AT91_MCI_TRTYP_MULTIPLE (1 << 19)
-#define                        AT91_MCI_TRTYP_STREAM   (2 << 19)
-#define                        AT91_MCI_TRTYP_SDIO_BYTE        (4 << 19)
-#define                        AT91_MCI_TRTYP_SDIO_BLOCK       (5 << 19)
-
-#define AT91_MCI_BLKR          0x18            /* Block Register */
-#define                AT91_MCI_BLKR_BCNT(n)   ((0xffff & (n)) << 0)   /* Block count */
-#define                AT91_MCI_BLKR_BLKLEN(n) ((0xffff & (n)) << 16)  /* Block length */
-
-#define AT91_MCI_RSPR(n)       (0x20 + ((n) * 4))      /* Response Registers 0-3 */
-#define AT91_MCR_RDR           0x30            /* Receive Data Register */
-#define AT91_MCR_TDR           0x34            /* Transmit Data Register */
-
-#define AT91_MCI_SR            0x40            /* Status Register */
-#define                AT91_MCI_CMDRDY         (1 <<  0)       /* Command Ready */
-#define                AT91_MCI_RXRDY          (1 <<  1)       /* Receiver Ready */
-#define                AT91_MCI_TXRDY          (1 <<  2)       /* Transmit Ready */
-#define                AT91_MCI_BLKE           (1 <<  3)       /* Data Block Ended */
-#define                AT91_MCI_DTIP           (1 <<  4)       /* Data Transfer in Progress */
-#define                AT91_MCI_NOTBUSY        (1 <<  5)       /* Data Not Busy */
-#define                AT91_MCI_ENDRX          (1 <<  6)       /* End of RX Buffer */
-#define                AT91_MCI_ENDTX          (1 <<  7)       /* End fo TX Buffer */
-#define                AT91_MCI_SDIOIRQA       (1 <<  8)       /* SDIO Interrupt for Slot A */
-#define                AT91_MCI_SDIOIRQB       (1 <<  9)       /* SDIO Interrupt for Slot B */
-#define                AT91_MCI_RXBUFF         (1 << 14)       /* RX Buffer Full */
-#define                AT91_MCI_TXBUFE         (1 << 15)       /* TX Buffer Empty */
-#define                AT91_MCI_RINDE          (1 << 16)       /* Response Index Error */
-#define                AT91_MCI_RDIRE          (1 << 17)       /* Response Direction Error */
-#define                AT91_MCI_RCRCE          (1 << 18)       /* Response CRC Error */
-#define                AT91_MCI_RENDE          (1 << 19)       /* Response End Bit Error */
-#define                AT91_MCI_RTOE           (1 << 20)       /* Response Time-out Error */
-#define                AT91_MCI_DCRCE          (1 << 21)       /* Data CRC Error */
-#define                AT91_MCI_DTOE           (1 << 22)       /* Data Time-out Error */
-#define                AT91_MCI_OVRE           (1 << 30)       /* Overrun */
-#define                AT91_MCI_UNRE           (1 << 31)       /* Underrun */
-
-#define AT91_MCI_IER           0x44            /* Interrupt Enable Register */
-#define AT91_MCI_IDR           0x48            /* Interrupt Disable Register */
-#define AT91_MCI_IMR           0x4c            /* Interrupt Mask Register */
-
-#endif
index edb37e9135ae3741b5bafef61633c2740e01f8f1..53a09cbb2c7c98ce3863d9c18b43a015dc6570ef 100644 (file)
@@ -134,7 +134,7 @@ static struct pci_driver dw_mci_pci_driver = {
        .name           = "dw_mmc_pci",
        .id_table       = dw_mci_pci_id,
        .probe          = dw_mci_pci_probe,
-       .remove         = dw_mci_pci_remove,
+       .remove         = __devexit_p(dw_mci_pci_remove),
        .driver         =       {
                .pm =   &dw_mci_pci_pmops
        },
index 917936bee5d50514103fbe8501a2ee40c0a4db3a..4e133709e33dded047fb6f5d440dfc679635a0c3 100644 (file)
@@ -119,7 +119,8 @@ static const struct of_device_id dw_mci_pltfm_match[] = {
 MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
 
 static struct platform_driver dw_mci_pltfm_driver = {
-       .remove         = __exit_p(dw_mci_pltfm_remove),
+       .probe          = dw_mci_pltfm_probe,
+       .remove         = __devexit_p(dw_mci_pltfm_remove),
        .driver         = {
                .name           = "dw_mmc",
                .of_match_table = of_match_ptr(dw_mci_pltfm_match),
@@ -127,18 +128,7 @@ static struct platform_driver dw_mci_pltfm_driver = {
        },
 };
 
-static int __init dw_mci_init(void)
-{
-       return platform_driver_probe(&dw_mci_pltfm_driver, dw_mci_pltfm_probe);
-}
-
-static void __exit dw_mci_exit(void)
-{
-       platform_driver_unregister(&dw_mci_pltfm_driver);
-}
-
-module_init(dw_mci_init);
-module_exit(dw_mci_exit);
+module_platform_driver(dw_mci_pltfm_driver);
 
 MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
 MODULE_AUTHOR("NXP Semiconductor VietNam");
index c0667c8af2bd7c78502151e0f6e8a2c3f8e148bc..323c5022c2ca10ad23df5a2e77bcaa956e94801c 100644 (file)
@@ -232,7 +232,7 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
 {
        struct mmc_data *data;
        struct dw_mci_slot *slot = mmc_priv(mmc);
-       struct dw_mci_drv_data *drv_data = slot->host->drv_data;
+       const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
        u32 cmdr;
        cmd->error = -EINPROGRESS;
 
@@ -617,13 +617,13 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
                cmd, arg, cmd_status);
 }
 
-static void dw_mci_setup_bus(struct dw_mci_slot *slot)
+static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
 {
        struct dw_mci *host = slot->host;
        u32 div;
        u32 clk_en_a;
 
-       if (slot->clock != host->current_speed) {
+       if (slot->clock != host->current_speed || force_clkinit) {
                div = host->bus_hz / slot->clock;
                if (host->bus_hz % slot->clock && host->bus_hz > slot->clock)
                        /*
@@ -683,9 +683,6 @@ static void __dw_mci_start_request(struct dw_mci *host,
        if (host->pdata->select_slot)
                host->pdata->select_slot(slot->id);
 
-       /* Slot specific timing and width adjustment */
-       dw_mci_setup_bus(slot);
-
        host->cur_slot = slot;
        host->mrq = mrq;
 
@@ -773,22 +770,19 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct dw_mci_slot *slot = mmc_priv(mmc);
-       struct dw_mci_drv_data *drv_data = slot->host->drv_data;
+       const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
        u32 regs;
 
-       /* set default 1 bit mode */
-       slot->ctype = SDMMC_CTYPE_1BIT;
-
        switch (ios->bus_width) {
-       case MMC_BUS_WIDTH_1:
-               slot->ctype = SDMMC_CTYPE_1BIT;
-               break;
        case MMC_BUS_WIDTH_4:
                slot->ctype = SDMMC_CTYPE_4BIT;
                break;
        case MMC_BUS_WIDTH_8:
                slot->ctype = SDMMC_CTYPE_8BIT;
                break;
+       default:
+               /* set default 1 bit mode */
+               slot->ctype = SDMMC_CTYPE_1BIT;
        }
 
        regs = mci_readl(slot->host, UHS_REG);
@@ -812,6 +806,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        if (drv_data && drv_data->set_ios)
                drv_data->set_ios(slot->host, ios);
 
+       /* Slot specific timing and width adjustment */
+       dw_mci_setup_bus(slot, false);
+
        switch (ios->power_mode) {
        case MMC_POWER_UP:
                set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
@@ -1817,7 +1814,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 {
        struct mmc_host *mmc;
        struct dw_mci_slot *slot;
-       struct dw_mci_drv_data *drv_data = host->drv_data;
+       const struct dw_mci_drv_data *drv_data = host->drv_data;
        int ctrl_id, ret;
        u8 bus_width;
 
@@ -1850,6 +1847,9 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
        if (host->pdata->caps)
                mmc->caps = host->pdata->caps;
 
+       if (host->pdata->pm_caps)
+               mmc->pm_caps = host->pdata->pm_caps;
+
        if (host->dev->of_node) {
                ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
                if (ctrl_id < 0)
@@ -1911,7 +1911,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 #endif /* CONFIG_MMC_DW_IDMAC */
        }
 
-       host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
+       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;
@@ -1960,7 +1960,7 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
 static void dw_mci_init_dma(struct dw_mci *host)
 {
        /* Alloc memory for sg translation */
-       host->sg_cpu = dma_alloc_coherent(host->dev, PAGE_SIZE,
+       host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
                                          &host->sg_dma, GFP_KERNEL);
        if (!host->sg_cpu) {
                dev_err(host->dev, "%s: could not alloc DMA memory\n",
@@ -2038,7 +2038,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
        struct dw_mci_board *pdata;
        struct device *dev = host->dev;
        struct device_node *np = dev->of_node;
-       struct dw_mci_drv_data *drv_data = host->drv_data;
+       const struct dw_mci_drv_data *drv_data = host->drv_data;
        int idx, ret;
 
        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
@@ -2072,6 +2072,12 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
                        return ERR_PTR(ret);
        }
 
+       if (of_find_property(np, "keep-power-in-suspend", NULL))
+               pdata->pm_caps |= MMC_PM_KEEP_POWER;
+
+       if (of_find_property(np, "enable-sdio-wakeup", NULL))
+               pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
+
        return pdata;
 }
 
@@ -2084,7 +2090,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
 
 int dw_mci_probe(struct dw_mci *host)
 {
-       struct dw_mci_drv_data *drv_data = host->drv_data;
+       const struct dw_mci_drv_data *drv_data = host->drv_data;
        int width, i, ret = 0;
        u32 fifo_size;
        int init_slots = 0;
@@ -2103,26 +2109,24 @@ int dw_mci_probe(struct dw_mci *host)
                return -ENODEV;
        }
 
-       host->biu_clk = clk_get(host->dev, "biu");
+       host->biu_clk = devm_clk_get(host->dev, "biu");
        if (IS_ERR(host->biu_clk)) {
                dev_dbg(host->dev, "biu clock not available\n");
        } else {
                ret = clk_prepare_enable(host->biu_clk);
                if (ret) {
                        dev_err(host->dev, "failed to enable biu clock\n");
-                       clk_put(host->biu_clk);
                        return ret;
                }
        }
 
-       host->ciu_clk = clk_get(host->dev, "ciu");
+       host->ciu_clk = devm_clk_get(host->dev, "ciu");
        if (IS_ERR(host->ciu_clk)) {
                dev_dbg(host->dev, "ciu clock not available\n");
        } else {
                ret = clk_prepare_enable(host->ciu_clk);
                if (ret) {
                        dev_err(host->dev, "failed to enable ciu clock\n");
-                       clk_put(host->ciu_clk);
                        goto err_clk_biu;
                }
        }
@@ -2224,7 +2228,8 @@ int dw_mci_probe(struct dw_mci *host)
        if (!host->card_workqueue)
                goto err_dmaunmap;
        INIT_WORK(&host->card_work, dw_mci_work_routine_card);
-       ret = request_irq(host->irq, dw_mci_interrupt, host->irq_flags, "dw-mci", host);
+       ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
+                              host->irq_flags, "dw-mci", host);
        if (ret)
                goto err_workqueue;
 
@@ -2262,7 +2267,7 @@ int dw_mci_probe(struct dw_mci *host)
        } else {
                dev_dbg(host->dev, "attempted to initialize %d slots, "
                                        "but failed on all\n", host->num_slots);
-               goto err_init_slot;
+               goto err_workqueue;
        }
 
        /*
@@ -2282,33 +2287,24 @@ int dw_mci_probe(struct dw_mci *host)
 
        return 0;
 
-err_init_slot:
-       free_irq(host->irq, host);
-
 err_workqueue:
        destroy_workqueue(host->card_workqueue);
 
 err_dmaunmap:
        if (host->use_dma && host->dma_ops->exit)
                host->dma_ops->exit(host);
-       dma_free_coherent(host->dev, PAGE_SIZE,
-                         host->sg_cpu, host->sg_dma);
 
-       if (host->vmmc) {
+       if (host->vmmc)
                regulator_disable(host->vmmc);
-               regulator_put(host->vmmc);
-       }
 
 err_clk_ciu:
-       if (!IS_ERR(host->ciu_clk)) {
+       if (!IS_ERR(host->ciu_clk))
                clk_disable_unprepare(host->ciu_clk);
-               clk_put(host->ciu_clk);
-       }
+
 err_clk_biu:
-       if (!IS_ERR(host->biu_clk)) {
+       if (!IS_ERR(host->biu_clk))
                clk_disable_unprepare(host->biu_clk);
-               clk_put(host->biu_clk);
-       }
+
        return ret;
 }
 EXPORT_SYMBOL(dw_mci_probe);
@@ -2330,24 +2326,19 @@ void dw_mci_remove(struct dw_mci *host)
        mci_writel(host, CLKENA, 0);
        mci_writel(host, CLKSRC, 0);
 
-       free_irq(host->irq, host);
        destroy_workqueue(host->card_workqueue);
-       dma_free_coherent(host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
 
        if (host->use_dma && host->dma_ops->exit)
                host->dma_ops->exit(host);
 
-       if (host->vmmc) {
+       if (host->vmmc)
                regulator_disable(host->vmmc);
-               regulator_put(host->vmmc);
-       }
 
        if (!IS_ERR(host->ciu_clk))
                clk_disable_unprepare(host->ciu_clk);
+
        if (!IS_ERR(host->biu_clk))
                clk_disable_unprepare(host->biu_clk);
-       clk_put(host->ciu_clk);
-       clk_put(host->biu_clk);
 }
 EXPORT_SYMBOL(dw_mci_remove);
 
@@ -2411,6 +2402,11 @@ int dw_mci_resume(struct dw_mci *host)
                struct dw_mci_slot *slot = host->slot[i];
                if (!slot)
                        continue;
+               if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) {
+                       dw_mci_set_ios(slot->mmc, &slot->mmc->ios);
+                       dw_mci_setup_bus(slot, true);
+               }
+
                ret = mmc_resume_host(host->slot[i]->mmc);
                if (ret < 0)
                        return ret;
index 6290b7f1ccfec2d56f31675663923e057a1570c8..29e680f193a0a44bce9abd723e5b23c9758df402 100644 (file)
@@ -240,7 +240,7 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
                return 0;
 
        for_each_sg(data->sg, sg, data->sg_len, i) {
-               if (sg->offset & 3 || sg->length & 3) {
+               if (sg->offset & 3 || sg->length & 3 || sg->length < 512) {
                        host->do_dma = 0;
                        return 0;
                }
index 80d1e6d4b0ae2272588b8860f91527d02358dbf4..206fe499ded5b565a21f473291652930aa81a356 100644 (file)
@@ -43,7 +43,6 @@
 #include <linux/module.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/stmp_device.h>
-#include <linux/mmc/mxs-mmc.h>
 #include <linux/spi/mxs-spi.h>
 
 #define DRIVER_NAME    "mxs-mmc"
@@ -593,13 +592,13 @@ static int mxs_mmc_probe(struct platform_device *pdev)
        struct mxs_mmc_host *host;
        struct mmc_host *mmc;
        struct resource *iores, *dmares;
-       struct mxs_mmc_platform_data *pdata;
        struct pinctrl *pinctrl;
        int ret = 0, irq_err, irq_dma;
        dma_cap_mask_t mask;
        struct regulator *reg_vmmc;
        enum of_gpio_flags flags;
        struct mxs_ssp *ssp;
+       u32 bus_width = 0;
 
        iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@@ -682,25 +681,15 @@ static int mxs_mmc_probe(struct platform_device *pdev)
        mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
                    MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL;
 
-       pdata = mmc_dev(host->mmc)->platform_data;
-       if (!pdata) {
-               u32 bus_width = 0;
-               of_property_read_u32(np, "bus-width", &bus_width);
-               if (bus_width == 4)
-                       mmc->caps |= MMC_CAP_4_BIT_DATA;
-               else if (bus_width == 8)
-                       mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
-               host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0,
-                                                       &flags);
-               if (flags & OF_GPIO_ACTIVE_LOW)
-                       host->wp_inverted = 1;
-       } else {
-               if (pdata->flags & SLOTF_8_BIT_CAPABLE)
-                       mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
-               if (pdata->flags & SLOTF_4_BIT_CAPABLE)
-                       mmc->caps |= MMC_CAP_4_BIT_DATA;
-               host->wp_gpio = pdata->wp_gpio;
-       }
+       of_property_read_u32(np, "bus-width", &bus_width);
+       if (bus_width == 4)
+               mmc->caps |= MMC_CAP_4_BIT_DATA;
+       else if (bus_width == 8)
+               mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
+       host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags);
+
+       if (flags & OF_GPIO_ACTIVE_LOW)
+               host->wp_inverted = 1;
 
        mmc->f_min = 400000;
        mmc->f_max = 288000000;
index fedd258cc4ea2effe547f1fc15729f60277d8c33..d0a912fbad3be5da3a01ae5f76524e05247974d2 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/io.h>
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/pm_runtime.h>
 #include <mach/hardware.h>
 #include <plat/mmc.h>
@@ -62,6 +63,7 @@
 
 #define VS18                   (1 << 26)
 #define VS30                   (1 << 25)
+#define HSS                    (1 << 21)
 #define SDVS18                 (0x5 << 9)
 #define SDVS30                 (0x6 << 9)
 #define SDVS33                 (0x7 << 9)
 #define CLKD_SHIFT             6
 #define DTO_MASK               0x000F0000
 #define DTO_SHIFT              16
-#define INT_EN_MASK            0x307F0033
-#define BWR_ENABLE             (1 << 4)
-#define BRR_ENABLE             (1 << 5)
-#define DTO_ENABLE             (1 << 20)
 #define INIT_STREAM            (1 << 1)
 #define DP_SELECT              (1 << 21)
 #define DDIR                   (1 << 4)
-#define DMA_EN                 0x1
+#define DMAE                   0x1
 #define MSBS                   (1 << 5)
 #define BCE                    (1 << 1)
 #define FOUR_BIT               (1 << 1)
+#define HSPE                   (1 << 2)
 #define DDR                    (1 << 19)
 #define DW8                    (1 << 5)
-#define CC                     0x1
-#define TC                     0x02
 #define OD                     0x1
-#define ERR                    (1 << 15)
-#define CMD_TIMEOUT            (1 << 16)
-#define DATA_TIMEOUT           (1 << 20)
-#define CMD_CRC                        (1 << 17)
-#define DATA_CRC               (1 << 21)
-#define CARD_ERR               (1 << 28)
 #define STAT_CLEAR             0xFFFFFFFF
 #define INIT_STREAM_CMD                0x00000000
 #define DUAL_VOLT_OCR_BIT      7
 #define SOFTRESET              (1 << 1)
 #define RESETDONE              (1 << 0)
 
+/* Interrupt masks for IE and ISE register */
+#define CC_EN                  (1 << 0)
+#define TC_EN                  (1 << 1)
+#define BWR_EN                 (1 << 4)
+#define BRR_EN                 (1 << 5)
+#define ERR_EN                 (1 << 15)
+#define CTO_EN                 (1 << 16)
+#define CCRC_EN                        (1 << 17)
+#define CEB_EN                 (1 << 18)
+#define CIE_EN                 (1 << 19)
+#define DTO_EN                 (1 << 20)
+#define DCRC_EN                        (1 << 21)
+#define DEB_EN                 (1 << 22)
+#define CERR_EN                        (1 << 28)
+#define BADA_EN                        (1 << 29)
+
+#define INT_EN_MASK            (BADA_EN | CERR_EN | DEB_EN | DCRC_EN |\
+               DTO_EN | CIE_EN | CEB_EN | CCRC_EN | CTO_EN | \
+               BRR_EN | BWR_EN | TC_EN | CC_EN)
+
 #define MMC_AUTOSUSPEND_DELAY  100
 #define MMC_TIMEOUT_MS         20
 #define OMAP_MMC_MIN_CLOCK     400000
@@ -302,7 +313,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
 
        reg = regulator_get(host->dev, "vmmc");
        if (IS_ERR(reg)) {
-               dev_dbg(host->dev, "vmmc regulator missing\n");
+               dev_err(host->dev, "vmmc regulator missing\n");
                return PTR_ERR(reg);
        } else {
                mmc_slot(host).set_power = omap_hsmmc_set_power;
@@ -455,13 +466,13 @@ static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
        unsigned int irq_mask;
 
        if (host->use_dma)
-               irq_mask = INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE);
+               irq_mask = INT_EN_MASK & ~(BRR_EN | BWR_EN);
        else
                irq_mask = INT_EN_MASK;
 
        /* Disable timeout for erases */
        if (cmd->opcode == MMC_ERASE)
-               irq_mask &= ~DTO_ENABLE;
+               irq_mask &= ~DTO_EN;
 
        OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
        OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
@@ -494,6 +505,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
        struct mmc_ios *ios = &host->mmc->ios;
        unsigned long regval;
        unsigned long timeout;
+       unsigned long clkdiv;
 
        dev_vdbg(mmc_dev(host->mmc), "Set clock to %uHz\n", ios->clock);
 
@@ -501,7 +513,8 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
 
        regval = OMAP_HSMMC_READ(host->base, SYSCTL);
        regval = regval & ~(CLKD_MASK | DTO_MASK);
-       regval = regval | (calc_divisor(host, ios) << 6) | (DTO << 16);
+       clkdiv = calc_divisor(host, ios);
+       regval = regval | (clkdiv << 6) | (DTO << 16);
        OMAP_HSMMC_WRITE(host->base, SYSCTL, regval);
        OMAP_HSMMC_WRITE(host->base, SYSCTL,
                OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
@@ -512,6 +525,27 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
                && time_before(jiffies, timeout))
                cpu_relax();
 
+       /*
+        * Enable High-Speed Support
+        * Pre-Requisites
+        *      - Controller should support High-Speed-Enable Bit
+        *      - Controller should not be using DDR Mode
+        *      - Controller should advertise that it supports High Speed
+        *        in capabilities register
+        *      - MMC/SD clock coming out of controller > 25MHz
+        */
+       if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) &&
+           (ios->timing != MMC_TIMING_UHS_DDR50) &&
+           ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) {
+               regval = OMAP_HSMMC_READ(host->base, HCTL);
+               if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000)
+                       regval |= HSPE;
+               else
+                       regval &= ~HSPE;
+
+               OMAP_HSMMC_WRITE(host->base, HCTL, regval);
+       }
+
        omap_hsmmc_start_clock(host);
 }
 
@@ -676,8 +710,8 @@ static void send_init_stream(struct omap_hsmmc_host *host)
        OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);
 
        timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
-       while ((reg != CC) && time_before(jiffies, timeout))
-               reg = OMAP_HSMMC_READ(host->base, STAT) & CC;
+       while ((reg != CC_EN) && time_before(jiffies, timeout))
+               reg = OMAP_HSMMC_READ(host->base, STAT) & CC_EN;
 
        OMAP_HSMMC_WRITE(host->base, CON,
                OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM);
@@ -768,7 +802,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
        }
 
        if (host->use_dma)
-               cmdreg |= DMA_EN;
+               cmdreg |= DMAE;
 
        host->req_in_progress = 1;
 
@@ -968,16 +1002,20 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
                        __func__);
 }
 
-static void hsmmc_command_incomplete(struct omap_hsmmc_host *host, int err)
+static void hsmmc_command_incomplete(struct omap_hsmmc_host *host,
+                                       int err, int end_cmd)
 {
-       omap_hsmmc_reset_controller_fsm(host, SRC);
-       host->cmd->error = err;
+       if (end_cmd) {
+               omap_hsmmc_reset_controller_fsm(host, SRC);
+               if (host->cmd)
+                       host->cmd->error = err;
+       }
 
        if (host->data) {
                omap_hsmmc_reset_controller_fsm(host, SRD);
                omap_hsmmc_dma_cleanup(host, err);
-       }
-
+       } else if (host->mrq && host->mrq->cmd)
+               host->mrq->cmd->error = err;
 }
 
 static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
@@ -988,23 +1026,25 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
        data = host->data;
        dev_vdbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
 
-       if (status & ERR) {
+       if (status & ERR_EN) {
                omap_hsmmc_dbg_report_irq(host, status);
-               if (status & (CMD_TIMEOUT | DATA_TIMEOUT))
-                       hsmmc_command_incomplete(host, -ETIMEDOUT);
-               else if (status & (CMD_CRC | DATA_CRC))
-                       hsmmc_command_incomplete(host, -EILSEQ);
 
-               end_cmd = 1;
+               if (status & (CTO_EN | CCRC_EN))
+                       end_cmd = 1;
+               if (status & (CTO_EN | DTO_EN))
+                       hsmmc_command_incomplete(host, -ETIMEDOUT, end_cmd);
+               else if (status & (CCRC_EN | DCRC_EN))
+                       hsmmc_command_incomplete(host, -EILSEQ, end_cmd);
+
                if (host->data || host->response_busy) {
-                       end_trans = 1;
+                       end_trans = !end_cmd;
                        host->response_busy = 0;
                }
        }
 
-       if (end_cmd || ((status & CC) && host->cmd))
+       if (end_cmd || ((status & CC_EN) && host->cmd))
                omap_hsmmc_cmd_done(host, host->cmd);
-       if ((end_trans || (status & TC)) && host->mrq)
+       if ((end_trans || (status & TC_EN)) && host->mrq)
                omap_hsmmc_xfer_done(host, data);
 }
 
@@ -1101,7 +1141,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
 
        return 0;
 err:
-       dev_dbg(mmc_dev(host->mmc), "Unable to switch operating voltage\n");
+       dev_err(mmc_dev(host->mmc), "Unable to switch operating voltage\n");
        return ret;
 }
 
@@ -1360,7 +1400,7 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
        if (host->use_dma) {
                ret = omap_hsmmc_start_dma_transfer(host, req);
                if (ret != 0) {
-                       dev_dbg(mmc_dev(host->mmc), "MMC start dma failure\n");
+                       dev_err(mmc_dev(host->mmc), "MMC start dma failure\n");
                        return ret;
                }
        }
@@ -1678,7 +1718,7 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
 {
        struct omap_mmc_platform_data *pdata;
        struct device_node *np = dev->of_node;
-       u32 bus_width;
+       u32 bus_width, max_freq;
 
        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata)
@@ -1705,6 +1745,12 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
        if (of_find_property(np, "ti,needs-special-reset", NULL))
                pdata->slots[0].features |= HSMMC_HAS_UPDATED_RESET;
 
+       if (!of_property_read_u32(np, "max-frequency", &max_freq))
+               pdata->max_freq = max_freq;
+
+       if (of_find_property(np, "ti,needs-special-hs-handling", NULL))
+               pdata->slots[0].features |= HSMMC_HAS_HSPE_SUPPORT;
+
        return pdata;
 }
 #else
@@ -1725,6 +1771,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
        const struct of_device_id *match;
        dma_cap_mask_t mask;
        unsigned tx_req, rx_req;
+       struct pinctrl *pinctrl;
 
        match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
        if (match) {
@@ -1821,7 +1868,6 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
         * MMC can still work without debounce clock.
         */
        if (IS_ERR(host->dbclk)) {
-               dev_warn(mmc_dev(host->mmc), "Failed to get debounce clk\n");
                host->dbclk = NULL;
        } else if (clk_prepare_enable(host->dbclk) != 0) {
                dev_warn(mmc_dev(host->mmc), "Failed to enable debounce clk\n");
@@ -1889,13 +1935,13 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
        ret = request_irq(host->irq, omap_hsmmc_irq, 0,
                        mmc_hostname(mmc), host);
        if (ret) {
-               dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
+               dev_err(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
                goto err_irq;
        }
 
        if (pdata->init != NULL) {
                if (pdata->init(&pdev->dev) != 0) {
-                       dev_dbg(mmc_dev(host->mmc),
+                       dev_err(mmc_dev(host->mmc),
                                "Unable to configure MMC IRQs\n");
                        goto err_irq_cd_init;
                }
@@ -1918,7 +1964,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
                                           IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
                                           mmc_hostname(mmc), host);
                if (ret) {
-                       dev_dbg(mmc_dev(host->mmc),
+                       dev_err(mmc_dev(host->mmc),
                                "Unable to grab MMC CD IRQ\n");
                        goto err_irq_cd;
                }
@@ -1928,6 +1974,11 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
 
        omap_hsmmc_disable_irq(host);
 
+       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
+       if (IS_ERR(pinctrl))
+               dev_warn(&pdev->dev,
+                       "pins are not configured from the driver\n");
+
        omap_hsmmc_protect_card(host);
 
        mmc_add_host(mmc);
@@ -2027,6 +2078,25 @@ static int __devexit omap_hsmmc_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
+static int omap_hsmmc_prepare(struct device *dev)
+{
+       struct omap_hsmmc_host *host = dev_get_drvdata(dev);
+
+       if (host->pdata->suspend)
+               return host->pdata->suspend(dev, host->slot_id);
+
+       return 0;
+}
+
+static void omap_hsmmc_complete(struct device *dev)
+{
+       struct omap_hsmmc_host *host = dev_get_drvdata(dev);
+
+       if (host->pdata->resume)
+               host->pdata->resume(dev, host->slot_id);
+
+}
+
 static int omap_hsmmc_suspend(struct device *dev)
 {
        int ret = 0;
@@ -2040,23 +2110,10 @@ static int omap_hsmmc_suspend(struct device *dev)
 
        pm_runtime_get_sync(host->dev);
        host->suspended = 1;
-       if (host->pdata->suspend) {
-               ret = host->pdata->suspend(dev, host->slot_id);
-               if (ret) {
-                       dev_dbg(dev, "Unable to handle MMC board"
-                                       " level suspend\n");
-                       host->suspended = 0;
-                       return ret;
-               }
-       }
        ret = mmc_suspend_host(host->mmc);
 
        if (ret) {
                host->suspended = 0;
-               if (host->pdata->resume) {
-                       if (host->pdata->resume(dev, host->slot_id))
-                               dev_dbg(dev, "Unmask interrupt failed\n");
-               }
                goto err;
        }
 
@@ -2093,12 +2150,6 @@ static int omap_hsmmc_resume(struct device *dev)
        if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER))
                omap_hsmmc_conf_bus_power(host);
 
-       if (host->pdata->resume) {
-               ret = host->pdata->resume(dev, host->slot_id);
-               if (ret)
-                       dev_dbg(dev, "Unmask interrupt failed\n");
-       }
-
        omap_hsmmc_protect_card(host);
 
        /* Notify the core to resume the host */
@@ -2114,8 +2165,10 @@ static int omap_hsmmc_resume(struct device *dev)
 }
 
 #else
+#define omap_hsmmc_prepare     NULL
+#define omap_hsmmc_complete    NULL
 #define omap_hsmmc_suspend     NULL
-#define omap_hsmmc_resume              NULL
+#define omap_hsmmc_resume      NULL
 #endif
 
 static int omap_hsmmc_runtime_suspend(struct device *dev)
@@ -2143,6 +2196,8 @@ static int omap_hsmmc_runtime_resume(struct device *dev)
 static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
        .suspend        = omap_hsmmc_suspend,
        .resume         = omap_hsmmc_resume,
+       .prepare        = omap_hsmmc_prepare,
+       .complete       = omap_hsmmc_complete,
        .runtime_suspend = omap_hsmmc_runtime_suspend,
        .runtime_resume = omap_hsmmc_runtime_resume,
 };
index 8fd50a211037126df4a4beea26dd6fc3aaa71c94..e6214480bc98b2bafe58b52b844bb8273182b54a 100644 (file)
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/err.h>
-#include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/err.h>
-#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
 #include <linux/mmc/host.h>
+#include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_gpio.h>
 
 #include "sdhci-pltfm.h"
 
 struct sdhci_dove_priv {
        struct clk *clk;
+       int gpio_cd;
 };
 
+static irqreturn_t sdhci_dove_carddetect_irq(int irq, void *data)
+{
+       struct sdhci_host *host = data;
+
+       tasklet_schedule(&host->card_tasklet);
+       return IRQ_HANDLED;
+}
+
 static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)
 {
        u16 ret;
@@ -50,16 +60,25 @@ static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)
 
 static u32 sdhci_dove_readl(struct sdhci_host *host, int reg)
 {
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_dove_priv *priv = pltfm_host->priv;
        u32 ret;
 
+       ret = readl(host->ioaddr + reg);
+
        switch (reg) {
        case SDHCI_CAPABILITIES:
-               ret = readl(host->ioaddr + reg);
                /* Mask the support for 3.0V */
                ret &= ~SDHCI_CAN_VDD_300;
                break;
-       default:
-               ret = readl(host->ioaddr + reg);
+       case SDHCI_PRESENT_STATE:
+               if (gpio_is_valid(priv->gpio_cd)) {
+                       if (gpio_get_value(priv->gpio_cd) == 0)
+                               ret |= SDHCI_CARD_PRESENT;
+                       else
+                               ret &= ~SDHCI_CARD_PRESENT;
+               }
+               break;
        }
        return ret;
 }
@@ -92,25 +111,70 @@ static int __devinit sdhci_dove_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-       priv->clk = clk_get(&pdev->dev, NULL);
-       if (!IS_ERR(priv->clk))
-               clk_prepare_enable(priv->clk);
+       priv->clk = devm_clk_get(&pdev->dev, NULL);
 
-       ret = sdhci_pltfm_register(pdev, &sdhci_dove_pdata);
-       if (ret)
-               goto sdhci_dove_register_fail;
+       if (pdev->dev.of_node) {
+               priv->gpio_cd = of_get_named_gpio(pdev->dev.of_node,
+                                                 "cd-gpios", 0);
+       } else {
+               priv->gpio_cd = -EINVAL;
+       }
+
+       if (gpio_is_valid(priv->gpio_cd)) {
+               ret = gpio_request(priv->gpio_cd, "sdhci-cd");
+               if (ret) {
+                       dev_err(&pdev->dev, "card detect gpio request failed: %d\n",
+                               ret);
+                       return ret;
+               }
+               gpio_direction_input(priv->gpio_cd);
+       }
+
+       host = sdhci_pltfm_init(pdev, &sdhci_dove_pdata);
+       if (IS_ERR(host)) {
+               ret = PTR_ERR(host);
+               goto err_sdhci_pltfm_init;
+       }
 
-       host = platform_get_drvdata(pdev);
        pltfm_host = sdhci_priv(host);
        pltfm_host->priv = priv;
 
+       if (!IS_ERR(priv->clk))
+               clk_prepare_enable(priv->clk);
+
+       sdhci_get_of_property(pdev);
+
+       ret = sdhci_add_host(host);
+       if (ret)
+               goto err_sdhci_add;
+
+       /*
+        * We must request the IRQ after sdhci_add_host(), as the tasklet only
+        * gets setup in sdhci_add_host() and we oops.
+        */
+       if (gpio_is_valid(priv->gpio_cd)) {
+               ret = request_irq(gpio_to_irq(priv->gpio_cd),
+                                 sdhci_dove_carddetect_irq,
+                                 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+                                 mmc_hostname(host->mmc), host);
+               if (ret) {
+                       dev_err(&pdev->dev, "card detect irq request failed: %d\n",
+                               ret);
+                       goto err_request_irq;
+               }
+       }
+
        return 0;
 
-sdhci_dove_register_fail:
-       if (!IS_ERR(priv->clk)) {
+err_request_irq:
+       sdhci_remove_host(host, 0);
+err_sdhci_add:
+       if (!IS_ERR(priv->clk))
                clk_disable_unprepare(priv->clk);
-               clk_put(priv->clk);
-       }
+       sdhci_pltfm_free(pdev);
+err_sdhci_pltfm_init:
+       if (gpio_is_valid(priv->gpio_cd))
+               gpio_free(priv->gpio_cd);
        return ret;
 }
 
@@ -122,10 +186,14 @@ static int __devexit sdhci_dove_remove(struct platform_device *pdev)
 
        sdhci_pltfm_unregister(pdev);
 
-       if (!IS_ERR(priv->clk)) {
-               clk_disable_unprepare(priv->clk);
-               clk_put(priv->clk);
+       if (gpio_is_valid(priv->gpio_cd)) {
+               free_irq(gpio_to_irq(priv->gpio_cd), host);
+               gpio_free(priv->gpio_cd);
        }
+
+       if (!IS_ERR(priv->clk))
+               clk_disable_unprepare(priv->clk);
+
        return 0;
 }
 
index effc2acfe77838427997078eacab1551af46c416..1849461c39ee62e3b12d444fe88ce8ea1b3e9ba7 100644 (file)
@@ -456,10 +456,10 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
 
        pltfm_host = sdhci_priv(host);
 
-       imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
+       imx_data = devm_kzalloc(&pdev->dev, sizeof(*imx_data), GFP_KERNEL);
        if (!imx_data) {
                err = -ENOMEM;
-               goto err_imx_data;
+               goto free_sdhci;
        }
 
        if (of_id)
@@ -470,19 +470,19 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
        imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
        if (IS_ERR(imx_data->clk_ipg)) {
                err = PTR_ERR(imx_data->clk_ipg);
-               goto err_clk_get;
+               goto free_sdhci;
        }
 
        imx_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
        if (IS_ERR(imx_data->clk_ahb)) {
                err = PTR_ERR(imx_data->clk_ahb);
-               goto err_clk_get;
+               goto free_sdhci;
        }
 
        imx_data->clk_per = devm_clk_get(&pdev->dev, "per");
        if (IS_ERR(imx_data->clk_per)) {
                err = PTR_ERR(imx_data->clk_per);
-               goto err_clk_get;
+               goto free_sdhci;
        }
 
        pltfm_host->clk = imx_data->clk_per;
@@ -494,7 +494,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
        imx_data->pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
        if (IS_ERR(imx_data->pinctrl)) {
                err = PTR_ERR(imx_data->pinctrl);
-               goto pin_err;
+               goto disable_clk;
        }
 
        host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
@@ -519,7 +519,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
                if (!host->mmc->parent->platform_data) {
                        dev_err(mmc_dev(host->mmc), "no board data!\n");
                        err = -EINVAL;
-                       goto no_board_data;
+                       goto disable_clk;
                }
                imx_data->boarddata = *((struct esdhc_platform_data *)
                                        host->mmc->parent->platform_data);
@@ -527,7 +527,8 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
 
        /* write_protect */
        if (boarddata->wp_type == ESDHC_WP_GPIO) {
-               err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP");
+               err = devm_gpio_request_one(&pdev->dev, boarddata->wp_gpio,
+                                           GPIOF_IN, "ESDHC_WP");
                if (err) {
                        dev_warn(mmc_dev(host->mmc),
                                 "no write-protect pin available!\n");
@@ -543,19 +544,21 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
 
        switch (boarddata->cd_type) {
        case ESDHC_CD_GPIO:
-               err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD");
+               err = devm_gpio_request_one(&pdev->dev, boarddata->cd_gpio,
+                                           GPIOF_IN, "ESDHC_CD");
                if (err) {
                        dev_err(mmc_dev(host->mmc),
                                "no card-detect pin available!\n");
-                       goto no_card_detect_pin;
+                       goto disable_clk;
                }
 
-               err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq,
+               err = devm_request_irq(&pdev->dev,
+                                gpio_to_irq(boarddata->cd_gpio), cd_irq,
                                 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
                                 mmc_hostname(host->mmc), host);
                if (err) {
                        dev_err(mmc_dev(host->mmc), "request irq error\n");
-                       goto no_card_detect_irq;
+                       goto disable_clk;
                }
                /* fall through */
 
@@ -574,27 +577,15 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
 
        err = sdhci_add_host(host);
        if (err)
-               goto err_add_host;
+               goto disable_clk;
 
        return 0;
 
-err_add_host:
-       if (gpio_is_valid(boarddata->cd_gpio))
-               free_irq(gpio_to_irq(boarddata->cd_gpio), host);
-no_card_detect_irq:
-       if (gpio_is_valid(boarddata->cd_gpio))
-               gpio_free(boarddata->cd_gpio);
-       if (gpio_is_valid(boarddata->wp_gpio))
-               gpio_free(boarddata->wp_gpio);
-no_card_detect_pin:
-no_board_data:
-pin_err:
+disable_clk:
        clk_disable_unprepare(imx_data->clk_per);
        clk_disable_unprepare(imx_data->clk_ipg);
        clk_disable_unprepare(imx_data->clk_ahb);
-err_clk_get:
-       kfree(imx_data);
-err_imx_data:
+free_sdhci:
        sdhci_pltfm_free(pdev);
        return err;
 }
@@ -604,25 +595,14 @@ static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
        struct sdhci_host *host = platform_get_drvdata(pdev);
        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;
        int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
 
        sdhci_remove_host(host, dead);
 
-       if (gpio_is_valid(boarddata->wp_gpio))
-               gpio_free(boarddata->wp_gpio);
-
-       if (gpio_is_valid(boarddata->cd_gpio)) {
-               free_irq(gpio_to_irq(boarddata->cd_gpio), host);
-               gpio_free(boarddata->cd_gpio);
-       }
-
        clk_disable_unprepare(imx_data->clk_per);
        clk_disable_unprepare(imx_data->clk_ipg);
        clk_disable_unprepare(imx_data->clk_ahb);
 
-       kfree(imx_data);
-
        sdhci_pltfm_free(pdev);
 
        return 0;
index 63d219f57caebcd3a4cd0216ec17aca2500cb257..60de2eeb39b12854adb3dd5184d56babfb9cc391 100644 (file)
@@ -22,6 +22,7 @@
 #include "sdhci-esdhc.h"
 
 #define VENDOR_V_22    0x12
+#define VENDOR_V_23    0x13
 static u32 esdhc_readl(struct sdhci_host *host, int reg)
 {
        u32 ret;
@@ -85,6 +86,18 @@ static u8 esdhc_readb(struct sdhci_host *host, int reg)
        return ret;
 }
 
+static void esdhc_writel(struct sdhci_host *host, u32 val, int reg)
+{
+       /*
+        * Enable IRQSTATEN[BGESEN] is just to set IRQSTAT[BGE]
+        * when SYSCTL[RSTD]) is set for some special operations.
+        * No any impact other operation.
+        */
+       if (reg == SDHCI_INT_ENABLE)
+               val |= SDHCI_INT_BLK_GAP;
+       sdhci_be32bs_writel(host, val, reg);
+}
+
 static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
 {
        if (reg == SDHCI_BLOCK_SIZE) {
@@ -121,6 +134,41 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
        sdhci_be32bs_writeb(host, val, reg);
 }
 
+/*
+ * For Abort or Suspend after Stop at Block Gap, ignore the ADMA
+ * error(IRQSTAT[ADMAE]) if both Transfer Complete(IRQSTAT[TC])
+ * and Block Gap Event(IRQSTAT[BGE]) are also set.
+ * For Continue, apply soft reset for data(SYSCTL[RSTD]);
+ * and re-issue the entire read transaction from beginning.
+ */
+static void esdhci_of_adma_workaround(struct sdhci_host *host, u32 intmask)
+{
+       u32 tmp;
+       bool applicable;
+       dma_addr_t dmastart;
+       dma_addr_t dmanow;
+
+       tmp = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
+       tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
+
+       applicable = (intmask & SDHCI_INT_DATA_END) &&
+               (intmask & SDHCI_INT_BLK_GAP) &&
+               (tmp == VENDOR_V_23);
+       if (!applicable)
+               return;
+
+       host->data->error = 0;
+       dmastart = sg_dma_address(host->data->sg);
+       dmanow = dmastart + host->data->bytes_xfered;
+       /*
+        * Force update to the next DMA block boundary.
+        */
+       dmanow = (dmanow & ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
+               SDHCI_DEFAULT_BOUNDARY_SIZE;
+       host->data->bytes_xfered = dmanow - dmastart;
+       sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
+}
+
 static int esdhc_of_enable_dma(struct sdhci_host *host)
 {
        setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
@@ -177,13 +225,16 @@ static void esdhc_of_platform_init(struct sdhci_host *host)
        vvn = (vvn & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
        if (vvn == VENDOR_V_22)
                host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;
+
+       if (vvn > VENDOR_V_22)
+               host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
 }
 
 static struct sdhci_ops sdhci_esdhc_ops = {
        .read_l = esdhc_readl,
        .read_w = esdhc_readw,
        .read_b = esdhc_readb,
-       .write_l = sdhci_be32bs_writel,
+       .write_l = esdhc_writel,
        .write_w = esdhc_writew,
        .write_b = esdhc_writeb,
        .set_clock = esdhc_of_set_clock,
@@ -195,6 +246,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
        .platform_suspend = esdhc_of_suspend,
        .platform_resume = esdhc_of_resume,
 #endif
+       .adma_workaround = esdhci_of_adma_workaround,
 };
 
 static struct sdhci_pltfm_data sdhci_esdhc_pdata = {
index 04936f353ced53461a35545b22add0460c582d3a..0777fad997ba4b3951dff5ffad6af73e75577574 100644 (file)
@@ -114,6 +114,7 @@ static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot)
 
                SDHCI_TIMEOUT_CLK_UNIT |
                SDHCI_CAN_VDD_330 |
+               SDHCI_CAN_DO_HISPD |
                SDHCI_CAN_DO_SDMA;
        return 0;
 }
index 27164457f861dce37da3e12b00b399bf81b00e1e..d4283ef5917ac6d0912244c802bccf5c81ea35dd 100644 (file)
@@ -78,6 +78,9 @@ void sdhci_get_of_property(struct platform_device *pdev)
                if (of_get_property(np, "broken-cd", NULL))
                        host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
 
+               if (of_get_property(np, "no-1-8-v", NULL))
+                       host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
+
                if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc"))
                        host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
 
@@ -89,6 +92,12 @@ void sdhci_get_of_property(struct platform_device *pdev)
                clk = of_get_property(np, "clock-frequency", &size);
                if (clk && size == sizeof(*clk) && *clk)
                        pltfm_host->clock = be32_to_cpup(clk);
+
+               if (of_find_property(np, "keep-power-in-suspend", NULL))
+                       host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
+
+               if (of_find_property(np, "enable-sdio-wakeup", NULL))
+                       host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
        }
 }
 #else
index e918a2bb3af1aa99a0f51f97ce0c10f1bd33b3dd..60829c92bcfd1c04b7e582899ff2163a02da0225 100644 (file)
@@ -163,10 +163,18 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
        return 0;
 }
 
+static u32 pxav3_get_max_clock(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+       return clk_get_rate(pltfm_host->clk);
+}
+
 static struct sdhci_ops pxav3_sdhci_ops = {
        .platform_reset_exit = pxav3_set_private_registers,
        .set_uhs_signaling = pxav3_set_uhs_signaling,
        .platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
+       .get_max_clock = pxav3_get_max_clock,
 };
 
 #ifdef CONFIG_OF
@@ -249,7 +257,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
 
        host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
                | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
-               | SDHCI_QUIRK_32BIT_ADMA_SIZE;
+               | SDHCI_QUIRK_32BIT_ADMA_SIZE
+               | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
 
        /* enable 1/8V DDR capable */
        host->mmc->caps |= MMC_CAP_1_8V_DDR;
@@ -271,6 +280,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
 
                if (pdata->quirks)
                        host->quirks |= pdata->quirks;
+               if (pdata->quirks2)
+                       host->quirks2 |= pdata->quirks2;
                if (pdata->host_caps)
                        host->mmc->caps |= pdata->host_caps;
                if (pdata->host_caps2)
index c9ec725884e5cbe6b841a2008241fc8b20db2d8d..82b7a7ad42172b28f50e7d509ad1eeb174c33ccb 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/of_gpio.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
+#include <linux/pinctrl/consumer.h>
 
 #include <linux/mmc/host.h>
 
@@ -57,6 +58,7 @@ struct sdhci_s3c {
        int                     ext_cd_irq;
        int                     ext_cd_gpio;
        int                     *gpios;
+       struct pinctrl          *pctrl;
 
        struct clk              *clk_io;
        struct clk              *clk_bus[MAX_BUS_CLK];
@@ -373,7 +375,9 @@ static struct sdhci_ops sdhci_s3c_ops = {
 static void sdhci_s3c_notify_change(struct platform_device *dev, int state)
 {
        struct sdhci_host *host = platform_get_drvdata(dev);
+#ifdef CONFIG_PM_RUNTIME
        struct sdhci_s3c *sc = sdhci_priv(host);
+#endif
        unsigned long flags;
 
        if (host) {
@@ -413,7 +417,7 @@ static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc)
        struct s3c_sdhci_platdata *pdata = sc->pdata;
        struct device *dev = &sc->pdev->dev;
 
-       if (gpio_request(pdata->ext_cd_gpio, "SDHCI EXT CD") == 0) {
+       if (devm_gpio_request(dev, pdata->ext_cd_gpio, "SDHCI EXT CD") == 0) {
                sc->ext_cd_gpio = pdata->ext_cd_gpio;
                sc->ext_cd_irq = gpio_to_irq(pdata->ext_cd_gpio);
                if (sc->ext_cd_irq &&
@@ -456,12 +460,12 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
                return -ENOMEM;
 
        /* get the card detection method */
-       if (of_get_property(node, "broken-cd", 0)) {
+       if (of_get_property(node, "broken-cd", NULL)) {
                pdata->cd_type = S3C_SDHCI_CD_NONE;
                goto setup_bus;
        }
 
-       if (of_get_property(node, "non-removable", 0)) {
+       if (of_get_property(node, "non-removable", NULL)) {
                pdata->cd_type = S3C_SDHCI_CD_PERMANENT;
                goto setup_bus;
        }
@@ -484,8 +488,9 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
                return -EINVAL;
        }
 
-       dev_info(dev, "assuming no card detect line available\n");
-       pdata->cd_type = S3C_SDHCI_CD_NONE;
+       /* assuming internal card detect that will be configured by pinctrl */
+       pdata->cd_type = S3C_SDHCI_CD_INTERNAL;
+       goto setup_bus;
 
  found_cd:
        if (pdata->cd_type == S3C_SDHCI_CD_GPIO) {
@@ -494,7 +499,7 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
                if (of_get_property(node, "cd-inverted", NULL))
                        pdata->ext_cd_gpio_invert = 1;
        } else if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
-               ret = gpio_request(gpio, "sdhci-cd");
+               ret = devm_gpio_request(dev, gpio, "sdhci-cd");
                if (ret) {
                        dev_err(dev, "card detect gpio request failed\n");
                        return -EINVAL;
@@ -503,33 +508,28 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
        }
 
  setup_bus:
+       if (!IS_ERR(ourhost->pctrl))
+               return 0;
+
        /* get the gpios for command, clock and data lines */
        for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) {
                gpio = of_get_gpio(node, cnt);
                if (!gpio_is_valid(gpio)) {
                        dev_err(dev, "invalid gpio[%d]\n", cnt);
-                       goto err_free_dt_cd_gpio;
+                       return -EINVAL;
                }
                ourhost->gpios[cnt] = gpio;
        }
 
        for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) {
-               ret = gpio_request(ourhost->gpios[cnt], "sdhci-gpio");
+               ret = devm_gpio_request(dev, ourhost->gpios[cnt], "sdhci-gpio");
                if (ret) {
                        dev_err(dev, "gpio[%d] request failed\n", cnt);
-                       goto err_free_dt_gpios;
+                       return -EINVAL;
                }
        }
 
        return 0;
-
- err_free_dt_gpios:
-       while (--cnt >= 0)
-               gpio_free(ourhost->gpios[cnt]);
- err_free_dt_cd_gpio:
-       if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL)
-               gpio_free(ourhost->ext_cd_gpio);
-       return -EINVAL;
 }
 #else
 static int __devinit sdhci_s3c_parse_dt(struct device *dev,
@@ -586,13 +586,15 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata) {
                ret = -ENOMEM;
-               goto err_pdata;
+               goto err_pdata_io_clk;
        }
 
+       sc->pctrl = devm_pinctrl_get_select_default(&pdev->dev);
+
        if (pdev->dev.of_node) {
                ret = sdhci_s3c_parse_dt(&pdev->dev, host, pdata);
                if (ret)
-                       goto err_pdata;
+                       goto err_pdata_io_clk;
        } else {
                memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));
                sc->ext_cd_gpio = -1; /* invalid gpio number */
@@ -610,7 +612,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
        if (IS_ERR(sc->clk_io)) {
                dev_err(dev, "failed to get io clock\n");
                ret = PTR_ERR(sc->clk_io);
-               goto err_io_clk;
+               goto err_pdata_io_clk;
        }
 
        /* enable the local io clock and keep it running for the moment. */
@@ -773,13 +775,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
        clk_disable_unprepare(sc->clk_io);
        clk_put(sc->clk_io);
 
- err_io_clk:
-       for (ptr = 0; ptr < NUM_GPIOS(sc->pdata->max_width); ptr++)
-               gpio_free(sc->gpios[ptr]);
-       if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL)
-               gpio_free(sc->ext_cd_gpio);
-
- err_pdata:
+ err_pdata_io_clk:
        sdhci_free_host(host);
 
        return ret;
@@ -798,9 +794,6 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
        if (sc->ext_cd_irq)
                free_irq(sc->ext_cd_irq, sc);
 
-       if (gpio_is_valid(sc->ext_cd_gpio))
-               gpio_free(sc->ext_cd_gpio);
-
 #ifdef CONFIG_PM_RUNTIME
        if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL)
                clk_prepare_enable(sc->clk_io);
@@ -821,11 +814,6 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
        clk_disable_unprepare(sc->clk_io);
        clk_put(sc->clk_io);
 
-       if (pdev->dev.of_node) {
-               for (ptr = 0; ptr < NUM_GPIOS(sc->pdata->max_width); ptr++)
-                       gpio_free(sc->gpios[ptr]);
-       }
-
        sdhci_free_host(host);
        platform_set_drvdata(pdev, NULL);
 
index 6be89c032debe32f16ad978730b70695a2512aab..87a700944b7d618968d1f5ded0967483cd03f144 100644 (file)
@@ -146,6 +146,11 @@ static int __devinit sdhci_probe(struct platform_device *pdev)
                goto put_clk;
        }
 
+       ret = clk_set_rate(sdhci->clk, 50000000);
+       if (ret)
+               dev_dbg(&pdev->dev, "Error setting desired clk, clk=%lu\n",
+                               clk_get_rate(sdhci->clk));
+
        if (np) {
                sdhci->data = sdhci_probe_config_dt(pdev);
                if (IS_ERR(sdhci->data)) {
@@ -297,7 +302,7 @@ static int sdhci_suspend(struct device *dev)
 
        ret = sdhci_suspend_host(host);
        if (!ret)
-               clk_disable_unprepare(sdhci->clk);
+               clk_disable(sdhci->clk);
 
        return ret;
 }
@@ -308,7 +313,7 @@ static int sdhci_resume(struct device *dev)
        struct spear_sdhci *sdhci = dev_get_platdata(dev);
        int ret;
 
-       ret = clk_prepare_enable(sdhci->clk);
+       ret = clk_enable(sdhci->clk);
        if (ret) {
                dev_dbg(dev, "Resume: Error enabling clock\n");
                return ret;
index c7851c0aabce52226d118d50bbe95fe61b4094c2..6f0bfc0c8c9ca96479165dfc6918228f63a9c9ce 100644 (file)
@@ -1618,7 +1618,7 @@ static int sdhci_do_3_3v_signal_voltage_switch(struct sdhci_host *host,
        sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
        if (host->vqmmc) {
-               ret = regulator_set_voltage(host->vqmmc, 3300000, 3300000);
+               ret = regulator_set_voltage(host->vqmmc, 2700000, 3600000);
                if (ret) {
                        pr_warning("%s: Switching to 3.3V signalling voltage "
                                   " failed\n", mmc_hostname(host->mmc));
@@ -1662,7 +1662,7 @@ static int sdhci_do_1_8v_signal_voltage_switch(struct sdhci_host *host,
                 */
                if (host->vqmmc)
                        ret = regulator_set_voltage(host->vqmmc,
-                               1800000, 1800000);
+                               1700000, 1950000);
                else
                        ret = 0;
 
@@ -1994,30 +1994,11 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable)
        sdhci_runtime_pm_put(host);
 }
 
-static const struct mmc_host_ops sdhci_ops = {
-       .request        = sdhci_request,
-       .set_ios        = sdhci_set_ios,
-       .get_ro         = sdhci_get_ro,
-       .hw_reset       = sdhci_hw_reset,
-       .enable_sdio_irq = sdhci_enable_sdio_irq,
-       .start_signal_voltage_switch    = sdhci_start_signal_voltage_switch,
-       .execute_tuning                 = sdhci_execute_tuning,
-       .enable_preset_value            = sdhci_enable_preset_value,
-};
-
-/*****************************************************************************\
- *                                                                           *
- * Tasklets                                                                  *
- *                                                                           *
-\*****************************************************************************/
-
-static void sdhci_tasklet_card(unsigned long param)
+static void sdhci_card_event(struct mmc_host *mmc)
 {
-       struct sdhci_host *host;
+       struct sdhci_host *host = mmc_priv(mmc);
        unsigned long flags;
 
-       host = (struct sdhci_host*)param;
-
        spin_lock_irqsave(&host->lock, flags);
 
        /* Check host->mrq first in case we are runtime suspended */
@@ -2036,6 +2017,31 @@ static void sdhci_tasklet_card(unsigned long param)
        }
 
        spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static const struct mmc_host_ops sdhci_ops = {
+       .request        = sdhci_request,
+       .set_ios        = sdhci_set_ios,
+       .get_ro         = sdhci_get_ro,
+       .hw_reset       = sdhci_hw_reset,
+       .enable_sdio_irq = sdhci_enable_sdio_irq,
+       .start_signal_voltage_switch    = sdhci_start_signal_voltage_switch,
+       .execute_tuning                 = sdhci_execute_tuning,
+       .enable_preset_value            = sdhci_enable_preset_value,
+       .card_event                     = sdhci_card_event,
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Tasklets                                                                  *
+ *                                                                           *
+\*****************************************************************************/
+
+static void sdhci_tasklet_card(unsigned long param)
+{
+       struct sdhci_host *host = (struct sdhci_host*)param;
+
+       sdhci_card_event(host->mmc);
 
        mmc_detect_change(host->mmc, msecs_to_jiffies(200));
 }
@@ -2282,6 +2288,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
                pr_err("%s: ADMA error\n", mmc_hostname(host->mmc));
                sdhci_show_adma_error(host);
                host->data->error = -EIO;
+               if (host->ops->adma_workaround)
+                       host->ops->adma_workaround(host, intmask);
        }
 
        if (host->data->error)
@@ -2858,10 +2866,16 @@ int sdhci_add_host(struct sdhci_host *host)
                                mmc_hostname(mmc));
                        host->vqmmc = NULL;
                }
-       }
-       else if (regulator_is_supported_voltage(host->vqmmc, 1800000, 1800000))
+       } else {
                regulator_enable(host->vqmmc);
-       else
+               if (!regulator_is_supported_voltage(host->vqmmc, 1700000,
+                       1950000))
+                       caps[1] &= ~(SDHCI_SUPPORT_SDR104 |
+                                       SDHCI_SUPPORT_SDR50 |
+                                       SDHCI_SUPPORT_DDR50);
+       }
+
+       if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V)
                caps[1] &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
                       SDHCI_SUPPORT_DDR50);
 
@@ -2919,21 +2933,18 @@ int sdhci_add_host(struct sdhci_host *host)
                                mmc_hostname(mmc));
                        host->vmmc = NULL;
                }
-       } else
-               regulator_enable(host->vmmc);
+       }
 
 #ifdef CONFIG_REGULATOR
        if (host->vmmc) {
-               ret = regulator_is_supported_voltage(host->vmmc, 3300000,
-                       3300000);
+               ret = regulator_is_supported_voltage(host->vmmc, 2700000,
+                       3600000);
                if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_330)))
                        caps[0] &= ~SDHCI_CAN_VDD_330;
-               ret = regulator_is_supported_voltage(host->vmmc, 3000000,
-                       3000000);
                if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_300)))
                        caps[0] &= ~SDHCI_CAN_VDD_300;
-               ret = regulator_is_supported_voltage(host->vmmc, 1800000,
-                       1800000);
+               ret = regulator_is_supported_voltage(host->vmmc, 1700000,
+                       1950000);
                if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_180)))
                        caps[0] &= ~SDHCI_CAN_VDD_180;
        }
index 71a4a7ed46c5095653ce43e90ffd6754815f98da..a6d69b7bdea2c3ceddb230c8c3366473e7beea45 100644 (file)
 #define SDHCI_SIGNAL_ENABLE    0x38
 #define  SDHCI_INT_RESPONSE    0x00000001
 #define  SDHCI_INT_DATA_END    0x00000002
+#define  SDHCI_INT_BLK_GAP     0x00000004
 #define  SDHCI_INT_DMA_END     0x00000008
 #define  SDHCI_INT_SPACE_AVAIL 0x00000010
 #define  SDHCI_INT_DATA_AVAIL  0x00000020
 #define  SDHCI_INT_DATA_MASK   (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
                SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
                SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
-               SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR)
+               SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \
+               SDHCI_INT_BLK_GAP)
 #define SDHCI_INT_ALL_MASK     ((unsigned int)-1)
 
 #define SDHCI_ACMD12_ERR       0x3C
@@ -278,6 +280,7 @@ struct sdhci_ops {
        void    (*hw_reset)(struct sdhci_host *host);
        void    (*platform_suspend)(struct sdhci_host *host);
        void    (*platform_resume)(struct sdhci_host *host);
+       void    (*adma_workaround)(struct sdhci_host *host, u32 intmask);
        void    (*platform_init)(struct sdhci_host *host);
 };
 
index 7eaee3eeb6b2bffed13af54651e6ad5e19d0b409..ae795233a1d6628cfa05b01b9bf53c4227fa27c8 100644 (file)
@@ -1306,7 +1306,6 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
        struct sh_mmcif_plat_data *pd = pdev->dev.platform_data;
        struct resource *res;
        void __iomem *reg;
-       char clk_name[8];
 
        irq[0] = platform_get_irq(pdev, 0);
        irq[1] = platform_get_irq(pdev, 1);
@@ -1356,11 +1355,10 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        host->power = false;
 
-       snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id);
-       host->hclk = clk_get(&pdev->dev, clk_name);
+       host->hclk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(host->hclk)) {
                ret = PTR_ERR(host->hclk);
-               dev_err(&pdev->dev, "cannot get clock \"%s\": %d\n", clk_name, ret);
+               dev_err(&pdev->dev, "cannot get clock: %d\n", ret);
                goto eclkget;
        }
        ret = sh_mmcif_clk_update(host);
index 0bdc146178dbcee41aa55c1f27754bb36c256d37..d6ff8531fb3568dedd1980195a7bd46a357fa7c6 100644 (file)
@@ -123,7 +123,6 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
        struct tmio_mmc_data *mmc_data;
        struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
        struct tmio_mmc_host *host;
-       char clk_name[8];
        int irq, ret, i = 0;
        bool multiplexed_isr = true;
 
@@ -144,11 +143,10 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
                }
        }
 
-       snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
-       priv->clk = clk_get(&pdev->dev, clk_name);
+       priv->clk = clk_get(&pdev->dev, NULL);
        if (IS_ERR(priv->clk)) {
-               dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
                ret = PTR_ERR(priv->clk);
+               dev_err(&pdev->dev, "cannot get clock: %d\n", ret);
                goto eclkget;
        }
 
@@ -250,7 +248,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
        dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n",
                 mmc_hostname(host->mmc), (unsigned long)
                 (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start),
-                mmc_data->hclk / 1000000);
+                host->mmc->f_max / 1000000);
 
        return ret;
 
index d5655a63eda4909f647185621cfe8837c380398d..cb9f361c03ab2d6f45edcb261b3907bb5bcdb7ec 100644 (file)
@@ -2362,6 +2362,7 @@ error4:
 error1:
        usb_free_urb(command_out_urb);
 error0:
+       usb_put_dev(udev);
        return retval;
 }
 
diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c
new file mode 100644 (file)
index 0000000..5ba4605
--- /dev/null
@@ -0,0 +1,1029 @@
+/*
+ *  WM8505/WM8650 SD/MMC Host Controller
+ *
+ *  Copyright (C) 2010 Tony Prisk
+ *  Copyright (C) 2008 WonderMedia Technologies, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+
+#include <asm/byteorder.h>
+
+
+#define DRIVER_NAME "wmt-sdhc"
+
+
+/* MMC/SD controller registers */
+#define SDMMC_CTLR                     0x00
+#define SDMMC_CMD                      0x01
+#define SDMMC_RSPTYPE                  0x02
+#define SDMMC_ARG                      0x04
+#define SDMMC_BUSMODE                  0x08
+#define SDMMC_BLKLEN                   0x0C
+#define SDMMC_BLKCNT                   0x0E
+#define SDMMC_RSP                      0x10
+#define SDMMC_CBCR                     0x20
+#define SDMMC_INTMASK0                 0x24
+#define SDMMC_INTMASK1                 0x25
+#define SDMMC_STS0                     0x28
+#define SDMMC_STS1                     0x29
+#define SDMMC_STS2                     0x2A
+#define SDMMC_STS3                     0x2B
+#define SDMMC_RSPTIMEOUT               0x2C
+#define SDMMC_CLK                      0x30    /* VT8500 only */
+#define SDMMC_EXTCTRL                  0x34
+#define SDMMC_SBLKLEN                  0x38
+#define SDMMC_DMATIMEOUT               0x3C
+
+
+/* SDMMC_CTLR bit fields */
+#define CTLR_CMD_START                 0x01
+#define CTLR_CMD_WRITE                 0x04
+#define CTLR_FIFO_RESET                        0x08
+
+/* SDMMC_BUSMODE bit fields */
+#define BM_SPI_MODE                    0x01
+#define BM_FOURBIT_MODE                        0x02
+#define BM_EIGHTBIT_MODE               0x04
+#define BM_SD_OFF                      0x10
+#define BM_SPI_CS                      0x20
+#define BM_SD_POWER                    0x40
+#define BM_SOFT_RESET                  0x80
+#define BM_ONEBIT_MASK                 0xFD
+
+/* SDMMC_BLKLEN bit fields */
+#define BLKL_CRCERR_ABORT              0x0800
+#define BLKL_CD_POL_HIGH               0x1000
+#define BLKL_GPI_CD                    0x2000
+#define BLKL_DATA3_CD                  0x4000
+#define BLKL_INT_ENABLE                        0x8000
+
+/* SDMMC_INTMASK0 bit fields */
+#define INT0_MBLK_TRAN_DONE_INT_EN     0x10
+#define INT0_BLK_TRAN_DONE_INT_EN      0x20
+#define INT0_CD_INT_EN                 0x40
+#define INT0_DI_INT_EN                 0x80
+
+/* SDMMC_INTMASK1 bit fields */
+#define INT1_CMD_RES_TRAN_DONE_INT_EN  0x02
+#define INT1_CMD_RES_TOUT_INT_EN       0x04
+#define INT1_MBLK_AUTO_STOP_INT_EN     0x08
+#define INT1_DATA_TOUT_INT_EN          0x10
+#define INT1_RESCRC_ERR_INT_EN         0x20
+#define INT1_RCRC_ERR_INT_EN           0x40
+#define INT1_WCRC_ERR_INT_EN           0x80
+
+/* SDMMC_STS0 bit fields */
+#define STS0_WRITE_PROTECT             0x02
+#define STS0_CD_DATA3                  0x04
+#define STS0_CD_GPI                    0x08
+#define STS0_MBLK_DONE                 0x10
+#define STS0_BLK_DONE                  0x20
+#define STS0_CARD_DETECT               0x40
+#define STS0_DEVICE_INS                        0x80
+
+/* SDMMC_STS1 bit fields */
+#define STS1_SDIO_INT                  0x01
+#define STS1_CMDRSP_DONE               0x02
+#define STS1_RSP_TIMEOUT               0x04
+#define STS1_AUTOSTOP_DONE             0x08
+#define STS1_DATA_TIMEOUT              0x10
+#define STS1_RSP_CRC_ERR               0x20
+#define STS1_RCRC_ERR                  0x40
+#define STS1_WCRC_ERR                  0x80
+
+/* SDMMC_STS2 bit fields */
+#define STS2_CMD_RES_BUSY              0x10
+#define STS2_DATARSP_BUSY              0x20
+#define STS2_DIS_FORCECLK              0x80
+
+
+/* MMC/SD DMA Controller Registers */
+#define SDDMA_GCR                      0x100
+#define SDDMA_IER                      0x104
+#define SDDMA_ISR                      0x108
+#define SDDMA_DESPR                    0x10C
+#define SDDMA_RBR                      0x110
+#define SDDMA_DAR                      0x114
+#define SDDMA_BAR                      0x118
+#define SDDMA_CPR                      0x11C
+#define SDDMA_CCR                      0x120
+
+
+/* SDDMA_GCR bit fields */
+#define DMA_GCR_DMA_EN                 0x00000001
+#define DMA_GCR_SOFT_RESET             0x00000100
+
+/* SDDMA_IER bit fields */
+#define DMA_IER_INT_EN                 0x00000001
+
+/* SDDMA_ISR bit fields */
+#define DMA_ISR_INT_STS                        0x00000001
+
+/* SDDMA_RBR bit fields */
+#define DMA_RBR_FORMAT                 0x40000000
+#define DMA_RBR_END                    0x80000000
+
+/* SDDMA_CCR bit fields */
+#define DMA_CCR_RUN                    0x00000080
+#define DMA_CCR_IF_TO_PERIPHERAL       0x00000000
+#define DMA_CCR_PERIPHERAL_TO_IF       0x00400000
+
+/* SDDMA_CCR event status */
+#define DMA_CCR_EVT_NO_STATUS          0x00000000
+#define DMA_CCR_EVT_UNDERRUN           0x00000001
+#define DMA_CCR_EVT_OVERRUN            0x00000002
+#define DMA_CCR_EVT_DESP_READ          0x00000003
+#define DMA_CCR_EVT_DATA_RW            0x00000004
+#define DMA_CCR_EVT_EARLY_END          0x00000005
+#define DMA_CCR_EVT_SUCCESS            0x0000000F
+
+#define PDMA_READ                      0x00
+#define PDMA_WRITE                     0x01
+
+#define WMT_SD_POWER_OFF               0
+#define WMT_SD_POWER_ON                        1
+
+struct wmt_dma_descriptor {
+       u32 flags;
+       u32 data_buffer_addr;
+       u32 branch_addr;
+       u32 reserved1;
+};
+
+struct wmt_mci_caps {
+       unsigned int    f_min;
+       unsigned int    f_max;
+       u32             ocr_avail;
+       u32             caps;
+       u32             max_seg_size;
+       u32             max_segs;
+       u32             max_blk_size;
+};
+
+struct wmt_mci_priv {
+       struct mmc_host *mmc;
+       void __iomem *sdmmc_base;
+
+       int irq_regular;
+       int irq_dma;
+
+       void *dma_desc_buffer;
+       dma_addr_t dma_desc_device_addr;
+
+       struct completion cmdcomp;
+       struct completion datacomp;
+
+       struct completion *comp_cmd;
+       struct completion *comp_dma;
+
+       struct mmc_request *req;
+       struct mmc_command *cmd;
+
+       struct clk *clk_sdmmc;
+       struct device *dev;
+
+       u8 power_inverted;
+       u8 cd_inverted;
+};
+
+static void wmt_set_sd_power(struct wmt_mci_priv *priv, int enable)
+{
+       u32 reg_tmp;
+       if (enable) {
+               if (priv->power_inverted) {
+                       reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+                       writeb(reg_tmp | BM_SD_OFF,
+                              priv->sdmmc_base + SDMMC_BUSMODE);
+               } else {
+                       reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+                       writeb(reg_tmp & (~BM_SD_OFF),
+                              priv->sdmmc_base + SDMMC_BUSMODE);
+               }
+       } else {
+               if (priv->power_inverted) {
+                       reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+                       writeb(reg_tmp & (~BM_SD_OFF),
+                              priv->sdmmc_base + SDMMC_BUSMODE);
+               } else {
+                       reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+                       writeb(reg_tmp | BM_SD_OFF,
+                              priv->sdmmc_base + SDMMC_BUSMODE);
+               }
+       }
+}
+
+static void wmt_mci_read_response(struct mmc_host *mmc)
+{
+       struct wmt_mci_priv *priv;
+       int idx1, idx2;
+       u8 tmp_resp;
+       u32 response;
+
+       priv = mmc_priv(mmc);
+
+       for (idx1 = 0; idx1 < 4; idx1++) {
+               response = 0;
+               for (idx2 = 0; idx2 < 4; idx2++) {
+                       if ((idx1 == 3) && (idx2 == 3))
+                               tmp_resp = readb(priv->sdmmc_base + SDMMC_RSP);
+                       else
+                               tmp_resp = readb(priv->sdmmc_base + SDMMC_RSP +
+                                                (idx1*4) + idx2 + 1);
+                       response |= (tmp_resp << (idx2 * 8));
+               }
+               priv->cmd->resp[idx1] = cpu_to_be32(response);
+       }
+}
+
+static void wmt_mci_start_command(struct wmt_mci_priv *priv)
+{
+       u32 reg_tmp;
+
+       reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR);
+       writeb(reg_tmp | CTLR_CMD_START, priv->sdmmc_base + SDMMC_CTLR);
+}
+
+static int wmt_mci_send_command(struct mmc_host *mmc, u8 command, u8 cmdtype,
+                               u32 arg, u8 rsptype)
+{
+       struct wmt_mci_priv *priv;
+       u32 reg_tmp;
+
+       priv = mmc_priv(mmc);
+
+       /* write command, arg, resptype registers */
+       writeb(command, priv->sdmmc_base + SDMMC_CMD);
+       writel(arg, priv->sdmmc_base + SDMMC_ARG);
+       writeb(rsptype, priv->sdmmc_base + SDMMC_RSPTYPE);
+
+       /* reset response FIFO */
+       reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR);
+       writeb(reg_tmp | CTLR_FIFO_RESET, priv->sdmmc_base + SDMMC_CTLR);
+
+       /* ensure clock enabled - VT3465 */
+       wmt_set_sd_power(priv, WMT_SD_POWER_ON);
+
+       /* clear status bits */
+       writeb(0xFF, priv->sdmmc_base + SDMMC_STS0);
+       writeb(0xFF, priv->sdmmc_base + SDMMC_STS1);
+       writeb(0xFF, priv->sdmmc_base + SDMMC_STS2);
+       writeb(0xFF, priv->sdmmc_base + SDMMC_STS3);
+
+       /* set command type */
+       reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR);
+       writeb((reg_tmp & 0x0F) | (cmdtype << 4),
+              priv->sdmmc_base + SDMMC_CTLR);
+
+       return 0;
+}
+
+static void wmt_mci_disable_dma(struct wmt_mci_priv *priv)
+{
+       writel(DMA_ISR_INT_STS, priv->sdmmc_base + SDDMA_ISR);
+       writel(0, priv->sdmmc_base + SDDMA_IER);
+}
+
+static void wmt_complete_data_request(struct wmt_mci_priv *priv)
+{
+       struct mmc_request *req;
+       req = priv->req;
+
+       req->data->bytes_xfered = req->data->blksz * req->data->blocks;
+
+       /* unmap the DMA pages used for write data */
+       if (req->data->flags & MMC_DATA_WRITE)
+               dma_unmap_sg(mmc_dev(priv->mmc), req->data->sg,
+                            req->data->sg_len, DMA_TO_DEVICE);
+       else
+               dma_unmap_sg(mmc_dev(priv->mmc), req->data->sg,
+                            req->data->sg_len, DMA_FROM_DEVICE);
+
+       /* Check if the DMA ISR returned a data error */
+       if ((req->cmd->error) || (req->data->error))
+               mmc_request_done(priv->mmc, req);
+       else {
+               wmt_mci_read_response(priv->mmc);
+               if (!req->data->stop) {
+                       /* single-block read/write requests end here */
+                       mmc_request_done(priv->mmc, req);
+               } else {
+                       /*
+                        * we change the priv->cmd variable so the response is
+                        * stored in the stop struct rather than the original
+                        * calling command struct
+                        */
+                       priv->comp_cmd = &priv->cmdcomp;
+                       init_completion(priv->comp_cmd);
+                       priv->cmd = req->data->stop;
+                       wmt_mci_send_command(priv->mmc, req->data->stop->opcode,
+                                            7, req->data->stop->arg, 9);
+                       wmt_mci_start_command(priv);
+               }
+       }
+}
+
+static irqreturn_t wmt_mci_dma_isr(int irq_num, void *data)
+{
+       struct mmc_host *mmc;
+       struct wmt_mci_priv *priv;
+
+       int status;
+
+       priv = (struct wmt_mci_priv *)data;
+       mmc = priv->mmc;
+
+       status = readl(priv->sdmmc_base + SDDMA_CCR) & 0x0F;
+
+       if (status != DMA_CCR_EVT_SUCCESS) {
+               dev_err(priv->dev, "DMA Error: Status = %d\n", status);
+               priv->req->data->error = -ETIMEDOUT;
+               complete(priv->comp_dma);
+               return IRQ_HANDLED;
+       }
+
+       priv->req->data->error = 0;
+
+       wmt_mci_disable_dma(priv);
+
+       complete(priv->comp_dma);
+
+       if (priv->comp_cmd) {
+               if (completion_done(priv->comp_cmd)) {
+                       /*
+                        * if the command (regular) interrupt has already
+                        * completed, finish off the request otherwise we wait
+                        * for the command interrupt and finish from there.
+                        */
+                       wmt_complete_data_request(priv);
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t wmt_mci_regular_isr(int irq_num, void *data)
+{
+       struct wmt_mci_priv *priv;
+       u32 status0;
+       u32 status1;
+       u32 status2;
+       u32 reg_tmp;
+       int cmd_done;
+
+       priv = (struct wmt_mci_priv *)data;
+       cmd_done = 0;
+       status0 = readb(priv->sdmmc_base + SDMMC_STS0);
+       status1 = readb(priv->sdmmc_base + SDMMC_STS1);
+       status2 = readb(priv->sdmmc_base + SDMMC_STS2);
+
+       /* Check for card insertion */
+       reg_tmp = readb(priv->sdmmc_base + SDMMC_INTMASK0);
+       if ((reg_tmp & INT0_DI_INT_EN) && (status0 & STS0_DEVICE_INS)) {
+               mmc_detect_change(priv->mmc, 0);
+               if (priv->cmd)
+                       priv->cmd->error = -ETIMEDOUT;
+               if (priv->comp_cmd)
+                       complete(priv->comp_cmd);
+               if (priv->comp_dma) {
+                       wmt_mci_disable_dma(priv);
+                       complete(priv->comp_dma);
+               }
+               writeb(STS0_DEVICE_INS, priv->sdmmc_base + SDMMC_STS0);
+               return IRQ_HANDLED;
+       }
+
+       if ((!priv->req->data) ||
+           ((priv->req->data->stop) && (priv->cmd == priv->req->data->stop))) {
+               /* handle non-data & stop_transmission requests */
+               if (status1 & STS1_CMDRSP_DONE) {
+                       priv->cmd->error = 0;
+                       cmd_done = 1;
+               } else if ((status1 & STS1_RSP_TIMEOUT) ||
+                          (status1 & STS1_DATA_TIMEOUT)) {
+                       priv->cmd->error = -ETIMEDOUT;
+                       cmd_done = 1;
+               }
+
+               if (cmd_done) {
+                       priv->comp_cmd = NULL;
+
+                       if (!priv->cmd->error)
+                               wmt_mci_read_response(priv->mmc);
+
+                       priv->cmd = NULL;
+
+                       mmc_request_done(priv->mmc, priv->req);
+               }
+       } else {
+               /* handle data requests */
+               if (status1 & STS1_CMDRSP_DONE) {
+                       if (priv->cmd)
+                               priv->cmd->error = 0;
+                       if (priv->comp_cmd)
+                               complete(priv->comp_cmd);
+               }
+
+               if ((status1 & STS1_RSP_TIMEOUT) ||
+                   (status1 & STS1_DATA_TIMEOUT)) {
+                       if (priv->cmd)
+                               priv->cmd->error = -ETIMEDOUT;
+                       if (priv->comp_cmd)
+                               complete(priv->comp_cmd);
+                       if (priv->comp_dma) {
+                               wmt_mci_disable_dma(priv);
+                               complete(priv->comp_dma);
+                       }
+               }
+
+               if (priv->comp_dma) {
+                       /*
+                        * If the dma interrupt has already completed, finish
+                        * off the request; otherwise we wait for the DMA
+                        * interrupt and finish from there.
+                        */
+                       if (completion_done(priv->comp_dma))
+                               wmt_complete_data_request(priv);
+               }
+       }
+
+       writeb(status0, priv->sdmmc_base + SDMMC_STS0);
+       writeb(status1, priv->sdmmc_base + SDMMC_STS1);
+       writeb(status2, priv->sdmmc_base + SDMMC_STS2);
+
+       return IRQ_HANDLED;
+}
+
+static void wmt_reset_hardware(struct mmc_host *mmc)
+{
+       struct wmt_mci_priv *priv;
+       u32 reg_tmp;
+
+       priv = mmc_priv(mmc);
+
+       /* reset controller */
+       reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+       writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + SDMMC_BUSMODE);
+
+       /* reset response FIFO */
+       reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR);
+       writeb(reg_tmp | CTLR_FIFO_RESET, priv->sdmmc_base + SDMMC_CTLR);
+
+       /* enable GPI pin to detect card */
+       writew(BLKL_INT_ENABLE | BLKL_GPI_CD, priv->sdmmc_base + SDMMC_BLKLEN);
+
+       /* clear interrupt status */
+       writeb(0xFF, priv->sdmmc_base + SDMMC_STS0);
+       writeb(0xFF, priv->sdmmc_base + SDMMC_STS1);
+
+       /* setup interrupts */
+       writeb(INT0_CD_INT_EN | INT0_DI_INT_EN, priv->sdmmc_base +
+              SDMMC_INTMASK0);
+       writeb(INT1_DATA_TOUT_INT_EN | INT1_CMD_RES_TRAN_DONE_INT_EN |
+              INT1_CMD_RES_TOUT_INT_EN, priv->sdmmc_base + SDMMC_INTMASK1);
+
+       /* set the DMA timeout */
+       writew(8191, priv->sdmmc_base + SDMMC_DMATIMEOUT);
+
+       /* auto clock freezing enable */
+       reg_tmp = readb(priv->sdmmc_base + SDMMC_STS2);
+       writeb(reg_tmp | STS2_DIS_FORCECLK, priv->sdmmc_base + SDMMC_STS2);
+
+       /* set a default clock speed of 400Khz */
+       clk_set_rate(priv->clk_sdmmc, 400000);
+}
+
+static int wmt_dma_init(struct mmc_host *mmc)
+{
+       struct wmt_mci_priv *priv;
+
+       priv = mmc_priv(mmc);
+
+       writel(DMA_GCR_SOFT_RESET, priv->sdmmc_base + SDDMA_GCR);
+       writel(DMA_GCR_DMA_EN, priv->sdmmc_base + SDDMA_GCR);
+       if ((readl(priv->sdmmc_base + SDDMA_GCR) & DMA_GCR_DMA_EN) != 0)
+               return 0;
+       else
+               return 1;
+}
+
+static void wmt_dma_init_descriptor(struct wmt_dma_descriptor *desc,
+               u16 req_count, u32 buffer_addr, u32 branch_addr, int end)
+{
+       desc->flags = 0x40000000 | req_count;
+       if (end)
+               desc->flags |= 0x80000000;
+       desc->data_buffer_addr = buffer_addr;
+       desc->branch_addr = branch_addr;
+}
+
+static void wmt_dma_config(struct mmc_host *mmc, u32 descaddr, u8 dir)
+{
+       struct wmt_mci_priv *priv;
+       u32 reg_tmp;
+
+       priv = mmc_priv(mmc);
+
+       /* Enable DMA Interrupts */
+       writel(DMA_IER_INT_EN, priv->sdmmc_base + SDDMA_IER);
+
+       /* Write DMA Descriptor Pointer Register */
+       writel(descaddr, priv->sdmmc_base + SDDMA_DESPR);
+
+       writel(0x00, priv->sdmmc_base + SDDMA_CCR);
+
+       if (dir == PDMA_WRITE) {
+               reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR);
+               writel(reg_tmp & DMA_CCR_IF_TO_PERIPHERAL, priv->sdmmc_base +
+                      SDDMA_CCR);
+       } else {
+               reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR);
+               writel(reg_tmp | DMA_CCR_PERIPHERAL_TO_IF, priv->sdmmc_base +
+                      SDDMA_CCR);
+       }
+}
+
+static void wmt_dma_start(struct wmt_mci_priv *priv)
+{
+       u32 reg_tmp;
+
+       reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR);
+       writel(reg_tmp | DMA_CCR_RUN, priv->sdmmc_base + SDDMA_CCR);
+}
+
+static void wmt_mci_request(struct mmc_host *mmc, struct mmc_request *req)
+{
+       struct wmt_mci_priv *priv;
+       struct wmt_dma_descriptor *desc;
+       u8 command;
+       u8 cmdtype;
+       u32 arg;
+       u8 rsptype;
+       u32 reg_tmp;
+
+       struct scatterlist *sg;
+       int i;
+       int sg_cnt;
+       int offset;
+       u32 dma_address;
+       int desc_cnt;
+
+       priv = mmc_priv(mmc);
+       priv->req = req;
+
+       /*
+        * Use the cmd variable to pass a pointer to the resp[] structure
+        * This is required on multi-block requests to pass the pointer to the
+        * stop command
+        */
+       priv->cmd = req->cmd;
+
+       command = req->cmd->opcode;
+       arg = req->cmd->arg;
+       rsptype = mmc_resp_type(req->cmd);
+       cmdtype = 0;
+
+       /* rsptype=7 only valid for SPI commands - should be =2 for SD */
+       if (rsptype == 7)
+               rsptype = 2;
+       /* rsptype=21 is R1B, convert for controller */
+       if (rsptype == 21)
+               rsptype = 9;
+
+       if (!req->data) {
+               wmt_mci_send_command(mmc, command, cmdtype, arg, rsptype);
+               wmt_mci_start_command(priv);
+               /* completion is now handled in the regular_isr() */
+       }
+       if (req->data) {
+               priv->comp_cmd = &priv->cmdcomp;
+               init_completion(priv->comp_cmd);
+
+               wmt_dma_init(mmc);
+
+               /* set controller data length */
+               reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN);
+               writew((reg_tmp & 0xF800) | (req->data->blksz - 1),
+                      priv->sdmmc_base + SDMMC_BLKLEN);
+
+               /* set controller block count */
+               writew(req->data->blocks, priv->sdmmc_base + SDMMC_BLKCNT);
+
+               desc = (struct wmt_dma_descriptor *)priv->dma_desc_buffer;
+
+               if (req->data->flags & MMC_DATA_WRITE) {
+                       sg_cnt = dma_map_sg(mmc_dev(mmc), req->data->sg,
+                                           req->data->sg_len, DMA_TO_DEVICE);
+                       cmdtype = 1;
+                       if (req->data->blocks > 1)
+                               cmdtype = 3;
+               } else {
+                       sg_cnt = dma_map_sg(mmc_dev(mmc), req->data->sg,
+                                           req->data->sg_len, DMA_FROM_DEVICE);
+                       cmdtype = 2;
+                       if (req->data->blocks > 1)
+                               cmdtype = 4;
+               }
+
+               dma_address = priv->dma_desc_device_addr + 16;
+               desc_cnt = 0;
+
+               for_each_sg(req->data->sg, sg, sg_cnt, i) {
+                       offset = 0;
+                       while (offset < sg_dma_len(sg)) {
+                               wmt_dma_init_descriptor(desc, req->data->blksz,
+                                               sg_dma_address(sg)+offset,
+                                               dma_address, 0);
+                               desc++;
+                               desc_cnt++;
+                               offset += req->data->blksz;
+                               dma_address += 16;
+                               if (desc_cnt == req->data->blocks)
+                                       break;
+                       }
+               }
+               desc--;
+               desc->flags |= 0x80000000;
+
+               if (req->data->flags & MMC_DATA_WRITE)
+                       wmt_dma_config(mmc, priv->dma_desc_device_addr,
+                                      PDMA_WRITE);
+               else
+                       wmt_dma_config(mmc, priv->dma_desc_device_addr,
+                                      PDMA_READ);
+
+               wmt_mci_send_command(mmc, command, cmdtype, arg, rsptype);
+
+               priv->comp_dma = &priv->datacomp;
+               init_completion(priv->comp_dma);
+
+               wmt_dma_start(priv);
+               wmt_mci_start_command(priv);
+       }
+}
+
+static void wmt_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct wmt_mci_priv *priv;
+       u32 reg_tmp;
+
+       priv = mmc_priv(mmc);
+
+       if (ios->power_mode == MMC_POWER_UP) {
+               wmt_reset_hardware(mmc);
+
+               wmt_set_sd_power(priv, WMT_SD_POWER_ON);
+       }
+       if (ios->power_mode == MMC_POWER_OFF)
+               wmt_set_sd_power(priv, WMT_SD_POWER_OFF);
+
+       if (ios->clock != 0)
+               clk_set_rate(priv->clk_sdmmc, ios->clock);
+
+       switch (ios->bus_width) {
+       case MMC_BUS_WIDTH_8:
+               reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL);
+               writeb(reg_tmp | 0x04, priv->sdmmc_base + SDMMC_EXTCTRL);
+               break;
+       case MMC_BUS_WIDTH_4:
+               reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+               writeb(reg_tmp | BM_FOURBIT_MODE, priv->sdmmc_base +
+                      SDMMC_BUSMODE);
+
+               reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL);
+               writeb(reg_tmp & 0xFB, priv->sdmmc_base + SDMMC_EXTCTRL);
+               break;
+       case MMC_BUS_WIDTH_1:
+               reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+               writeb(reg_tmp & BM_ONEBIT_MASK, priv->sdmmc_base +
+                      SDMMC_BUSMODE);
+
+               reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL);
+               writeb(reg_tmp & 0xFB, priv->sdmmc_base + SDMMC_EXTCTRL);
+               break;
+       }
+}
+
+static int wmt_mci_get_ro(struct mmc_host *mmc)
+{
+       struct wmt_mci_priv *priv = mmc_priv(mmc);
+
+       return !(readb(priv->sdmmc_base + SDMMC_STS0) & STS0_WRITE_PROTECT);
+}
+
+static int wmt_mci_get_cd(struct mmc_host *mmc)
+{
+       struct wmt_mci_priv *priv = mmc_priv(mmc);
+       u32 cd = (readb(priv->sdmmc_base + SDMMC_STS0) & STS0_CD_GPI) >> 3;
+
+       return !(cd ^ priv->cd_inverted);
+}
+
+static struct mmc_host_ops wmt_mci_ops = {
+       .request = wmt_mci_request,
+       .set_ios = wmt_mci_set_ios,
+       .get_ro = wmt_mci_get_ro,
+       .get_cd = wmt_mci_get_cd,
+};
+
+/* Controller capabilities */
+static struct wmt_mci_caps wm8505_caps = {
+       .f_min = 390425,
+       .f_max = 50000000,
+       .ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34,
+       .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED |
+               MMC_CAP_SD_HIGHSPEED,
+       .max_seg_size = 65024,
+       .max_segs = 128,
+       .max_blk_size = 2048,
+};
+
+static struct of_device_id wmt_mci_dt_ids[] = {
+       { .compatible = "wm,wm8505-sdhc", .data = &wm8505_caps },
+       { /* Sentinel */ },
+};
+
+static int __devinit wmt_mci_probe(struct platform_device *pdev)
+{
+       struct mmc_host *mmc;
+       struct wmt_mci_priv *priv;
+       struct device_node *np = pdev->dev.of_node;
+       const struct of_device_id *of_id =
+               of_match_device(wmt_mci_dt_ids, &pdev->dev);
+       const struct wmt_mci_caps *wmt_caps = of_id->data;
+       int ret;
+       int regular_irq, dma_irq;
+
+       if (!of_id || !of_id->data) {
+               dev_err(&pdev->dev, "Controller capabilities data missing\n");
+               return -EFAULT;
+       }
+
+       if (!np) {
+               dev_err(&pdev->dev, "Missing SDMMC description in devicetree\n");
+               return -EFAULT;
+       }
+
+       regular_irq = irq_of_parse_and_map(np, 0);
+       dma_irq = irq_of_parse_and_map(np, 1);
+
+       if (!regular_irq || !dma_irq) {
+               dev_err(&pdev->dev, "Getting IRQs failed!\n");
+               ret = -ENXIO;
+               goto fail1;
+       }
+
+       mmc = mmc_alloc_host(sizeof(struct wmt_mci_priv), &pdev->dev);
+       if (!mmc) {
+               dev_err(&pdev->dev, "Failed to allocate mmc_host\n");
+               ret = -ENOMEM;
+               goto fail1;
+       }
+
+       mmc->ops = &wmt_mci_ops;
+       mmc->f_min = wmt_caps->f_min;
+       mmc->f_max = wmt_caps->f_max;
+       mmc->ocr_avail = wmt_caps->ocr_avail;
+       mmc->caps = wmt_caps->caps;
+
+       mmc->max_seg_size = wmt_caps->max_seg_size;
+       mmc->max_segs = wmt_caps->max_segs;
+       mmc->max_blk_size = wmt_caps->max_blk_size;
+
+       mmc->max_req_size = (16*512*mmc->max_segs);
+       mmc->max_blk_count = mmc->max_req_size / 512;
+
+       priv = mmc_priv(mmc);
+       priv->mmc = mmc;
+       priv->dev = &pdev->dev;
+
+       priv->power_inverted = 0;
+       priv->cd_inverted = 0;
+
+       if (of_get_property(np, "sdon-inverted", NULL))
+               priv->power_inverted = 1;
+       if (of_get_property(np, "cd-inverted", NULL))
+               priv->cd_inverted = 1;
+
+       priv->sdmmc_base = of_iomap(np, 0);
+       if (!priv->sdmmc_base) {
+               dev_err(&pdev->dev, "Failed to map IO space\n");
+               ret = -ENOMEM;
+               goto fail2;
+       }
+
+       priv->irq_regular = regular_irq;
+       priv->irq_dma = dma_irq;
+
+       ret = request_irq(regular_irq, wmt_mci_regular_isr, 0, "sdmmc", priv);
+       if (ret) {
+               dev_err(&pdev->dev, "Register regular IRQ fail\n");
+               goto fail3;
+       }
+
+       ret = request_irq(dma_irq, wmt_mci_dma_isr, 32, "sdmmc", priv);
+       if (ret) {
+               dev_err(&pdev->dev, "Register DMA IRQ fail\n");
+               goto fail4;
+       }
+
+       /* alloc some DMA buffers for descriptors/transfers */
+       priv->dma_desc_buffer = dma_alloc_coherent(&pdev->dev,
+                                                  mmc->max_blk_count * 16,
+                                                  &priv->dma_desc_device_addr,
+                                                  208);
+       if (!priv->dma_desc_buffer) {
+               dev_err(&pdev->dev, "DMA alloc fail\n");
+               ret = -EPERM;
+               goto fail5;
+       }
+
+       platform_set_drvdata(pdev, mmc);
+
+       priv->clk_sdmmc = of_clk_get(np, 0);
+       if (IS_ERR(priv->clk_sdmmc)) {
+               dev_err(&pdev->dev, "Error getting clock\n");
+               ret = PTR_ERR(priv->clk_sdmmc);
+               goto fail5;
+       }
+
+       clk_prepare_enable(priv->clk_sdmmc);
+
+       /* configure the controller to a known 'ready' state */
+       wmt_reset_hardware(mmc);
+
+       mmc_add_host(mmc);
+
+       dev_info(&pdev->dev, "WMT SDHC Controller initialized\n");
+
+       return 0;
+fail5:
+       free_irq(dma_irq, priv);
+fail4:
+       free_irq(regular_irq, priv);
+fail3:
+       iounmap(priv->sdmmc_base);
+fail2:
+       mmc_free_host(mmc);
+fail1:
+       return ret;
+}
+
+static int __devexit wmt_mci_remove(struct platform_device *pdev)
+{
+       struct mmc_host *mmc;
+       struct wmt_mci_priv *priv;
+       struct resource *res;
+       u32 reg_tmp;
+
+       mmc = platform_get_drvdata(pdev);
+       priv = mmc_priv(mmc);
+
+       /* reset SD controller */
+       reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+       writel(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + SDMMC_BUSMODE);
+       reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN);
+       writew(reg_tmp & ~(0xA000), priv->sdmmc_base + SDMMC_BLKLEN);
+       writeb(0xFF, priv->sdmmc_base + SDMMC_STS0);
+       writeb(0xFF, priv->sdmmc_base + SDMMC_STS1);
+
+       /* release the dma buffers */
+       dma_free_coherent(&pdev->dev, priv->mmc->max_blk_count * 16,
+                         priv->dma_desc_buffer, priv->dma_desc_device_addr);
+
+       mmc_remove_host(mmc);
+
+       free_irq(priv->irq_regular, priv);
+       free_irq(priv->irq_dma, priv);
+
+       iounmap(priv->sdmmc_base);
+
+       clk_disable_unprepare(priv->clk_sdmmc);
+       clk_put(priv->clk_sdmmc);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       release_mem_region(res->start, res->end - res->start + 1);
+
+       mmc_free_host(mmc);
+
+       platform_set_drvdata(pdev, NULL);
+
+       dev_info(&pdev->dev, "WMT MCI device removed\n");
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int wmt_mci_suspend(struct device *dev)
+{
+       u32 reg_tmp;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct mmc_host *mmc = platform_get_drvdata(pdev);
+       struct wmt_mci_priv *priv;
+       int ret;
+
+       if (!mmc)
+               return 0;
+
+       priv = mmc_priv(mmc);
+       ret = mmc_suspend_host(mmc);
+
+       if (!ret) {
+               reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+               writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base +
+                      SDMMC_BUSMODE);
+
+               reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN);
+               writew(reg_tmp & 0x5FFF, priv->sdmmc_base + SDMMC_BLKLEN);
+
+               writeb(0xFF, priv->sdmmc_base + SDMMC_STS0);
+               writeb(0xFF, priv->sdmmc_base + SDMMC_STS1);
+
+               clk_disable(priv->clk_sdmmc);
+       }
+       return ret;
+}
+
+static int wmt_mci_resume(struct device *dev)
+{
+       u32 reg_tmp;
+       struct platform_device *pdev = to_platform_device(dev);
+       struct mmc_host *mmc = platform_get_drvdata(pdev);
+       struct wmt_mci_priv *priv;
+       int ret = 0;
+
+       if (mmc) {
+               priv = mmc_priv(mmc);
+               clk_enable(priv->clk_sdmmc);
+
+               reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE);
+               writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base +
+                      SDMMC_BUSMODE);
+
+               reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN);
+               writew(reg_tmp | (BLKL_GPI_CD | BLKL_INT_ENABLE),
+                      priv->sdmmc_base + SDMMC_BLKLEN);
+
+               reg_tmp = readb(priv->sdmmc_base + SDMMC_INTMASK0);
+               writeb(reg_tmp | INT0_DI_INT_EN, priv->sdmmc_base +
+                      SDMMC_INTMASK0);
+
+               ret = mmc_resume_host(mmc);
+       }
+
+       return ret;
+}
+
+static const struct dev_pm_ops wmt_mci_pm = {
+       .suspend        = wmt_mci_suspend,
+       .resume         = wmt_mci_resume,
+};
+
+#define wmt_mci_pm_ops (&wmt_mci_pm)
+
+#else  /* !CONFIG_PM */
+
+#define wmt_mci_pm_ops NULL
+
+#endif
+
+static struct platform_driver wmt_mci_driver = {
+       .probe = wmt_mci_probe,
+       .remove = __exit_p(wmt_mci_remove),
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .pm = wmt_mci_pm_ops,
+               .of_match_table = wmt_mci_dt_ids,
+       },
+};
+
+module_platform_driver(wmt_mci_driver);
+
+MODULE_DESCRIPTION("Wondermedia MMC/SD Driver");
+MODULE_AUTHOR("Tony Prisk");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, wmt_mci_dt_ids);
index 943550dfe9ea7f7f372c1a5d64d5a6328a371727..5c69315d60cc6ac8a4a3b5b447e9be514ecb4123 100644 (file)
@@ -85,6 +85,7 @@ struct mmc_ext_csd {
        bool                    boot_ro_lockable;
        u8                      raw_exception_status;   /* 53 */
        u8                      raw_partition_support;  /* 160 */
+       u8                      raw_rpmb_size_mult;     /* 168 */
        u8                      raw_erased_mem_count;   /* 181 */
        u8                      raw_ext_csd_structure;  /* 194 */
        u8                      raw_card_type;          /* 196 */
@@ -206,6 +207,7 @@ struct mmc_part {
 #define MMC_BLK_DATA_AREA_MAIN (1<<0)
 #define MMC_BLK_DATA_AREA_BOOT (1<<1)
 #define MMC_BLK_DATA_AREA_GP   (1<<2)
+#define MMC_BLK_DATA_AREA_RPMB (1<<3)
 };
 
 /*
index 9b9cdafc7737931f12bcd790112faa907edc8bc1..5bf7c2274fcb711138d517a131b2898d12f5b8a8 100644 (file)
@@ -170,6 +170,8 @@ extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
 extern unsigned int mmc_calc_max_discard(struct mmc_card *card);
 
 extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
+extern int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
+                             bool is_rel_write);
 extern int mmc_hw_reset(struct mmc_host *host);
 extern int mmc_hw_reset_check(struct mmc_host *host);
 extern int mmc_can_reset(struct mmc_card *card);
index 96531664a0612dc6bc006cad026cd795cf6a9aea..34be4f47293caa906ee7a8d5d2148897a4adff4a 100644 (file)
@@ -229,8 +229,9 @@ struct dw_mci_board {
        u32 quirks; /* Workaround / Quirk flags */
        unsigned int bus_hz; /* Clock speed at the cclk_in pad */
 
-       unsigned int caps;      /* Capabilities */
-       unsigned int caps2;     /* More capabilities */
+       u32 caps;       /* Capabilities */
+       u32 caps2;      /* More capabilities */
+       u32 pm_caps;    /* PM capabilities */
        /*
         * Override fifo depth. If 0, autodetect it from the FIFOTH register,
         * but note that this may not be reliable after a bootloader has used
index 7abb0e1f7bda5b4a72f1477078abfd6d86232ffa..61a10c17aabd98df129c091bc82697b5faa0b09d 100644 (file)
@@ -53,12 +53,12 @@ struct mmc_ios {
 #define MMC_TIMING_LEGACY      0
 #define MMC_TIMING_MMC_HS      1
 #define MMC_TIMING_SD_HS       2
-#define MMC_TIMING_UHS_SDR12   MMC_TIMING_LEGACY
-#define MMC_TIMING_UHS_SDR25   MMC_TIMING_SD_HS
-#define MMC_TIMING_UHS_SDR50   3
-#define MMC_TIMING_UHS_SDR104  4
-#define MMC_TIMING_UHS_DDR50   5
-#define MMC_TIMING_MMC_HS200   6
+#define MMC_TIMING_UHS_SDR12   3
+#define MMC_TIMING_UHS_SDR25   4
+#define MMC_TIMING_UHS_SDR50   5
+#define MMC_TIMING_UHS_SDR104  6
+#define MMC_TIMING_UHS_DDR50   7
+#define MMC_TIMING_MMC_HS200   8
 
 #define MMC_SDR_MODE           0
 #define MMC_1_2V_DDR_MODE      1
@@ -136,6 +136,7 @@ struct mmc_host_ops {
        void    (*enable_preset_value)(struct mmc_host *host, bool enable);
        int     (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
        void    (*hw_reset)(struct mmc_host *host);
+       void    (*card_event)(struct mmc_host *host);
 };
 
 struct mmc_card;
@@ -211,7 +212,7 @@ struct mmc_host {
 #define MMC_VDD_34_35          0x00400000      /* VDD voltage 3.4 ~ 3.5 */
 #define MMC_VDD_35_36          0x00800000      /* VDD voltage 3.5 ~ 3.6 */
 
-       unsigned long           caps;           /* Host capabilities */
+       u32                     caps;           /* Host capabilities */
 
 #define MMC_CAP_4_BIT_DATA     (1 << 0)        /* Can the host do 4 bit transfers */
 #define MMC_CAP_MMC_HIGHSPEED  (1 << 1)        /* Can do MMC high-speed timing */
@@ -241,7 +242,7 @@ struct mmc_host {
 #define MMC_CAP_CMD23          (1 << 30)       /* CMD23 supported. */
 #define MMC_CAP_HW_RESET       (1 << 31)       /* Hardware reset */
 
-       unsigned int            caps2;          /* More host capabilities */
+       u32                     caps2;          /* More host capabilities */
 
 #define MMC_CAP2_BOOTPART_NOACC        (1 << 0)        /* Boot partition no access */
 #define MMC_CAP2_CACHE_CTRL    (1 << 1)        /* Allow cache control */
index 01e4b394029b1bf15fc6d0bd70f0295b0ee28986..94d532e41c61cc6c8cef8f9bef3376955f2ae898 100644 (file)
@@ -286,6 +286,7 @@ struct _mmc_csd {
 #define EXT_CSD_BKOPS_START            164     /* W */
 #define EXT_CSD_SANITIZE_START         165     /* W */
 #define EXT_CSD_WR_REL_PARAM           166     /* RO */
+#define EXT_CSD_RPMB_MULT              168     /* RO */
 #define EXT_CSD_BOOT_WP                        173     /* R/W */
 #define EXT_CSD_ERASE_GROUP_DEF                175     /* R/W */
 #define EXT_CSD_PART_CONFIG            179     /* R/W */
@@ -339,6 +340,7 @@ struct _mmc_csd {
 
 #define EXT_CSD_PART_CONFIG_ACC_MASK   (0x7)
 #define EXT_CSD_PART_CONFIG_ACC_BOOT0  (0x1)
+#define EXT_CSD_PART_CONFIG_ACC_RPMB   (0x3)
 #define EXT_CSD_PART_CONFIG_ACC_GP0    (0x4)
 
 #define EXT_CSD_PART_SUPPORT_PART_EN   (0x1)
diff --git a/include/linux/mmc/mxs-mmc.h b/include/linux/mmc/mxs-mmc.h
deleted file mode 100644 (file)
index 7c2ad3a..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __LINUX_MMC_MXS_MMC_H__
-#define __LINUX_MMC_MXS_MMC_H__
-
-struct mxs_mmc_platform_data {
-       int wp_gpio;    /* write protect pin */
-       unsigned int flags;
-#define SLOTF_4_BIT_CAPABLE    (1 << 0)
-#define SLOTF_8_BIT_CAPABLE    (1 << 1)
-};
-
-#endif /* __LINUX_MMC_MXS_MMC_H__ */
index 1edcb4dad8c464a7910d126ebcf1b36bcefacb36..4bbc3301fbbfef64988495a910f274825fccc057 100644 (file)
@@ -92,6 +92,8 @@ struct sdhci_host {
 
 #define SDHCI_QUIRK2_HOST_OFF_CARD_ON                  (1<<0)
 #define SDHCI_QUIRK2_HOST_NO_CMD23                     (1<<1)
+/* The system physically doesn't support 1.8v, even if the host does */
+#define SDHCI_QUIRK2_NO_1_8_V                          (1<<2)
 
        int irq;                /* Device IRQ */
        void __iomem *ioaddr;   /* Mapped address */
@@ -158,8 +160,8 @@ struct sdhci_host {
 
        struct timer_list timer;        /* Timer for timeouts */
 
-       unsigned int caps;      /* Alternative CAPABILITY_0 */
-       unsigned int caps1;     /* Alternative CAPABILITY_1 */
+       u32 caps;               /* Alternative CAPABILITY_0 */
+       u32 caps1;              /* Alternative CAPABILITY_1 */
 
        unsigned int            ocr_avail_sdio; /* OCR bit masks */
        unsigned int            ocr_avail_sd;
index 59acd987ed340e18b69a55fd15f0872dca94b055..27d3156d093ae4f05ac09da2ddf5b58c4292d8ec 100644 (file)
@@ -38,6 +38,7 @@
  * @max_speed: the maximum speed supported
  * @host_caps: Standard MMC host capabilities bit field.
  * @quirks: quirks of platfrom
+ * @quirks2: quirks2 of platfrom
  * @pm_caps: pm_caps of platfrom
  */
 struct sdhci_pxa_platdata {
@@ -48,9 +49,10 @@ struct sdhci_pxa_platdata {
        unsigned int    ext_cd_gpio;
        bool            ext_cd_gpio_invert;
        unsigned int    max_speed;
-       unsigned int    host_caps;
-       unsigned int    host_caps2;
+       u32             host_caps;
+       u32             host_caps2;
        unsigned int    quirks;
+       unsigned int    quirks2;
        unsigned int    pm_caps;
 };