Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 28 Oct 2010 16:33:42 +0000 (09:33 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 28 Oct 2010 16:33:42 +0000 (09:33 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (66 commits)
  mmc: add new sdhci-pxa driver for Marvell SoCs
  mmc: make number of mmcblk minors configurable
  mmc_spi: Recover from CRC errors for r/w operation over SPI.
  mmc: sdhci-pltfm: add -pltfm driver for imx35/51
  mmc: sdhci-of-esdhc: factor out common stuff
  mmc: sdhci_pltfm: pass more data on custom init call
  mmc: sdhci: introduce get_ro private write-protect hook
  mmc: sdhci-pltfm: move .h file into appropriate subdir
  mmc: sdhci-pltfm: Add structure for host-specific data
  mmc: fix cb710 kconfig dependency warning
  mmc: cb710: remove debugging printk (info duplicated from mmc-core)
  mmc: cb710: clear irq handler on init() error path
  mmc: cb710: remove unnecessary msleep()
  mmc: cb710: implement get_cd() callback
  mmc: cb710: partially demystify clock selection
  mmc: add a file to debugfs for changing host clock at runtime
  mmc: sdhci: allow for eMMC 74 clock generation by controller
  mmc: sdhci: highspeed: check for mmc as well as sd cards
  mmc: sdhci: Add Moorestown device support
  mmc: sdhci: Intel Medfield support
  ...

60 files changed:
Documentation/devices.txt
arch/arm/plat-pxa/include/plat/sdhci.h [new file with mode: 0644]
drivers/mmc/Makefile
drivers/mmc/card/Kconfig
drivers/mmc/card/Makefile
drivers/mmc/card/block.c
drivers/mmc/card/mmc_test.c
drivers/mmc/card/queue.c
drivers/mmc/core/Makefile
drivers/mmc/core/bus.c
drivers/mmc/core/bus.h
drivers/mmc/core/core.c
drivers/mmc/core/core.h
drivers/mmc/core/debugfs.c
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/core/sd.c
drivers/mmc/core/sdio.c
drivers/mmc/core/sdio_bus.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/at91_mci.c
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/au1xmmc.c
drivers/mmc/host/bfin_sdh.c
drivers/mmc/host/cb710-mmc.c
drivers/mmc/host/davinci_mmc.c
drivers/mmc/host/imxmmc.c
drivers/mmc/host/jz4740_mmc.c
drivers/mmc/host/mmc_spi.c
drivers/mmc/host/mmci.c
drivers/mmc/host/msm_sdcc.c
drivers/mmc/host/mvsdio.c
drivers/mmc/host/mxcmmc.c
drivers/mmc/host/omap.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/pxamci.c
drivers/mmc/host/s3cmci.c
drivers/mmc/host/sdhci-cns3xxx.c
drivers/mmc/host/sdhci-esdhc-imx.c [new file with mode: 0644]
drivers/mmc/host/sdhci-esdhc.h [new file with mode: 0644]
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-pltfm.c
drivers/mmc/host/sdhci-pltfm.h
drivers/mmc/host/sdhci-pxa.c [new file with mode: 0644]
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/tifm_sd.c
drivers/mmc/host/ushc.c [new file with mode: 0644]
drivers/mmc/host/via-sdmmc.c
drivers/mmc/host/wbsd.c
include/linux/mmc/card.h
include/linux/mmc/core.h
include/linux/mmc/host.h
include/linux/mmc/mmc.h
include/linux/mmc/sdhci-pltfm.h [moved from include/linux/sdhci-pltfm.h with 93% similarity]
include/linux/mmc/sdhci.h [new file with mode: 0644]
include/linux/pci_ids.h

index c58abf1..170cc1e 100644 (file)
@@ -2520,6 +2520,12 @@ Your cooperation is appreciated.
                  8 = /dev/mmcblk1      Second SD/MMC card
                    ...
 
+               The start of next SD/MMC card can be configured with
+               CONFIG_MMC_BLOCK_MINORS, or overridden at boot/modprobe
+               time using the mmcblk.perdev_minors option. That would
+               bump the offset between each card to be the configured
+               value instead of the default 8.
+
 179 char       CCube DVXChip-based PCI products
                  0 = /dev/dvxirq0      First DVX device
                  1 = /dev/dvxirq1      Second DVX device
diff --git a/arch/arm/plat-pxa/include/plat/sdhci.h b/arch/arm/plat-pxa/include/plat/sdhci.h
new file mode 100644 (file)
index 0000000..e49c5b6
--- /dev/null
@@ -0,0 +1,32 @@
+/* linux/arch/arm/plat-pxa/include/plat/sdhci.h
+ *
+ * Copyright 2010 Marvell
+ *     Zhangfei Gao <zhangfei.gao@marvell.com>
+ *
+ * PXA Platform - SDHCI platform data definitions
+ *
+ * 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 __PLAT_PXA_SDHCI_H
+#define __PLAT_PXA_SDHCI_H
+
+/* pxa specific flag */
+/* Require clock free running */
+#define PXA_FLAG_DISABLE_CLOCK_GATING (1<<0)
+
+/*
+ * struct pxa_sdhci_platdata() - Platform device data for PXA SDHCI
+ * @max_speed: the maximum speed supported
+ * @quirks: quirks of specific device
+ * @flags: flags for platform requirement
+ */
+struct sdhci_pxa_platdata {
+       unsigned int    max_speed;
+       unsigned int    quirks;
+       unsigned int    flags;
+};
+
+#endif /* __PLAT_PXA_SDHCI_H */
index 9979f5e..12eef39 100644 (file)
@@ -2,9 +2,7 @@
 # Makefile for the kernel mmc device drivers.
 #
 
-ifeq ($(CONFIG_MMC_DEBUG),y)
-       EXTRA_CFLAGS            += -DDEBUG
-endif
+subdir-ccflags-$(CONFIG_MMC_DEBUG) := -DDEBUG
 
 obj-$(CONFIG_MMC)              += core/
 obj-$(CONFIG_MMC)              += card/
index 3f2a912..57e4416 100644 (file)
@@ -14,6 +14,23 @@ config MMC_BLOCK
          mount the filesystem. Almost everyone wishing MMC support
          should say Y or M here.
 
+config MMC_BLOCK_MINORS
+       int "Number of minors per block device"
+       range 4 256
+       default 8
+       help
+         Number of minors per block device. One is needed for every
+         partition on the disk (plus one for the whole disk).
+
+         Number of total MMC minors available is 256, so your number
+         of supported block devices will be limited to 256 divided
+         by this number.
+
+         Default is 8 to be backwards compatible with previous
+         hardwired device numbering.
+
+         If unsure, say 8 here.
+
 config MMC_BLOCK_BOUNCE
        bool "Use bounce buffer for simple hosts"
        depends on MMC_BLOCK
index 0d40751..c73b406 100644 (file)
@@ -2,10 +2,6 @@
 # Makefile for MMC/SD card drivers
 #
 
-ifeq ($(CONFIG_MMC_DEBUG),y)
-       EXTRA_CFLAGS            += -DDEBUG
-endif
-
 obj-$(CONFIG_MMC_BLOCK)                += mmc_block.o
 mmc_block-objs                 := block.o queue.o
 obj-$(CONFIG_MMC_TEST)         += mmc_test.o
index 00073b7..217f820 100644 (file)
 #include "queue.h"
 
 MODULE_ALIAS("mmc:block");
+#ifdef MODULE_PARAM_PREFIX
+#undef MODULE_PARAM_PREFIX
+#endif
+#define MODULE_PARAM_PREFIX "mmcblk."
+
+static DEFINE_MUTEX(block_mutex);
 
 /*
- * max 8 partitions per card
+ * The defaults come from config options but can be overriden by module
+ * or bootarg options.
  */
-#define MMC_SHIFT      3
-#define MMC_NUM_MINORS (256 >> MMC_SHIFT)
+static int perdev_minors = CONFIG_MMC_BLOCK_MINORS;
 
-static DEFINE_MUTEX(block_mutex);
-static DECLARE_BITMAP(dev_use, MMC_NUM_MINORS);
+/*
+ * We've only got one major, so number of mmcblk devices is
+ * limited to 256 / number of minors per device.
+ */
+static int max_devices;
+
+/* 256 minors, so at most 256 separate devices */
+static DECLARE_BITMAP(dev_use, 256);
 
 /*
  * There is one mmc_blk_data per slot.
@@ -67,6 +79,9 @@ struct mmc_blk_data {
 
 static DEFINE_MUTEX(open_lock);
 
+module_param(perdev_minors, int, 0444);
+MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
+
 static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
 {
        struct mmc_blk_data *md;
@@ -88,10 +103,10 @@ static void mmc_blk_put(struct mmc_blk_data *md)
        md->usage--;
        if (md->usage == 0) {
                int devmaj = MAJOR(disk_devt(md->disk));
-               int devidx = MINOR(disk_devt(md->disk)) >> MMC_SHIFT;
+               int devidx = MINOR(disk_devt(md->disk)) / perdev_minors;
 
                if (!devmaj)
-                       devidx = md->disk->first_minor >> MMC_SHIFT;
+                       devidx = md->disk->first_minor / perdev_minors;
 
                blk_cleanup_queue(md->queue.queue);
 
@@ -373,7 +388,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
                        readcmd = MMC_READ_SINGLE_BLOCK;
                        writecmd = MMC_WRITE_BLOCK;
                }
-
                if (rq_data_dir(req) == READ) {
                        brq.cmd.opcode = readcmd;
                        brq.data.flags |= MMC_DATA_READ;
@@ -567,8 +581,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
        struct mmc_blk_data *md;
        int devidx, ret;
 
-       devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS);
-       if (devidx >= MMC_NUM_MINORS)
+       devidx = find_first_zero_bit(dev_use, max_devices);
+       if (devidx >= max_devices)
                return ERR_PTR(-ENOSPC);
        __set_bit(devidx, dev_use);
 
@@ -585,7 +599,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
         */
        md->read_only = mmc_blk_readonly(card);
 
-       md->disk = alloc_disk(1 << MMC_SHIFT);
+       md->disk = alloc_disk(perdev_minors);
        if (md->disk == NULL) {
                ret = -ENOMEM;
                goto err_kfree;
@@ -602,7 +616,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
        md->queue.data = md;
 
        md->disk->major = MMC_BLOCK_MAJOR;
-       md->disk->first_minor = devidx << MMC_SHIFT;
+       md->disk->first_minor = devidx * perdev_minors;
        md->disk->fops = &mmc_bdops;
        md->disk->private_data = md;
        md->disk->queue = md->queue.queue;
@@ -620,7 +634,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
         * messages to tell when the card is present.
         */
 
-       sprintf(md->disk->disk_name, "mmcblk%d", devidx);
+       snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
+               "mmcblk%d", devidx);
 
        blk_queue_logical_block_size(md->queue.queue, 512);
 
@@ -651,23 +666,15 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
 static int
 mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
 {
-       struct mmc_command cmd;
        int err;
 
-       /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
-       if (mmc_card_blockaddr(card))
-               return 0;
-
        mmc_claim_host(card->host);
-       cmd.opcode = MMC_SET_BLOCKLEN;
-       cmd.arg = 512;
-       cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
-       err = mmc_wait_for_cmd(card->host, &cmd, 5);
+       err = mmc_set_blocklen(card, 512);
        mmc_release_host(card->host);
 
        if (err) {
-               printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
-                       md->disk->disk_name, cmd.arg, err);
+               printk(KERN_ERR "%s: unable to set block size to 512: %d\n",
+                       md->disk->disk_name, err);
                return -EINVAL;
        }
 
@@ -678,7 +685,6 @@ static int mmc_blk_probe(struct mmc_card *card)
 {
        struct mmc_blk_data *md;
        int err;
-
        char cap_str[10];
 
        /*
@@ -768,6 +774,11 @@ static int __init mmc_blk_init(void)
 {
        int res;
 
+       if (perdev_minors != CONFIG_MMC_BLOCK_MINORS)
+               pr_info("mmcblk: using %d minors per device\n", perdev_minors);
+
+       max_devices = 256 / perdev_minors;
+
        res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
        if (res)
                goto out;
index 5dd8576..21adc27 100644 (file)
 
 #include <linux/scatterlist.h>
 #include <linux/swap.h>                /* For nr_free_buffer_pages() */
+#include <linux/list.h>
+
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/seq_file.h>
 
 #define RESULT_OK              0
 #define RESULT_FAIL            1
@@ -56,7 +61,9 @@ struct mmc_test_mem {
  * struct mmc_test_area - information for performance tests.
  * @max_sz: test area size (in bytes)
  * @dev_addr: address on card at which to do performance tests
- * @max_segs: maximum segments in scatterlist @sg
+ * @max_tfr: maximum transfer size allowed by driver (in bytes)
+ * @max_segs: maximum segments allowed by driver in scatterlist @sg
+ * @max_seg_sz: maximum segment size allowed by driver
  * @blocks: number of (512 byte) blocks currently mapped by @sg
  * @sg_len: length of currently mapped scatterlist @sg
  * @mem: allocated memory
@@ -65,13 +72,59 @@ struct mmc_test_mem {
 struct mmc_test_area {
        unsigned long max_sz;
        unsigned int dev_addr;
+       unsigned int max_tfr;
        unsigned int max_segs;
+       unsigned int max_seg_sz;
        unsigned int blocks;
        unsigned int sg_len;
        struct mmc_test_mem *mem;
        struct scatterlist *sg;
 };
 
+/**
+ * struct mmc_test_transfer_result - transfer results for performance tests.
+ * @link: double-linked list
+ * @count: amount of group of sectors to check
+ * @sectors: amount of sectors to check in one group
+ * @ts: time values of transfer
+ * @rate: calculated transfer rate
+ */
+struct mmc_test_transfer_result {
+       struct list_head link;
+       unsigned int count;
+       unsigned int sectors;
+       struct timespec ts;
+       unsigned int rate;
+};
+
+/**
+ * struct mmc_test_general_result - results for tests.
+ * @link: double-linked list
+ * @card: card under test
+ * @testcase: number of test case
+ * @result: result of test run
+ * @tr_lst: transfer measurements if any as mmc_test_transfer_result
+ */
+struct mmc_test_general_result {
+       struct list_head link;
+       struct mmc_card *card;
+       int testcase;
+       int result;
+       struct list_head tr_lst;
+};
+
+/**
+ * struct mmc_test_dbgfs_file - debugfs related file.
+ * @link: double-linked list
+ * @card: card under test
+ * @file: file created under debugfs
+ */
+struct mmc_test_dbgfs_file {
+       struct list_head link;
+       struct mmc_card *card;
+       struct dentry *file;
+};
+
 /**
  * struct mmc_test_card - test information.
  * @card: card under test
@@ -79,6 +132,7 @@ struct mmc_test_area {
  * @buffer: transfer buffer
  * @highmem: buffer for highmem tests
  * @area: information for performance tests
+ * @gr: pointer to results of current testcase
  */
 struct mmc_test_card {
        struct mmc_card *card;
@@ -88,7 +142,8 @@ struct mmc_test_card {
 #ifdef CONFIG_HIGHMEM
        struct page     *highmem;
 #endif
-       struct mmc_test_area area;
+       struct mmc_test_area            area;
+       struct mmc_test_general_result  *gr;
 };
 
 /*******************************************************************/
@@ -100,17 +155,7 @@ struct mmc_test_card {
  */
 static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size)
 {
-       struct mmc_command cmd;
-       int ret;
-
-       cmd.opcode = MMC_SET_BLOCKLEN;
-       cmd.arg = size;
-       cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-       ret = mmc_wait_for_cmd(test->card->host, &cmd, 0);
-       if (ret)
-               return ret;
-
-       return 0;
+       return mmc_set_blocklen(test->card, size);
 }
 
 /*
@@ -245,27 +290,38 @@ static void mmc_test_free_mem(struct mmc_test_mem *mem)
 
 /*
  * Allocate a lot of memory, preferrably max_sz but at least min_sz.  In case
- * there isn't much memory do not exceed 1/16th total lowmem pages.
+ * there isn't much memory do not exceed 1/16th total lowmem pages.  Also do
+ * not exceed a maximum number of segments and try not to make segments much
+ * bigger than maximum segment size.
  */
 static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
-                                              unsigned long max_sz)
+                                              unsigned long max_sz,
+                                              unsigned int max_segs,
+                                              unsigned int max_seg_sz)
 {
        unsigned long max_page_cnt = DIV_ROUND_UP(max_sz, PAGE_SIZE);
        unsigned long min_page_cnt = DIV_ROUND_UP(min_sz, PAGE_SIZE);
+       unsigned long max_seg_page_cnt = DIV_ROUND_UP(max_seg_sz, PAGE_SIZE);
        unsigned long page_cnt = 0;
        unsigned long limit = nr_free_buffer_pages() >> 4;
        struct mmc_test_mem *mem;
 
        if (max_page_cnt > limit)
                max_page_cnt = limit;
-       if (max_page_cnt < min_page_cnt)
-               max_page_cnt = min_page_cnt;
+       if (min_page_cnt > max_page_cnt)
+               min_page_cnt = max_page_cnt;
+
+       if (max_seg_page_cnt > max_page_cnt)
+               max_seg_page_cnt = max_page_cnt;
+
+       if (max_segs > max_page_cnt)
+               max_segs = max_page_cnt;
 
        mem = kzalloc(sizeof(struct mmc_test_mem), GFP_KERNEL);
        if (!mem)
                return NULL;
 
-       mem->arr = kzalloc(sizeof(struct mmc_test_pages) * max_page_cnt,
+       mem->arr = kzalloc(sizeof(struct mmc_test_pages) * max_segs,
                           GFP_KERNEL);
        if (!mem->arr)
                goto out_free;
@@ -276,7 +332,7 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
                gfp_t flags = GFP_KERNEL | GFP_DMA | __GFP_NOWARN |
                                __GFP_NORETRY;
 
-               order = get_order(max_page_cnt << PAGE_SHIFT);
+               order = get_order(max_seg_page_cnt << PAGE_SHIFT);
                while (1) {
                        page = alloc_pages(flags, order);
                        if (page || !order)
@@ -295,6 +351,11 @@ static struct mmc_test_mem *mmc_test_alloc_mem(unsigned long min_sz,
                        break;
                max_page_cnt -= 1UL << order;
                page_cnt += 1UL << order;
+               if (mem->cnt >= max_segs) {
+                       if (page_cnt < min_page_cnt)
+                               goto out_free;
+                       break;
+               }
        }
 
        return mem;
@@ -310,7 +371,8 @@ out_free:
  */
 static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz,
                           struct scatterlist *sglist, int repeat,
-                          unsigned int max_segs, unsigned int *sg_len)
+                          unsigned int max_segs, unsigned int max_seg_sz,
+                          unsigned int *sg_len)
 {
        struct scatterlist *sg = NULL;
        unsigned int i;
@@ -322,8 +384,10 @@ static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long sz,
                for (i = 0; i < mem->cnt; i++) {
                        unsigned long len = PAGE_SIZE << mem->arr[i].order;
 
-                       if (sz < len)
+                       if (len > sz)
                                len = sz;
+                       if (len > max_seg_sz)
+                               len = max_seg_sz;
                        if (sg)
                                sg = sg_next(sg);
                        else
@@ -355,6 +419,7 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
                                       unsigned long sz,
                                       struct scatterlist *sglist,
                                       unsigned int max_segs,
+                                      unsigned int max_seg_sz,
                                       unsigned int *sg_len)
 {
        struct scatterlist *sg = NULL;
@@ -365,7 +430,7 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
        sg_init_table(sglist, max_segs);
 
        *sg_len = 0;
-       while (sz && i) {
+       while (sz) {
                base = page_address(mem->arr[--i].page);
                cnt = 1 << mem->arr[i].order;
                while (sz && cnt) {
@@ -374,7 +439,9 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
                                continue;
                        last_addr = addr;
                        len = PAGE_SIZE;
-                       if (sz < len)
+                       if (len > max_seg_sz)
+                               len = max_seg_sz;
+                       if (len > sz)
                                len = sz;
                        if (sg)
                                sg = sg_next(sg);
@@ -386,6 +453,8 @@ static int mmc_test_map_sg_max_scatter(struct mmc_test_mem *mem,
                        sz -= len;
                        *sg_len += 1;
                }
+               if (i == 0)
+                       i = mem->cnt;
        }
 
        if (sg)
@@ -420,6 +489,30 @@ static unsigned int mmc_test_rate(uint64_t bytes, struct timespec *ts)
        return bytes;
 }
 
+/*
+ * Save transfer results for future usage
+ */
+static void mmc_test_save_transfer_result(struct mmc_test_card *test,
+       unsigned int count, unsigned int sectors, struct timespec ts,
+       unsigned int rate)
+{
+       struct mmc_test_transfer_result *tr;
+
+       if (!test->gr)
+               return;
+
+       tr = kmalloc(sizeof(struct mmc_test_transfer_result), GFP_KERNEL);
+       if (!tr)
+               return;
+
+       tr->count = count;
+       tr->sectors = sectors;
+       tr->ts = ts;
+       tr->rate = rate;
+
+       list_add_tail(&tr->link, &test->gr->tr_lst);
+}
+
 /*
  * Print the transfer rate.
  */
@@ -436,8 +529,10 @@ static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes,
        printk(KERN_INFO "%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu "
                         "seconds (%u kB/s, %u KiB/s)\n",
                         mmc_hostname(test->card->host), sectors, sectors >> 1,
-                        (sectors == 1 ? ".5" : ""), (unsigned long)ts.tv_sec,
+                        (sectors & 1 ? ".5" : ""), (unsigned long)ts.tv_sec,
                         (unsigned long)ts.tv_nsec, rate / 1000, rate / 1024);
+
+       mmc_test_save_transfer_result(test, 1, sectors, ts, rate);
 }
 
 /*
@@ -458,9 +553,11 @@ static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes,
        printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took "
                         "%lu.%09lu seconds (%u kB/s, %u KiB/s)\n",
                         mmc_hostname(test->card->host), count, sectors, count,
-                        sectors >> 1, (sectors == 1 ? ".5" : ""),
+                        sectors >> 1, (sectors & 1 ? ".5" : ""),
                         (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec,
                         rate / 1000, rate / 1024);
+
+       mmc_test_save_transfer_result(test, count, sectors, ts, rate);
 }
 
 /*
@@ -1215,16 +1312,22 @@ static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz,
                             int max_scatter)
 {
        struct mmc_test_area *t = &test->area;
+       int err;
 
        t->blocks = sz >> 9;
 
        if (max_scatter) {
-               return mmc_test_map_sg_max_scatter(t->mem, sz, t->sg,
-                                                  t->max_segs, &t->sg_len);
-       } else {
-               return mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs,
+               err = mmc_test_map_sg_max_scatter(t->mem, sz, t->sg,
+                                                 t->max_segs, t->max_seg_sz,
                                       &t->sg_len);
+       } else {
+               err = mmc_test_map_sg(t->mem, sz, t->sg, 1, t->max_segs,
+                                     t->max_seg_sz, &t->sg_len);
        }
+       if (err)
+               printk(KERN_INFO "%s: Failed to map sg list\n",
+                      mmc_hostname(test->card->host));
+       return err;
 }
 
 /*
@@ -1249,6 +1352,22 @@ static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
        struct timespec ts1, ts2;
        int ret;
 
+       /*
+        * In the case of a maximally scattered transfer, the maximum transfer
+        * size is further limited by using PAGE_SIZE segments.
+        */
+       if (max_scatter) {
+               struct mmc_test_area *t = &test->area;
+               unsigned long max_tfr;
+
+               if (t->max_seg_sz >= PAGE_SIZE)
+                       max_tfr = t->max_segs * PAGE_SIZE;
+               else
+                       max_tfr = t->max_segs * t->max_seg_sz;
+               if (sz > max_tfr)
+                       sz = max_tfr;
+       }
+
        ret = mmc_test_area_map(test, sz, max_scatter);
        if (ret)
                return ret;
@@ -1274,7 +1393,7 @@ static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
  */
 static int mmc_test_area_fill(struct mmc_test_card *test)
 {
-       return mmc_test_area_io(test, test->area.max_sz, test->area.dev_addr,
+       return mmc_test_area_io(test, test->area.max_tfr, test->area.dev_addr,
                                1, 0, 0);
 }
 
@@ -1328,16 +1447,29 @@ static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill)
                t->max_sz = TEST_AREA_MAX_SIZE;
        else
                t->max_sz = (unsigned long)test->card->pref_erase << 9;
+
+       t->max_segs = test->card->host->max_segs;
+       t->max_seg_sz = test->card->host->max_seg_size;
+
+       t->max_tfr = t->max_sz;
+       if (t->max_tfr >> 9 > test->card->host->max_blk_count)
+               t->max_tfr = test->card->host->max_blk_count << 9;
+       if (t->max_tfr > test->card->host->max_req_size)
+               t->max_tfr = test->card->host->max_req_size;
+       if (t->max_tfr / t->max_seg_sz > t->max_segs)
+               t->max_tfr = t->max_segs * t->max_seg_sz;
+
        /*
-        * Try to allocate enough memory for the whole area.  Less is OK
+        * Try to allocate enough memory for a max. sized transfer.  Less is OK
         * because the same memory can be mapped into the scatterlist more than
-        * once.
+        * once.  Also, take into account the limits imposed on scatterlist
+        * segments by the host driver.
         */
-       t->mem = mmc_test_alloc_mem(min_sz, t->max_sz);
+       t->mem = mmc_test_alloc_mem(min_sz, t->max_tfr, t->max_segs,
+                                   t->max_seg_sz);
        if (!t->mem)
                return -ENOMEM;
 
-       t->max_segs = DIV_ROUND_UP(t->max_sz, PAGE_SIZE);
        t->sg = kmalloc(sizeof(struct scatterlist) * t->max_segs, GFP_KERNEL);
        if (!t->sg) {
                ret = -ENOMEM;
@@ -1401,7 +1533,7 @@ static int mmc_test_area_prepare_fill(struct mmc_test_card *test)
 static int mmc_test_best_performance(struct mmc_test_card *test, int write,
                                     int max_scatter)
 {
-       return mmc_test_area_io(test, test->area.max_sz, test->area.dev_addr,
+       return mmc_test_area_io(test, test->area.max_tfr, test->area.dev_addr,
                                write, max_scatter, 1);
 }
 
@@ -1446,12 +1578,13 @@ static int mmc_test_profile_read_perf(struct mmc_test_card *test)
        unsigned int dev_addr;
        int ret;
 
-       for (sz = 512; sz < test->area.max_sz; sz <<= 1) {
+       for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
                dev_addr = test->area.dev_addr + (sz >> 9);
                ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
                if (ret)
                        return ret;
        }
+       sz = test->area.max_tfr;
        dev_addr = test->area.dev_addr;
        return mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
 }
@@ -1468,7 +1601,7 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
        ret = mmc_test_area_erase(test);
        if (ret)
                return ret;
-       for (sz = 512; sz < test->area.max_sz; sz <<= 1) {
+       for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
                dev_addr = test->area.dev_addr + (sz >> 9);
                ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
                if (ret)
@@ -1477,6 +1610,7 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
        ret = mmc_test_area_erase(test);
        if (ret)
                return ret;
+       sz = test->area.max_tfr;
        dev_addr = test->area.dev_addr;
        return mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
 }
@@ -1516,29 +1650,63 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
        return 0;
 }
 
+static int mmc_test_seq_read_perf(struct mmc_test_card *test, unsigned long sz)
+{
+       unsigned int dev_addr, i, cnt;
+       struct timespec ts1, ts2;
+       int ret;
+
+       cnt = test->area.max_sz / sz;
+       dev_addr = test->area.dev_addr;
+       getnstimeofday(&ts1);
+       for (i = 0; i < cnt; i++) {
+               ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 0);
+               if (ret)
+                       return ret;
+               dev_addr += (sz >> 9);
+       }
+       getnstimeofday(&ts2);
+       mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
+       return 0;
+}
+
 /*
  * Consecutive read performance by transfer size.
  */
 static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test)
 {
        unsigned long sz;
+       int ret;
+
+       for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
+               ret = mmc_test_seq_read_perf(test, sz);
+               if (ret)
+                       return ret;
+       }
+       sz = test->area.max_tfr;
+       return mmc_test_seq_read_perf(test, sz);
+}
+
+static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
+{
        unsigned int dev_addr, i, cnt;
        struct timespec ts1, ts2;
        int ret;
 
-       for (sz = 512; sz <= test->area.max_sz; sz <<= 1) {
-               cnt = test->area.max_sz / sz;
-               dev_addr = test->area.dev_addr;
-               getnstimeofday(&ts1);
-               for (i = 0; i < cnt; i++) {
-                       ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 0);
-                       if (ret)
-                               return ret;
-                       dev_addr += (sz >> 9);
-               }
-               getnstimeofday(&ts2);
-               mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
+       ret = mmc_test_area_erase(test);
+       if (ret)
+               return ret;
+       cnt = test->area.max_sz / sz;
+       dev_addr = test->area.dev_addr;
+       getnstimeofday(&ts1);
+       for (i = 0; i < cnt; i++) {
+               ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 0);
+               if (ret)
+                       return ret;
+               dev_addr += (sz >> 9);
        }
+       getnstimeofday(&ts2);
+       mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
        return 0;
 }
 
@@ -1548,27 +1716,15 @@ static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test)
 static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test)
 {
        unsigned long sz;
-       unsigned int dev_addr, i, cnt;
-       struct timespec ts1, ts2;
        int ret;
 
-       for (sz = 512; sz <= test->area.max_sz; sz <<= 1) {
-               ret = mmc_test_area_erase(test);
+       for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
+               ret = mmc_test_seq_write_perf(test, sz);
                if (ret)
                        return ret;
-               cnt = test->area.max_sz / sz;
-               dev_addr = test->area.dev_addr;
-               getnstimeofday(&ts1);
-               for (i = 0; i < cnt; i++) {
-                       ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 0);
-                       if (ret)
-                               return ret;
-                       dev_addr += (sz >> 9);
-               }
-               getnstimeofday(&ts2);
-               mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
        }
-       return 0;
+       sz = test->area.max_tfr;
+       return mmc_test_seq_write_perf(test, sz);
 }
 
 /*
@@ -1853,6 +2009,8 @@ static const struct mmc_test_case mmc_test_cases[] = {
 
 static DEFINE_MUTEX(mmc_test_lock);
 
+static LIST_HEAD(mmc_test_result);
+
 static void mmc_test_run(struct mmc_test_card *test, int testcase)
 {
        int i, ret;
@@ -1863,6 +2021,8 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
        mmc_claim_host(test->card->host);
 
        for (i = 0;i < ARRAY_SIZE(mmc_test_cases);i++) {
+               struct mmc_test_general_result *gr;
+
                if (testcase && ((i + 1) != testcase))
                        continue;
 
@@ -1881,6 +2041,25 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
                        }
                }
 
+               gr = kzalloc(sizeof(struct mmc_test_general_result),
+                       GFP_KERNEL);
+               if (gr) {
+                       INIT_LIST_HEAD(&gr->tr_lst);
+
+                       /* Assign data what we know already */
+                       gr->card = test->card;
+                       gr->testcase = i;
+
+                       /* Append container to global one */
+                       list_add_tail(&gr->link, &mmc_test_result);
+
+                       /*
+                        * Save the pointer to created container in our private
+                        * structure.
+                        */
+                       test->gr = gr;
+               }
+
                ret = mmc_test_cases[i].run(test);
                switch (ret) {
                case RESULT_OK:
@@ -1906,6 +2085,10 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
                                mmc_hostname(test->card->host), ret);
                }
 
+               /* Save the result */
+               if (gr)
+                       gr->result = ret;
+
                if (mmc_test_cases[i].cleanup) {
                        ret = mmc_test_cases[i].cleanup(test);
                        if (ret) {
@@ -1923,30 +2106,95 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase)
                mmc_hostname(test->card->host));
 }
 
-static ssize_t mmc_test_show(struct device *dev,
-       struct device_attribute *attr, char *buf)
+static void mmc_test_free_result(struct mmc_card *card)
 {
+       struct mmc_test_general_result *gr, *grs;
+
        mutex_lock(&mmc_test_lock);
+
+       list_for_each_entry_safe(gr, grs, &mmc_test_result, link) {
+               struct mmc_test_transfer_result *tr, *trs;
+
+               if (card && gr->card != card)
+                       continue;
+
+               list_for_each_entry_safe(tr, trs, &gr->tr_lst, link) {
+                       list_del(&tr->link);
+                       kfree(tr);
+               }
+
+               list_del(&gr->link);
+               kfree(gr);
+       }
+
+       mutex_unlock(&mmc_test_lock);
+}
+
+static LIST_HEAD(mmc_test_file_test);
+
+static int mtf_test_show(struct seq_file *sf, void *data)
+{
+       struct mmc_card *card = (struct mmc_card *)sf->private;
+       struct mmc_test_general_result *gr;
+
+       mutex_lock(&mmc_test_lock);
+
+       list_for_each_entry(gr, &mmc_test_result, link) {
+               struct mmc_test_transfer_result *tr;
+
+               if (gr->card != card)
+                       continue;
+
+               seq_printf(sf, "Test %d: %d\n", gr->testcase + 1, gr->result);
+
+               list_for_each_entry(tr, &gr->tr_lst, link) {
+                       seq_printf(sf, "%u %d %lu.%09lu %u\n",
+                               tr->count, tr->sectors,
+                               (unsigned long)tr->ts.tv_sec,
+                               (unsigned long)tr->ts.tv_nsec,
+                               tr->rate);
+               }
+       }
+
        mutex_unlock(&mmc_test_lock);
 
        return 0;
 }
 
-static ssize_t mmc_test_store(struct device *dev,
-       struct device_attribute *attr, const char *buf, size_t count)
+static int mtf_test_open(struct inode *inode, struct file *file)
 {
-       struct mmc_card *card;
+       return single_open(file, mtf_test_show, inode->i_private);
+}
+
+static ssize_t mtf_test_write(struct file *file, const char __user *buf,
+       size_t count, loff_t *pos)
+{
+       struct seq_file *sf = (struct seq_file *)file->private_data;
+       struct mmc_card *card = (struct mmc_card *)sf->private;
        struct mmc_test_card *test;
-       int testcase;
+       char lbuf[12];
+       long testcase;
 
-       card = container_of(dev, struct mmc_card, dev);
+       if (count >= sizeof(lbuf))
+               return -EINVAL;
 
-       testcase = simple_strtol(buf, NULL, 10);
+       if (copy_from_user(lbuf, buf, count))
+               return -EFAULT;
+       lbuf[count] = '\0';
+
+       if (strict_strtol(lbuf, 10, &testcase))
+               return -EINVAL;
 
        test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL);
        if (!test)
                return -ENOMEM;
 
+       /*
+        * Remove all test cases associated with given card. Thus we have only
+        * actual data of the last run.
+        */
+       mmc_test_free_result(card);
+
        test->card = card;
 
        test->buffer = kzalloc(BUFFER_SIZE, GFP_KERNEL);
@@ -1973,16 +2221,78 @@ static ssize_t mmc_test_store(struct device *dev,
        return count;
 }
 
-static DEVICE_ATTR(test, S_IWUSR | S_IRUGO, mmc_test_show, mmc_test_store);
+static const struct file_operations mmc_test_fops_test = {
+       .open           = mtf_test_open,
+       .read           = seq_read,
+       .write          = mtf_test_write,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void mmc_test_free_file_test(struct mmc_card *card)
+{
+       struct mmc_test_dbgfs_file *df, *dfs;
+
+       mutex_lock(&mmc_test_lock);
+
+       list_for_each_entry_safe(df, dfs, &mmc_test_file_test, link) {
+               if (card && df->card != card)
+                       continue;
+               debugfs_remove(df->file);
+               list_del(&df->link);
+               kfree(df);
+       }
+
+       mutex_unlock(&mmc_test_lock);
+}
+
+static int mmc_test_register_file_test(struct mmc_card *card)
+{
+       struct dentry *file = NULL;
+       struct mmc_test_dbgfs_file *df;
+       int ret = 0;
+
+       mutex_lock(&mmc_test_lock);
+
+       if (card->debugfs_root)
+               file = debugfs_create_file("test", S_IWUSR | S_IRUGO,
+                       card->debugfs_root, card, &mmc_test_fops_test);
+
+       if (IS_ERR_OR_NULL(file)) {
+               dev_err(&card->dev,
+                       "Can't create file. Perhaps debugfs is disabled.\n");
+               ret = -ENODEV;
+               goto err;
+       }
+
+       df = kmalloc(sizeof(struct mmc_test_dbgfs_file), GFP_KERNEL);
+       if (!df) {
+               debugfs_remove(file);
+               dev_err(&card->dev,
+                       "Can't allocate memory for internal usage.\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       df->card = card;
+       df->file = file;
+
+       list_add(&df->link, &mmc_test_file_test);
+
+err:
+       mutex_unlock(&mmc_test_lock);
+
+       return ret;
+}
 
 static int mmc_test_probe(struct mmc_card *card)
 {
        int ret;
 
-       if ((card->type != MMC_TYPE_MMC) && (card->type != MMC_TYPE_SD))
+       if (!mmc_card_mmc(card) && !mmc_card_sd(card))
                return -ENODEV;
 
-       ret = device_create_file(&card->dev, &dev_attr_test);
+       ret = mmc_test_register_file_test(card);
        if (ret)
                return ret;
 
@@ -1993,7 +2303,8 @@ static int mmc_test_probe(struct mmc_card *card)
 
 static void mmc_test_remove(struct mmc_card *card)
 {
-       device_remove_file(&card->dev, &dev_attr_test);
+       mmc_test_free_result(card);
+       mmc_test_free_file_test(card);
 }
 
 static struct mmc_driver mmc_driver = {
@@ -2011,6 +2322,10 @@ static int __init mmc_test_init(void)
 
 static void __exit mmc_test_exit(void)
 {
+       /* Clear stalled data if card is still plugged */
+       mmc_test_free_result(NULL);
+       mmc_test_free_file_test(NULL);
+
        mmc_unregister_driver(&mmc_driver);
 }
 
index 9c0b42b..4e42d03 100644 (file)
@@ -146,7 +146,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
        }
 
 #ifdef CONFIG_MMC_BLOCK_BOUNCE
-       if (host->max_hw_segs == 1) {
+       if (host->max_segs == 1) {
                unsigned int bouncesz;
 
                bouncesz = MMC_QUEUE_BOUNCESZ;
@@ -196,21 +196,23 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
                blk_queue_bounce_limit(mq->queue, limit);
                blk_queue_max_hw_sectors(mq->queue,
                        min(host->max_blk_count, host->max_req_size / 512));
-               blk_queue_max_segments(mq->queue, host->max_hw_segs);
+               blk_queue_max_segments(mq->queue, host->max_segs);
                blk_queue_max_segment_size(mq->queue, host->max_seg_size);
 
                mq->sg = kmalloc(sizeof(struct scatterlist) *
-                       host->max_phys_segs, GFP_KERNEL);
+                       host->max_segs, GFP_KERNEL);
                if (!mq->sg) {
                        ret = -ENOMEM;
                        goto cleanup_queue;
                }
-               sg_init_table(mq->sg, host->max_phys_segs);
+               sg_init_table(mq->sg, host->max_segs);
        }
 
-       init_MUTEX(&mq->thread_sem);
+       sema_init(&mq->thread_sem, 1);
+
+       mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d",
+               host->index);
 
-       mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd");
        if (IS_ERR(mq->thread)) {
                ret = PTR_ERR(mq->thread);
                goto free_bounce_sg;
index 889e5f8..86b4791 100644 (file)
@@ -2,10 +2,6 @@
 # Makefile for the kernel mmc core.
 #
 
-ifeq ($(CONFIG_MMC_DEBUG),y)
-       EXTRA_CFLAGS            += -DDEBUG
-endif
-
 obj-$(CONFIG_MMC)              += mmc_core.o
 mmc_core-y                     := core.o bus.o host.o \
                                   mmc.o mmc_ops.o sd.o sd_ops.o \
index 7cd9749..af8dc6a 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
 #include "sdio_cis.h"
 #include "bus.h"
 
-#define dev_to_mmc_card(d)     container_of(d, struct mmc_card, dev)
 #define to_mmc_driver(d)       container_of(d, struct mmc_driver, drv)
 
 static ssize_t mmc_type_show(struct device *dev,
        struct device_attribute *attr, char *buf)
 {
-       struct mmc_card *card = dev_to_mmc_card(dev);
+       struct mmc_card *card = mmc_dev_to_card(dev);
 
        switch (card->type) {
        case MMC_TYPE_MMC:
@@ -62,7 +62,7 @@ static int mmc_bus_match(struct device *dev, struct device_driver *drv)
 static int
 mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
-       struct mmc_card *card = dev_to_mmc_card(dev);
+       struct mmc_card *card = mmc_dev_to_card(dev);
        const char *type;
        int retval = 0;
 
@@ -105,7 +105,7 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 static int mmc_bus_probe(struct device *dev)
 {
        struct mmc_driver *drv = to_mmc_driver(dev->driver);
-       struct mmc_card *card = dev_to_mmc_card(dev);
+       struct mmc_card *card = mmc_dev_to_card(dev);
 
        return drv->probe(card);
 }
@@ -113,7 +113,7 @@ static int mmc_bus_probe(struct device *dev)
 static int mmc_bus_remove(struct device *dev)
 {
        struct mmc_driver *drv = to_mmc_driver(dev->driver);
-       struct mmc_card *card = dev_to_mmc_card(dev);
+       struct mmc_card *card = mmc_dev_to_card(dev);
 
        drv->remove(card);
 
@@ -123,7 +123,7 @@ static int mmc_bus_remove(struct device *dev)
 static int mmc_bus_suspend(struct device *dev, pm_message_t state)
 {
        struct mmc_driver *drv = to_mmc_driver(dev->driver);
-       struct mmc_card *card = dev_to_mmc_card(dev);
+       struct mmc_card *card = mmc_dev_to_card(dev);
        int ret = 0;
 
        if (dev->driver && drv->suspend)
@@ -134,7 +134,7 @@ static int mmc_bus_suspend(struct device *dev, pm_message_t state)
 static int mmc_bus_resume(struct device *dev)
 {
        struct mmc_driver *drv = to_mmc_driver(dev->driver);
-       struct mmc_card *card = dev_to_mmc_card(dev);
+       struct mmc_card *card = mmc_dev_to_card(dev);
        int ret = 0;
 
        if (dev->driver && drv->resume)
@@ -142,6 +142,41 @@ static int mmc_bus_resume(struct device *dev)
        return ret;
 }
 
+#ifdef CONFIG_PM_RUNTIME
+
+static int mmc_runtime_suspend(struct device *dev)
+{
+       struct mmc_card *card = mmc_dev_to_card(dev);
+
+       return mmc_power_save_host(card->host);
+}
+
+static int mmc_runtime_resume(struct device *dev)
+{
+       struct mmc_card *card = mmc_dev_to_card(dev);
+
+       return mmc_power_restore_host(card->host);
+}
+
+static int mmc_runtime_idle(struct device *dev)
+{
+       return pm_runtime_suspend(dev);
+}
+
+static const struct dev_pm_ops mmc_bus_pm_ops = {
+       .runtime_suspend        = mmc_runtime_suspend,
+       .runtime_resume         = mmc_runtime_resume,
+       .runtime_idle           = mmc_runtime_idle,
+};
+
+#define MMC_PM_OPS_PTR (&mmc_bus_pm_ops)
+
+#else /* !CONFIG_PM_RUNTIME */
+
+#define MMC_PM_OPS_PTR NULL
+
+#endif /* !CONFIG_PM_RUNTIME */
+
 static struct bus_type mmc_bus_type = {
        .name           = "mmc",
        .dev_attrs      = mmc_dev_attrs,
@@ -151,6 +186,7 @@ static struct bus_type mmc_bus_type = {
        .remove         = mmc_bus_remove,
        .suspend        = mmc_bus_suspend,
        .resume         = mmc_bus_resume,
+       .pm             = MMC_PM_OPS_PTR,
 };
 
 int mmc_register_bus(void)
@@ -189,7 +225,7 @@ EXPORT_SYMBOL(mmc_unregister_driver);
 
 static void mmc_release_card(struct device *dev)
 {
-       struct mmc_card *card = dev_to_mmc_card(dev);
+       struct mmc_card *card = mmc_dev_to_card(dev);
 
        sdio_free_common_cis(card);
 
@@ -254,14 +290,16 @@ int mmc_add_card(struct mmc_card *card)
        }
 
        if (mmc_host_is_spi(card->host)) {
-               printk(KERN_INFO "%s: new %s%s card on SPI\n",
+               printk(KERN_INFO "%s: new %s%s%s card on SPI\n",
                        mmc_hostname(card->host),
                        mmc_card_highspeed(card) ? "high speed " : "",
+                       mmc_card_ddr_mode(card) ? "DDR " : "",
                        type);
        } else {
-               printk(KERN_INFO "%s: new %s%s card at address %04x\n",
+               printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
                        mmc_hostname(card->host),
                        mmc_card_highspeed(card) ? "high speed " : "",
+                       mmc_card_ddr_mode(card) ? "DDR " : "",
                        type, card->rca);
        }
 
index 1817876..00a1971 100644 (file)
@@ -14,7 +14,7 @@
 #define MMC_DEV_ATTR(name, fmt, args...)                                       \
 static ssize_t mmc_##name##_show (struct device *dev, struct device_attribute *attr, char *buf)        \
 {                                                                              \
-       struct mmc_card *card = container_of(dev, struct mmc_card, dev);        \
+       struct mmc_card *card = mmc_dev_to_card(dev);                           \
        return sprintf(buf, fmt, args);                                         \
 }                                                                              \
 static DEVICE_ATTR(name, S_IRUGO, mmc_##name##_show, NULL)
index 09eee6d..8f86d70 100644 (file)
@@ -58,6 +58,7 @@ int mmc_assume_removable;
 #else
 int mmc_assume_removable = 1;
 #endif
+EXPORT_SYMBOL(mmc_assume_removable);
 module_param_named(removable, mmc_assume_removable, bool, 0644);
 MODULE_PARM_DESC(
        removable,
@@ -650,14 +651,24 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
 }
 
 /*
- * Change data bus width of a host.
+ * Change data bus width and DDR mode of a host.
  */
-void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
+void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
+                          unsigned int ddr)
 {
        host->ios.bus_width = width;
+       host->ios.ddr = ddr;
        mmc_set_ios(host);
 }
 
+/*
+ * Change data bus width of a host.
+ */
+void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
+{
+       mmc_set_bus_width_ddr(host, width, MMC_SDR_MODE);
+}
+
 /**
  * mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number
  * @vdd:       voltage (mV)
@@ -771,8 +782,9 @@ EXPORT_SYMBOL(mmc_regulator_get_ocrmask);
 
 /**
  * mmc_regulator_set_ocr - set regulator to match host->ios voltage
- * @vdd_bit: zero for power off, else a bit number (host->ios.vdd)
+ * @mmc: the host to regulate
  * @supply: regulator to use
+ * @vdd_bit: zero for power off, else a bit number (host->ios.vdd)
  *
  * Returns zero on success, else negative errno.
  *
@@ -780,15 +792,12 @@ EXPORT_SYMBOL(mmc_regulator_get_ocrmask);
  * a particular supply voltage.  This would normally be called from the
  * set_ios() method.
  */
-int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit)
+int mmc_regulator_set_ocr(struct mmc_host *mmc,
+                       struct regulator *supply,
+                       unsigned short vdd_bit)
 {
        int                     result = 0;
        int                     min_uV, max_uV;
-       int                     enabled;
-
-       enabled = regulator_is_enabled(supply);
-       if (enabled < 0)
-               return enabled;
 
        if (vdd_bit) {
                int             tmp;
@@ -819,17 +828,25 @@ int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit)
                else
                        result = 0;
 
-               if (result == 0 && !enabled)
+               if (result == 0 && !mmc->regulator_enabled) {
                        result = regulator_enable(supply);
-       } else if (enabled) {
+                       if (!result)
+                               mmc->regulator_enabled = true;
+               }
+       } else if (mmc->regulator_enabled) {
                result = regulator_disable(supply);
+               if (result == 0)
+                       mmc->regulator_enabled = false;
        }
 
+       if (result)
+               dev_err(mmc_dev(mmc),
+                       "could not set regulator OCR (%d)\n", result);
        return result;
 }
 EXPORT_SYMBOL(mmc_regulator_set_ocr);
 
-#endif
+#endif /* CONFIG_REGULATOR */
 
 /*
  * Mask off any voltages we don't support and select
@@ -907,12 +924,7 @@ static void mmc_power_up(struct mmc_host *host)
         */
        mmc_delay(10);
 
-       if (host->f_min > 400000) {
-               pr_warning("%s: Minimum clock frequency too high for "
-                               "identification mode\n", mmc_hostname(host));
-               host->ios.clock = host->f_min;
-       } else
-               host->ios.clock = 400000;
+       host->ios.clock = host->f_init;
 
        host->ios.power_mode = MMC_POWER_ON;
        mmc_set_ios(host);
@@ -1397,6 +1409,21 @@ int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
 }
 EXPORT_SYMBOL(mmc_erase_group_aligned);
 
+int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
+{
+       struct mmc_command cmd;
+
+       if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
+               return 0;
+
+       memset(&cmd, 0, sizeof(struct mmc_command));
+       cmd.opcode = MMC_SET_BLOCKLEN;
+       cmd.arg = blocklen;
+       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_blocklen);
+
 void mmc_rescan(struct work_struct *work)
 {
        struct mmc_host *host =
@@ -1404,6 +1431,8 @@ void mmc_rescan(struct work_struct *work)
        u32 ocr;
        int err;
        unsigned long flags;
+       int i;
+       const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
 
        spin_lock_irqsave(&host->lock, flags);
 
@@ -1443,55 +1472,71 @@ void mmc_rescan(struct work_struct *work)
        if (host->ops->get_cd && host->ops->get_cd(host) == 0)
                goto out;
 
-       mmc_claim_host(host);
+       for (i = 0; i < ARRAY_SIZE(freqs); i++) {
+               mmc_claim_host(host);
 
-       mmc_power_up(host);
-       sdio_reset(host);
-       mmc_go_idle(host);
+               if (freqs[i] >= host->f_min)
+                       host->f_init = freqs[i];
+               else if (!i || freqs[i-1] > host->f_min)
+                       host->f_init = host->f_min;
+               else {
+                       mmc_release_host(host);
+                       goto out;
+               }
+#ifdef CONFIG_MMC_DEBUG
+               pr_info("%s: %s: trying to init card at %u Hz\n",
+                       mmc_hostname(host), __func__, host->f_init);
+#endif
+               mmc_power_up(host);
+               sdio_reset(host);
+               mmc_go_idle(host);
 
-       mmc_send_if_cond(host, host->ocr_avail);
+               mmc_send_if_cond(host, host->ocr_avail);
 
-       /*
-        * First we search for SDIO...
-        */
-       err = mmc_send_io_op_cond(host, 0, &ocr);
-       if (!err) {
-               if (mmc_attach_sdio(host, ocr)) {
-                       mmc_claim_host(host);
-                       /* try SDMEM (but not MMC) even if SDIO is broken */
-                       if (mmc_send_app_op_cond(host, 0, &ocr))
-                               goto out_fail;
+               /*
+                * First we search for SDIO...
+                */
+               err = mmc_send_io_op_cond(host, 0, &ocr);
+               if (!err) {
+                       if (mmc_attach_sdio(host, ocr)) {
+                               mmc_claim_host(host);
+                               /*
+                                * Try SDMEM (but not MMC) even if SDIO
+                                * is broken.
+                                */
+                               if (mmc_send_app_op_cond(host, 0, &ocr))
+                                       goto out_fail;
+
+                               if (mmc_attach_sd(host, ocr))
+                                       mmc_power_off(host);
+                       }
+                       goto out;
+               }
 
+               /*
+                * ...then normal SD...
+                */
+               err = mmc_send_app_op_cond(host, 0, &ocr);
+               if (!err) {
                        if (mmc_attach_sd(host, ocr))
                                mmc_power_off(host);
+                       goto out;
                }
-               goto out;
-       }
 
-       /*
-        * ...then normal SD...
-        */
-       err = mmc_send_app_op_cond(host, 0, &ocr);
-       if (!err) {
-               if (mmc_attach_sd(host, ocr))
-                       mmc_power_off(host);
-               goto out;
-       }
-
-       /*
-        * ...and finally MMC.
-        */
-       err = mmc_send_op_cond(host, 0, &ocr);
-       if (!err) {
-               if (mmc_attach_mmc(host, ocr))
-                       mmc_power_off(host);
-               goto out;
-       }
+               /*
+                * ...and finally MMC.
+                */
+               err = mmc_send_op_cond(host, 0, &ocr);
+               if (!err) {
+                       if (mmc_attach_mmc(host, ocr))
+                               mmc_power_off(host);
+                       goto out;
+               }
 
 out_fail:
-       mmc_release_host(host);
-       mmc_power_off(host);
-
+               mmc_release_host(host);
+               mmc_power_off(host);
+       }
 out:
        if (host->caps & MMC_CAP_NEEDS_POLL)
                mmc_schedule_delayed_work(&host->detect, HZ);
@@ -1538,37 +1583,45 @@ void mmc_stop_host(struct mmc_host *host)
        mmc_power_off(host);
 }
 
-void mmc_power_save_host(struct mmc_host *host)
+int mmc_power_save_host(struct mmc_host *host)
 {
+       int ret = 0;
+
        mmc_bus_get(host);
 
        if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
                mmc_bus_put(host);
-               return;
+               return -EINVAL;
        }
 
        if (host->bus_ops->power_save)
-               host->bus_ops->power_save(host);
+               ret = host->bus_ops->power_save(host);
 
        mmc_bus_put(host);
 
        mmc_power_off(host);
+
+       return ret;
 }
 EXPORT_SYMBOL(mmc_power_save_host);
 
-void mmc_power_restore_host(struct mmc_host *host)
+int mmc_power_restore_host(struct mmc_host *host)
 {
+       int ret;
+
        mmc_bus_get(host);
 
        if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
                mmc_bus_put(host);
-               return;
+               return -EINVAL;
        }
 
        mmc_power_up(host);
-       host->bus_ops->power_restore(host);
+       ret = host->bus_ops->power_restore(host);
 
        mmc_bus_put(host);
+
+       return ret;
 }
 EXPORT_SYMBOL(mmc_power_restore_host);
 
index 9d9eef5..77240cd 100644 (file)
@@ -22,8 +22,8 @@ struct mmc_bus_ops {
        void (*detect)(struct mmc_host *);
        int (*suspend)(struct mmc_host *);
        int (*resume)(struct mmc_host *);
-       void (*power_save)(struct mmc_host *);
-       void (*power_restore)(struct mmc_host *);
+       int (*power_save)(struct mmc_host *);
+       int (*power_restore)(struct mmc_host *);
 };
 
 void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -35,6 +35,8 @@ void mmc_set_chip_select(struct mmc_host *host, int mode);
 void mmc_set_clock(struct mmc_host *host, unsigned int hz);
 void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
 void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
+void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
+                          unsigned int ddr);
 u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
 void mmc_set_timing(struct mmc_host *host, unsigned int timing);
 
@@ -58,7 +60,6 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr);
 
 /* Module parameters */
 extern int use_spi_crc;
-extern int mmc_assume_removable;
 
 /* Debugfs information for hosts and cards */
 void mmc_add_host_debugfs(struct mmc_host *host);
index 46bc6d7..eed1405 100644 (file)
@@ -134,6 +134,33 @@ static const struct file_operations mmc_ios_fops = {
        .release        = single_release,
 };
 
+static int mmc_clock_opt_get(void *data, u64 *val)
+{
+       struct mmc_host *host = data;
+
+       *val = host->ios.clock;
+
+       return 0;
+}
+
+static int mmc_clock_opt_set(void *data, u64 val)
+{
+       struct mmc_host *host = data;
+
+       /* We need this check due to input value is u64 */
+       if (val > host->f_max)
+               return -EINVAL;
+
+       mmc_claim_host(host);
+       mmc_set_clock(host, (unsigned int) val);
+       mmc_release_host(host);
+
+       return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(mmc_clock_fops, mmc_clock_opt_get, mmc_clock_opt_set,
+       "%llu\n");
+
 void mmc_add_host_debugfs(struct mmc_host *host)
 {
        struct dentry *root;
@@ -150,11 +177,15 @@ void mmc_add_host_debugfs(struct mmc_host *host)
        host->debugfs_root = root;
 
        if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
-               goto err_ios;
+               goto err_node;
+
+       if (!debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host,
+                       &mmc_clock_fops))
+               goto err_node;
 
        return;
 
-err_ios:
+err_node:
        debugfs_remove_recursive(root);
        host->debugfs_root = NULL;
 err_root:
index d80cfdc..10b8af2 100644 (file)
@@ -94,8 +94,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
         * By default, hosts do not support SGIO or large requests.
         * They have to set these according to their abilities.
         */
-       host->max_hw_segs = 1;
-       host->max_phys_segs = 1;
+       host->max_segs = 1;
        host->max_seg_size = PAGE_CACHE_SIZE;
 
        host->max_req_size = PAGE_CACHE_SIZE;
index 6909a54..995261f 100644 (file)
@@ -258,6 +258,21 @@ static int mmc_read_ext_csd(struct mmc_card *card)
        }
 
        switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
+       case EXT_CSD_CARD_TYPE_DDR_52 | EXT_CSD_CARD_TYPE_52 |
+            EXT_CSD_CARD_TYPE_26:
+               card->ext_csd.hs_max_dtr = 52000000;
+               card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_52;
+               break;
+       case EXT_CSD_CARD_TYPE_DDR_1_2V | EXT_CSD_CARD_TYPE_52 |
+            EXT_CSD_CARD_TYPE_26:
+               card->ext_csd.hs_max_dtr = 52000000;
+               card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_2V;
+               break;
+       case EXT_CSD_CARD_TYPE_DDR_1_8V | EXT_CSD_CARD_TYPE_52 |
+            EXT_CSD_CARD_TYPE_26:
+               card->ext_csd.hs_max_dtr = 52000000;
+               card->ext_csd.card_type = EXT_CSD_CARD_TYPE_DDR_1_8V;
+               break;
        case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
                card->ext_csd.hs_max_dtr = 52000000;
                break;
@@ -360,7 +375,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        struct mmc_card *oldcard)
 {
        struct mmc_card *card;
-       int err;
+       int err, ddr = MMC_SDR_MODE;
        u32 cid[4];
        unsigned int max_dtr;
 
@@ -503,17 +518,35 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
        mmc_set_clock(host, max_dtr);
 
        /*
-        * Activate wide bus (if supported).
+        * Indicate DDR mode (if supported).
+        */
+       if (mmc_card_highspeed(card)) {
+               if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
+                       && (host->caps & (MMC_CAP_1_8V_DDR)))
+                               ddr = MMC_1_8V_DDR_MODE;
+               else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
+                       && (host->caps & (MMC_CAP_1_2V_DDR)))
+                               ddr = MMC_1_2V_DDR_MODE;
+       }
+
+       /*
+        * Activate wide bus and DDR (if supported).
         */
        if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
            (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
                unsigned ext_csd_bit, bus_width;
 
                if (host->caps & MMC_CAP_8_BIT_DATA) {
-                       ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
+                       if (ddr)
+                               ext_csd_bit = EXT_CSD_DDR_BUS_WIDTH_8;
+                       else
+                               ext_csd_bit = EXT_CSD_BUS_WIDTH_8;
                        bus_width = MMC_BUS_WIDTH_8;
                } else {
-                       ext_csd_bit = EXT_CSD_BUS_WIDTH_4;
+                       if (ddr)
+                               ext_csd_bit = EXT_CSD_DDR_BUS_WIDTH_4;
+                       else
+                               ext_csd_bit = EXT_CSD_BUS_WIDTH_4;
                        bus_width = MMC_BUS_WIDTH_4;
                }
 
@@ -524,12 +557,13 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                        goto free_card;
 
                if (err) {
-                       printk(KERN_WARNING "%s: switch to bus width %d "
+                       printk(KERN_WARNING "%s: switch to bus width %d ddr %d "
                               "failed\n", mmc_hostname(card->host),
-                              1 << bus_width);
+                              1 << bus_width, ddr);
                        err = 0;
                } else {
-                       mmc_set_bus_width(card->host, bus_width);
+                       mmc_card_set_ddr_mode(card);
+                       mmc_set_bus_width_ddr(card->host, bus_width, ddr);
                }
        }
 
@@ -623,12 +657,16 @@ static int mmc_resume(struct mmc_host *host)
        return err;
 }
 
-static void mmc_power_restore(struct mmc_host *host)
+static int mmc_power_restore(struct mmc_host *host)
 {
+       int ret;
+
        host->card->state &= ~MMC_STATE_HIGHSPEED;
        mmc_claim_host(host);
-       mmc_init_card(host, host->ocr, host->card);
+       ret = mmc_init_card(host, host->ocr, host->card);
        mmc_release_host(host);
+
+       return ret;
 }
 
 static int mmc_sleep(struct mmc_host *host)
@@ -685,7 +723,7 @@ static void mmc_attach_bus_ops(struct mmc_host *host)
 {
        const struct mmc_bus_ops *bus_ops;
 
-       if (host->caps & MMC_CAP_NONREMOVABLE || !mmc_assume_removable)
+       if (!mmc_card_is_removable(host))
                bus_ops = &mmc_ops_unsafe;
        else
                bus_ops = &mmc_ops;
index 0f52410..49da4df 100644 (file)
@@ -722,12 +722,16 @@ static int mmc_sd_resume(struct mmc_host *host)
        return err;
 }
 
-static void mmc_sd_power_restore(struct mmc_host *host)
+static int mmc_sd_power_restore(struct mmc_host *host)
 {
+       int ret;
+
        host->card->state &= ~MMC_STATE_HIGHSPEED;
        mmc_claim_host(host);
-       mmc_sd_init_card(host, host->ocr, host->card);
+       ret = mmc_sd_init_card(host, host->ocr, host->card);
        mmc_release_host(host);
+
+       return ret;
 }
 
 static const struct mmc_bus_ops mmc_sd_ops = {
@@ -750,7 +754,7 @@ static void mmc_sd_attach_bus_ops(struct mmc_host *host)
 {
        const struct mmc_bus_ops *bus_ops;
 
-       if (host->caps & MMC_CAP_NONREMOVABLE || !mmc_assume_removable)
+       if (!mmc_card_is_removable(host))
                bus_ops = &mmc_sd_ops_unsafe;
        else
                bus_ops = &mmc_sd_ops;
index f332c52..c3ad105 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/err.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
@@ -456,7 +457,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
                        return -ENOENT;
 
                card = oldcard;
-               return 0;
        }
 
        if (card->type == MMC_TYPE_SD_COMBO) {
@@ -546,6 +546,11 @@ static void mmc_sdio_detect(struct mmc_host *host)
        BUG_ON(!host);
        BUG_ON(!host->card);
 
+       /* Make sure card is powered before detecting it */
+       err = pm_runtime_get_sync(&host->card->dev);
+       if (err < 0)
+               goto out;
+
        mmc_claim_host(host);
 
        /*
@@ -555,6 +560,7 @@ static void mmc_sdio_detect(struct mmc_host *host)
 
        mmc_release_host(host);
 
+out:
        if (err) {
                mmc_sdio_remove(host);
 
@@ -562,6 +568,9 @@ static void mmc_sdio_detect(struct mmc_host *host)
                mmc_detach_bus(host);
                mmc_release_host(host);
        }
+
+       /* Tell PM core that we're done */
+       pm_runtime_put(&host->card->dev);
 }
 
 /*
@@ -614,14 +623,6 @@ static int mmc_sdio_resume(struct mmc_host *host)
        mmc_claim_host(host);
        err = mmc_sdio_init_card(host, host->ocr, host->card,
                                 (host->pm_flags & MMC_PM_KEEP_POWER));
-       if (!err) {
-               /* We may have switched to 1-bit mode during suspend. */
-               err = sdio_enable_4bit_bus(host->card);
-               if (err > 0) {
-                       mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
-                       err = 0;
-               }
-       }
        if (!err && host->sdio_irqs)
                mmc_signal_sdio_irq(host);
        mmc_release_host(host);
@@ -647,11 +648,29 @@ static int mmc_sdio_resume(struct mmc_host *host)
        return err;
 }
 
+static int mmc_sdio_power_restore(struct mmc_host *host)
+{
+       int ret;
+
+       BUG_ON(!host);
+       BUG_ON(!host->card);
+
+       mmc_claim_host(host);
+       ret = mmc_sdio_init_card(host, host->ocr, host->card,
+                       (host->pm_flags & MMC_PM_KEEP_POWER));
+       if (!ret && host->sdio_irqs)
+               mmc_signal_sdio_irq(host);
+       mmc_release_host(host);
+
+       return ret;
+}
+
 static const struct mmc_bus_ops mmc_sdio_ops = {
        .remove = mmc_sdio_remove,
        .detect = mmc_sdio_detect,
        .suspend = mmc_sdio_suspend,
        .resume = mmc_sdio_resume,
+       .power_restore = mmc_sdio_power_restore,
 };
 
 
@@ -698,6 +717,18 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
                goto err;
        card = host->card;
 
+       /*
+        * Let runtime PM core know our card is active
+        */
+       err = pm_runtime_set_active(&card->dev);
+       if (err)
+               goto remove;
+
+       /*
+        * Enable runtime PM for this card
+        */
+       pm_runtime_enable(&card->dev);
+
        /*
         * The number of functions on the card is encoded inside
         * the ocr.
@@ -712,6 +743,11 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
                err = sdio_init_func(host->card, i + 1);
                if (err)
                        goto remove;
+
+               /*
+                * Enable Runtime PM for this func
+                */
+               pm_runtime_enable(&card->sdio_func[i]->dev);
        }
 
        mmc_release_host(host);
index 4a890dc..2716c7a 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/sdio_func.h>
@@ -125,21 +126,46 @@ static int sdio_bus_probe(struct device *dev)
        if (!id)
                return -ENODEV;
 
+       /* Unbound SDIO functions are always suspended.
+        * During probe, the function is set active and the usage count
+        * is incremented.  If the driver supports runtime PM,
+        * it should call pm_runtime_put_noidle() in its probe routine and
+        * pm_runtime_get_noresume() in its remove routine.
+        */
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0)
+               goto out;
+
        /* Set the default block size so the driver is sure it's something
         * sensible. */
        sdio_claim_host(func);
        ret = sdio_set_block_size(func, 0);
        sdio_release_host(func);
        if (ret)
-               return ret;
+               goto disable_runtimepm;
+
+       ret = drv->probe(func, id);
+       if (ret)
+               goto disable_runtimepm;
 
-       return drv->probe(func, id);
+       return 0;
+
+disable_runtimepm:
+       pm_runtime_put_noidle(dev);
+out:
+       return ret;
 }
 
 static int sdio_bus_remove(struct device *dev)
 {
        struct sdio_driver *drv = to_sdio_driver(dev->driver);
        struct sdio_func *func = dev_to_sdio_func(dev);
+       int ret;
+
+       /* Make sure card is powered before invoking ->remove() */
+       ret = pm_runtime_get_sync(dev);
+       if (ret < 0)
+               goto out;
 
        drv->remove(func);
 
@@ -151,9 +177,63 @@ static int sdio_bus_remove(struct device *dev)
                sdio_release_host(func);
        }
 
+       /* First, undo the increment made directly above */
+       pm_runtime_put_noidle(dev);
+
+       /* Then undo the runtime PM settings in sdio_bus_probe() */
+       pm_runtime_put_noidle(dev);
+
+out:
+       return ret;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+
+static int sdio_bus_pm_prepare(struct device *dev)
+{
+       /*
+        * Resume an SDIO device which was suspended at run time at this
+        * point, in order to allow standard SDIO suspend/resume paths
+        * to keep working as usual.
+        *
+        * Ultimately, the SDIO driver itself will decide (in its
+        * suspend handler, or lack thereof) whether the card should be
+        * removed or kept, and if kept, at what power state.
+        *
+        * At this point, PM core have increased our use count, so it's
+        * safe to directly resume the device. After system is resumed
+        * again, PM core will drop back its runtime PM use count, and if
+        * needed device will be suspended again.
+        *
+        * The end result is guaranteed to be a power state that is
+        * coherent with the device's runtime PM use count.
+        *
+        * The return value of pm_runtime_resume is deliberately unchecked
+        * since there is little point in failing system suspend if a
+        * device can't be resumed.
+        */
+       pm_runtime_resume(dev);
+
        return 0;
 }
 
+static const struct dev_pm_ops sdio_bus_pm_ops = {
+       SET_RUNTIME_PM_OPS(
+               pm_generic_runtime_suspend,
+               pm_generic_runtime_resume,
+               pm_generic_runtime_idle
+       )
+       .prepare = sdio_bus_pm_prepare,
+};
+
+#define SDIO_PM_OPS_PTR        (&sdio_bus_pm_ops)
+
+#else /* !CONFIG_PM_RUNTIME */
+
+#define SDIO_PM_OPS_PTR        NULL
+
+#endif /* !CONFIG_PM_RUNTIME */
+
 static struct bus_type sdio_bus_type = {
        .name           = "sdio",
        .dev_attrs      = sdio_dev_attrs,
@@ -161,6 +241,7 @@ static struct bus_type sdio_bus_type = {
        .uevent         = sdio_bus_uevent,
        .probe          = sdio_bus_probe,
        .remove         = sdio_bus_remove,
+       .pm             = SDIO_PM_OPS_PTR,
 };
 
 int sdio_register_bus(void)
index 1a02611..d618e86 100644 (file)
@@ -130,6 +130,16 @@ config MMC_SDHCI_CNS3XXX
 
          If unsure, say N.
 
+config MMC_SDHCI_ESDHC_IMX
+       bool "SDHCI platform support for the Freescale eSDHC i.MX controller"
+       depends on MMC_SDHCI_PLTFM && (ARCH_MX25 || ARCH_MX35 || ARCH_MX5)
+       select MMC_SDHCI_IO_ACCESSORS
+       help
+         This selects the Freescale eSDHC controller support on the platform
+         bus, found on platforms like mx35/51.
+
+         If unsure, say N.
+
 config MMC_SDHCI_S3C
        tristate "SDHCI support on Samsung S3C SoC"
        depends on MMC_SDHCI && PLAT_SAMSUNG
@@ -145,6 +155,18 @@ config MMC_SDHCI_S3C
 
          If unsure, say N.
 
+config MMC_SDHCI_PXA
+       tristate "Marvell PXA168/PXA910/MMP2 SD Host Controller support"
+       depends on ARCH_PXA || ARCH_MMP
+       select MMC_SDHCI
+       select MMC_SDHCI_IO_ACCESSORS
+       help
+         This selects the Marvell(R) PXA168/PXA910/MMP2 SD Host Controller.
+         If you have a PXA168/PXA910/MMP2 platform with SD Host Controller
+         and a card slot, say Y or M here.
+
+         If unsure, say N.
+
 config MMC_SDHCI_SPEAR
        tristate "SDHCI support on ST SPEAr platform"
        depends on MMC_SDHCI && PLAT_SPEAR
@@ -395,6 +417,7 @@ config MMC_TMIO
 config MMC_CB710
        tristate "ENE CB710 MMC/SD Interface support"
        depends on PCI
+       select MISC_DEVICES
        select CB710_CORE
        help
          This option enables support for MMC/SD part of ENE CB710/720 Flash
@@ -451,3 +474,17 @@ config MMC_JZ4740
          SoCs.
          If you have a board based on such a SoC and with a SD/MMC slot,
          say Y or M here.
+
+config MMC_USHC
+       tristate "USB SD Host Controller (USHC) support"
+       depends on USB
+       help
+         This selects support for USB SD Host Controllers based on
+         the Cypress Astoria chip with firmware compliant with CSR's
+         USB SD Host Controller specification (CS-118793-SP).
+
+         CSR boards with this device include: USB<>SDIO (M1985v2),
+         and Ultrasira.
+
+         Note: These controllers only support SDIO cards and do not
+         support MMC or SD memory cards.
index 840bcb5..7b645ff 100644 (file)
@@ -2,16 +2,13 @@
 # Makefile for MMC/SD host controller drivers
 #
 
-ifeq ($(CONFIG_MMC_DEBUG),y)
-       EXTRA_CFLAGS            += -DDEBUG
-endif
-
 obj-$(CONFIG_MMC_ARMMMCI)      += mmci.o
 obj-$(CONFIG_MMC_PXA)          += pxamci.o
 obj-$(CONFIG_MMC_IMX)          += imxmmc.o
 obj-$(CONFIG_MMC_MXC)          += mxcmmc.o
 obj-$(CONFIG_MMC_SDHCI)                += sdhci.o
 obj-$(CONFIG_MMC_SDHCI_PCI)    += sdhci-pci.o
+obj-$(CONFIG_MMC_SDHCI_PXA)    += sdhci-pxa.o
 obj-$(CONFIG_MMC_SDHCI_S3C)    += sdhci-s3c.o
 obj-$(CONFIG_MMC_SDHCI_SPEAR)  += sdhci-spear.o
 obj-$(CONFIG_MMC_WBSD)         += wbsd.o
@@ -36,10 +33,12 @@ obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
 obj-$(CONFIG_SDH_BFIN)         += bfin_sdh.o
 obj-$(CONFIG_MMC_SH_MMCIF)     += sh_mmcif.o
 obj-$(CONFIG_MMC_JZ4740)       += jz4740_mmc.o
+obj-$(CONFIG_MMC_USHC)         += ushc.o
 
 obj-$(CONFIG_MMC_SDHCI_PLTFM)                  += sdhci-platform.o
 sdhci-platform-y                               := sdhci-pltfm.o
 sdhci-platform-$(CONFIG_MMC_SDHCI_CNS3XXX)     += sdhci-cns3xxx.o
+sdhci-platform-$(CONFIG_MMC_SDHCI_ESDHC_IMX)   += sdhci-esdhc-imx.o
 
 obj-$(CONFIG_MMC_SDHCI_OF)     += sdhci-of.o
 sdhci-of-y                             := sdhci-of-core.o
index 87226cd..591ab54 100644 (file)
@@ -928,7 +928,7 @@ static int __init at91_mci_probe(struct platform_device *pdev)
        if (!res)
                return -ENXIO;
 
-       if (!request_mem_region(res->start, res->end - res->start + 1, DRIVER_NAME))
+       if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME))
                return -EBUSY;
 
        mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
@@ -947,8 +947,7 @@ static int __init at91_mci_probe(struct platform_device *pdev)
        mmc->max_blk_size  = MCI_MAXBLKSIZE;
        mmc->max_blk_count = MCI_BLKATONCE;
        mmc->max_req_size  = MCI_BUFSIZE;
-       mmc->max_phys_segs = MCI_BLKATONCE;
-       mmc->max_hw_segs   = MCI_BLKATONCE;
+       mmc->max_segs      = MCI_BLKATONCE;
        mmc->max_seg_size  = MCI_BUFSIZE;
 
        host = mmc_priv(mmc);
@@ -1017,7 +1016,7 @@ static int __init at91_mci_probe(struct platform_device *pdev)
        /*
         * Map I/O region
         */
-       host->baseaddr = ioremap(res->start, res->end - res->start + 1);
+       host->baseaddr = ioremap(res->start, resource_size(res));
        if (!host->baseaddr) {
                ret = -ENOMEM;
                goto fail1;
@@ -1093,7 +1092,7 @@ fail4b:
 fail5:
        mmc_free_host(mmc);
 fail6:
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
        dev_err(&pdev->dev, "probe failed, err %d\n", ret);
        return ret;
 }
@@ -1138,7 +1137,7 @@ static int __exit at91_mci_remove(struct platform_device *pdev)
 
        iounmap(host->baseaddr);
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
 
        mmc_free_host(mmc);
        platform_set_drvdata(pdev, NULL);
index 95ef864..301351a 100644 (file)
@@ -1618,8 +1618,7 @@ static int __init atmci_init_slot(struct atmel_mci *host,
        if (slot_data->bus_width >= 4)
                mmc->caps |= MMC_CAP_4_BIT_DATA;
 
-       mmc->max_hw_segs = 64;
-       mmc->max_phys_segs = 64;
+       mmc->max_segs = 64;
        mmc->max_req_size = 32768 * 512;
        mmc->max_blk_size = 32768;
        mmc->max_blk_count = 512;
@@ -1777,7 +1776,7 @@ static int __init atmci_probe(struct platform_device *pdev)
        }
 
        ret = -ENOMEM;
-       host->regs = ioremap(regs->start, regs->end - regs->start + 1);
+       host->regs = ioremap(regs->start, resource_size(regs));
        if (!host->regs)
                goto err_ioremap;
 
index c8da5d3..41e5a60 100644 (file)
@@ -964,7 +964,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
                goto out1;
        }
 
-       host->ioarea = request_mem_region(r->start, r->end - r->start + 1,
+       host->ioarea = request_mem_region(r->start, resource_size(r),
                                           pdev->name);
        if (!host->ioarea) {
                dev_err(&pdev->dev, "mmio already in use\n");
@@ -998,7 +998,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
        mmc->f_max = 24000000;
 
        mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
-       mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
+       mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT;
 
        mmc->max_blk_size = 2048;
        mmc->max_blk_count = 512;
index 4b0e677..bac7d62 100644 (file)
@@ -469,7 +469,7 @@ static int __devinit sdh_probe(struct platform_device *pdev)
        }
 
        mmc->ops = &sdh_ops;
-       mmc->max_phys_segs = 32;
+       mmc->max_segs = 32;
        mmc->max_seg_size = 1 << 16;
        mmc->max_blk_size = 1 << 11;
        mmc->max_blk_count = 1 << 11;
index ca3bdc8..66b4ce5 100644 (file)
@@ -25,7 +25,7 @@ static const u8 cb710_src_freq_mhz[16] = {
        50, 55, 60, 65, 70, 75, 80, 85
 };
 
-static void cb710_mmc_set_clock(struct mmc_host *mmc, int hz)
+static void cb710_mmc_select_clock_divider(struct mmc_host *mmc, int hz)
 {
        struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
        struct pci_dev *pdev = cb710_slot_to_chip(slot)->pdev;
@@ -33,8 +33,11 @@ static void cb710_mmc_set_clock(struct mmc_host *mmc, int hz)
        u32 divider_idx;
        int src_hz;
 
-       /* this is magic, unverifiable for me, unless I get
-        * MMC card with cables connected to bus signals */
+       /* on CB710 in HP nx9500:
+        *   src_freq_idx == 0
+        *   indexes 1-7 work as written in the table
+        *   indexes 0,8-15 give no clock output
+        */
        pci_read_config_dword(pdev, 0x48, &src_freq_idx);
        src_freq_idx = (src_freq_idx >> 16) & 0xF;
        src_hz = cb710_src_freq_mhz[src_freq_idx] * 1000000;
@@ -46,13 +49,15 @@ static void cb710_mmc_set_clock(struct mmc_host *mmc, int hz)
 
        if (src_freq_idx)
                divider_idx |= 0x8;
+       else if (divider_idx == 0)
+               divider_idx = 1;
 
        cb710_pci_update_config_reg(pdev, 0x40, ~0xF0000000, divider_idx << 28);
 
        dev_dbg(cb710_slot_dev(slot),
-               "clock set to %d Hz, wanted %d Hz; flag = %d\n",
+               "clock set to %d Hz, wanted %d Hz; src_freq_idx = %d, divider_idx = %d|%d\n",
                src_hz >> cb710_clock_divider_log2[divider_idx & 7],
-               hz, (divider_idx & 8) != 0);
+               hz, src_freq_idx, divider_idx & 7, divider_idx & 8);
 }
 
 static void __cb710_mmc_enable_irq(struct cb710_slot *slot,
@@ -95,16 +100,8 @@ static void cb710_mmc_reset_events(struct cb710_slot *slot)
        cb710_write_port_8(slot, CB710_MMC_STATUS2_PORT, 0xFF);
 }
 
-static int cb710_mmc_is_card_inserted(struct cb710_slot *slot)
-{
-       return cb710_read_port_8(slot, CB710_MMC_STATUS3_PORT)
-               & CB710_MMC_S3_CARD_DETECTED;
-}
-
 static void cb710_mmc_enable_4bit_data(struct cb710_slot *slot, int enable)
 {
-       dev_dbg(cb710_slot_dev(slot), "configuring %d-data-line%s mode\n",
-               enable ? 4 : 1, enable ? "s" : "");
        if (enable)
                cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT,
                        CB710_MMC_C1_4BIT_DATA_BUS, 0);
@@ -494,13 +491,8 @@ static void cb710_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
        reader->mrq = mrq;
        cb710_mmc_enable_irq(slot, CB710_MMC_IE_TEST_MASK, 0);
 
-       if (cb710_mmc_is_card_inserted(slot)) {
-               if (!cb710_mmc_command(mmc, mrq->cmd) && mrq->stop)
-                       cb710_mmc_command(mmc, mrq->stop);
-               mdelay(1);
-       } else {
-               mrq->cmd->error = -ENOMEDIUM;
-       }
+       if (!cb710_mmc_command(mmc, mrq->cmd) && mrq->stop)
+               cb710_mmc_command(mmc, mrq->stop);
 
        tasklet_schedule(&reader->finish_req_tasklet);
 }
@@ -512,7 +504,7 @@ static int cb710_mmc_powerup(struct cb710_slot *slot)
 #endif
        int err;
 
-       /* a lot of magic; see comment in cb710_mmc_set_clock() */
+       /* a lot of magic for now */
        dev_dbg(cb710_slot_dev(slot), "bus powerup\n");
        cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
        err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
@@ -572,13 +564,7 @@ static void cb710_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        struct cb710_mmc_reader *reader = mmc_priv(mmc);
        int err;
 
-       cb710_mmc_set_clock(mmc, ios->clock);
-
-       if (!cb710_mmc_is_card_inserted(slot)) {
-               dev_dbg(cb710_slot_dev(slot),
-                       "no card inserted - ignoring bus powerup request\n");
-               ios->power_mode = MMC_POWER_OFF;
-       }
+       cb710_mmc_select_clock_divider(mmc, ios->clock);
 
        if (ios->power_mode != reader->last_power_mode)
        switch (ios->power_mode) {
@@ -619,6 +605,14 @@ static int cb710_mmc_get_ro(struct mmc_host *mmc)
                & CB710_MMC_S3_WRITE_PROTECTED;
 }
 
+static int cb710_mmc_get_cd(struct mmc_host *mmc)
+{
+       struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
+
+       return cb710_read_port_8(slot, CB710_MMC_STATUS3_PORT)
+               & CB710_MMC_S3_CARD_DETECTED;
+}
+
 static int cb710_mmc_irq_handler(struct cb710_slot *slot)
 {
        struct mmc_host *mmc = cb710_slot_to_mmc(slot);
@@ -664,7 +658,8 @@ static void cb710_mmc_finish_request_tasklet(unsigned long data)
 static const struct mmc_host_ops cb710_mmc_host = {
        .request = cb710_mmc_request,
        .set_ios = cb710_mmc_set_ios,
-       .get_ro = cb710_mmc_get_ro
+       .get_ro = cb710_mmc_get_ro,
+       .get_cd = cb710_mmc_get_cd,
 };
 
 #ifdef CONFIG_PM
@@ -746,6 +741,7 @@ static int __devinit cb710_mmc_init(struct platform_device *pdev)
 err_free_mmc:
        dev_dbg(cb710_slot_dev(slot), "mmc_add_host() failed: %d\n", err);
 
+       cb710_set_irq_handler(slot, NULL);
        mmc_free_host(mmc);
        return err;
 }
index 33d9f1b..e15547c 100644 (file)
 /*
  * One scatterlist dma "segment" is at most MAX_CCNT rw_threshold units,
  * and we handle up to MAX_NR_SG segments.  MMC_BLOCK_BOUNCE kicks in only
- * for drivers with max_hw_segs == 1, making the segments bigger (64KB)
+ * for drivers with max_segs == 1, making the segments bigger (64KB)
  * than the page or two that's otherwise typical. nr_sg (passed from
  * platform data) == 16 gives at least the same throughput boost, using
  * EDMA transfer linkage instead of spending CPU time copying pages.
@@ -1239,8 +1239,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
         * Each hw_seg uses one EDMA parameter RAM slot, always one
         * channel and then usually some linked slots.
         */
-       mmc->max_hw_segs        = 1 + host->n_link;
-       mmc->max_phys_segs      = mmc->max_hw_segs;
+       mmc->max_segs           = 1 + host->n_link;
 
        /* EDMA limit per hw segment (one or two MBytes) */
        mmc->max_seg_size       = MAX_CCNT * rw_threshold;
@@ -1250,8 +1249,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
        mmc->max_blk_count      = 65535; /* NBLK is 16 bits */
        mmc->max_req_size       = mmc->max_blk_size * mmc->max_blk_count;
 
-       dev_dbg(mmc_dev(host->mmc), "max_phys_segs=%d\n", mmc->max_phys_segs);
-       dev_dbg(mmc_dev(host->mmc), "max_hw_segs=%d\n", mmc->max_hw_segs);
+       dev_dbg(mmc_dev(host->mmc), "max_segs=%d\n", mmc->max_segs);
        dev_dbg(mmc_dev(host->mmc), "max_blk_size=%d\n", mmc->max_blk_size);
        dev_dbg(mmc_dev(host->mmc), "max_req_size=%d\n", mmc->max_req_size);
        dev_dbg(mmc_dev(host->mmc), "max_seg_size=%d\n", mmc->max_seg_size);
index 5a950b1..881f7ba 100644 (file)
@@ -966,8 +966,7 @@ static int __init imxmci_probe(struct platform_device *pdev)
        mmc->caps = MMC_CAP_4_BIT_DATA;
 
        /* MMC core transfer sizes tunable parameters */
-       mmc->max_hw_segs = 64;
-       mmc->max_phys_segs = 64;
+       mmc->max_segs = 64;
        mmc->max_seg_size = 64*512;     /* default PAGE_CACHE_SIZE */
        mmc->max_req_size = 64*512;     /* default PAGE_CACHE_SIZE */
        mmc->max_blk_size = 2048;
index ad4f987..b3a0ab0 100644 (file)
@@ -876,8 +876,7 @@ static int __devinit jz4740_mmc_probe(struct platform_device* pdev)
        mmc->max_blk_count = (1 << 15) - 1;
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
 
-       mmc->max_phys_segs = 128;
-       mmc->max_hw_segs = 128;
+       mmc->max_segs = 128;
        mmc->max_seg_size = mmc->max_req_size;
 
        host->mmc = mmc;
index 62a3582..fd877f6 100644 (file)
@@ -1055,6 +1055,8 @@ static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq)
 {
        struct mmc_spi_host     *host = mmc_priv(mmc);
        int                     status = -EINVAL;
+       int                     crc_retry = 5;
+       struct mmc_command      stop;
 
 #ifdef DEBUG
        /* MMC core and layered drivers *MUST* issue SPI-aware commands */
@@ -1087,10 +1089,29 @@ static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq)
        /* request exclusive bus access */
        spi_bus_lock(host->spi->master);
 
+crc_recover:
        /* issue command; then optionally data and stop */
        status = mmc_spi_command_send(host, mrq, mrq->cmd, mrq->data != NULL);
        if (status == 0 && mrq->data) {
                mmc_spi_data_do(host, mrq->cmd, mrq->data, mrq->data->blksz);
+
+               /*
+                * The SPI bus is not always reliable for large data transfers.
+                * If an occasional crc error is reported by the SD device with
+                * data read/write over SPI, it may be recovered by repeating
+                * the last SD command again. The retry count is set to 5 to
+                * ensure the driver passes stress tests.
+                */
+               if (mrq->data->error == -EILSEQ && crc_retry) {
+                       stop.opcode = MMC_STOP_TRANSMISSION;
+                       stop.arg = 0;
+                       stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+                       status = mmc_spi_command_send(host, mrq, &stop, 0);
+                       crc_retry--;
+                       mrq->data->error = 0;
+                       goto crc_recover;
+               }
+
                if (mrq->stop)
                        status = mmc_spi_command_send(host, mrq, mrq->stop, 0);
                else
@@ -1345,8 +1366,7 @@ static int mmc_spi_probe(struct spi_device *spi)
 
        mmc->ops = &mmc_spi_ops;
        mmc->max_blk_size = MMC_SPI_BLOCKSIZE;
-       mmc->max_hw_segs = MMC_SPI_BLOCKSATONCE;
-       mmc->max_phys_segs = MMC_SPI_BLOCKSATONCE;
+       mmc->max_segs = MMC_SPI_BLOCKSATONCE;
        mmc->max_req_size = MMC_SPI_BLOCKSATONCE * MMC_SPI_BLOCKSIZE;
        mmc->max_blk_count = MMC_SPI_BLOCKSATONCE;
 
index f2e02d7..87b4fc6 100644 (file)
@@ -523,19 +523,27 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        struct mmci_host *host = mmc_priv(mmc);
        u32 pwr = 0;
        unsigned long flags;
+       int ret;
 
        switch (ios->power_mode) {
        case MMC_POWER_OFF:
-               if(host->vcc &&
-                  regulator_is_enabled(host->vcc))
-                       regulator_disable(host->vcc);
+               if (host->vcc)
+                       ret = mmc_regulator_set_ocr(mmc, host->vcc, 0);
                break;
        case MMC_POWER_UP:
-#ifdef CONFIG_REGULATOR
-               if (host->vcc)
-                       /* This implicitly enables the regulator */
-                       mmc_regulator_set_ocr(host->vcc, ios->vdd);
-#endif
+               if (host->vcc) {
+                       ret = mmc_regulator_set_ocr(mmc, host->vcc, ios->vdd);
+                       if (ret) {
+                               dev_err(mmc_dev(mmc), "unable to set OCR\n");
+                               /*
+                                * The .set_ios() function in the mmc_host_ops
+                                * struct return void, and failing to set the
+                                * power should be rare so we print an error
+                                * and return here.
+                                */
+                               return;
+                       }
+               }
                if (host->plat->vdd_handler)
                        pwr |= host->plat->vdd_handler(mmc_dev(mmc), ios->vdd,
                                                       ios->power_mode);
@@ -734,8 +742,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
        /*
         * We can do SGIO
         */
-       mmc->max_hw_segs = 16;
-       mmc->max_phys_segs = NR_SG;
+       mmc->max_segs = NR_SG;
 
        /*
         * Since only a certain number of bits are valid in the data length
@@ -870,8 +877,8 @@ static int __devexit mmci_remove(struct amba_device *dev)
                clk_disable(host->clk);
                clk_put(host->clk);
 
-               if (regulator_is_enabled(host->vcc))
-                       regulator_disable(host->vcc);
+               if (host->vcc)
+                       mmc_regulator_set_ocr(mmc, host->vcc, 0);
                regulator_put(host->vcc);
 
                mmc_free_host(mmc);
index ff77523..1290d14 100644 (file)
@@ -1164,8 +1164,7 @@ msmsdcc_probe(struct platform_device *pdev)
                mmc->caps |= MMC_CAP_SDIO_IRQ;
        mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
 
-       mmc->max_phys_segs = NR_SG;
-       mmc->max_hw_segs = NR_SG;
+       mmc->max_segs = NR_SG;
        mmc->max_blk_size = 4096;       /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
        mmc->max_blk_count = 65536;
 
index 366eefa..a5bf60e 100644 (file)
@@ -742,8 +742,7 @@ static int __init mvsd_probe(struct platform_device *pdev)
        mmc->max_blk_size = 2048;
        mmc->max_blk_count = 65535;
 
-       mmc->max_hw_segs = 1;
-       mmc->max_phys_segs = 1;
+       mmc->max_segs = 1;
        mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count;
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
 
index 350f78e..bdd2cbb 100644 (file)
@@ -790,8 +790,7 @@ static int mxcmci_probe(struct platform_device *pdev)
        mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
 
        /* MMC core transfer sizes tunable parameters */
-       mmc->max_hw_segs = 64;
-       mmc->max_phys_segs = 64;
+       mmc->max_segs = 64;
        mmc->max_blk_size = 2048;
        mmc->max_blk_count = 65535;
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
index d98ddcf..0c7e37f 100644 (file)
@@ -1335,8 +1335,7 @@ static int __init mmc_omap_new_slot(struct mmc_omap_host *host, int id)
         * NOTE max_seg_size assumption that small blocks aren't
         * normally used (except e.g. for reading SD registers).
         */
-       mmc->max_phys_segs = 32;
-       mmc->max_hw_segs = 32;
+       mmc->max_segs = 32;
        mmc->max_blk_size = 2048;       /* BLEN is 11 bits (+1) */
        mmc->max_blk_count = 2048;      /* NBLK is 11 bits (+1) */
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
index 4693e62..e865032 100644 (file)
@@ -250,9 +250,9 @@ static int omap_hsmmc_1_set_power(struct device *dev, int slot, int power_on,
                mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
 
        if (power_on)
-               ret = mmc_regulator_set_ocr(host->vcc, vdd);
+               ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
        else
-               ret = mmc_regulator_set_ocr(host->vcc, 0);
+               ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
 
        if (mmc_slot(host).after_set_reg)
                mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
@@ -291,18 +291,23 @@ static int omap_hsmmc_23_set_power(struct device *dev, int slot, int power_on,
         * chips/cards need an interface voltage rail too.
         */
        if (power_on) {
-               ret = mmc_regulator_set_ocr(host->vcc, vdd);
+               ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
                /* Enable interface voltage rail, if needed */
                if (ret == 0 && host->vcc_aux) {
                        ret = regulator_enable(host->vcc_aux);
                        if (ret < 0)
-                               ret = mmc_regulator_set_ocr(host->vcc, 0);
+                               ret = mmc_regulator_set_ocr(host->mmc,
+                                                       host->vcc, 0);
                }
        } else {
+               /* Shut down the rail */
                if (host->vcc_aux)
                        ret = regulator_disable(host->vcc_aux);
-               if (ret == 0)
-                       ret = mmc_regulator_set_ocr(host->vcc, 0);
+               if (!ret) {
+                       /* Then proceed to shut down the local regulator */
+                       ret = mmc_regulator_set_ocr(host->mmc,
+                                               host->vcc, 0);
+               }
        }
 
        if (mmc_slot(host).after_set_reg)
@@ -343,9 +348,9 @@ static int omap_hsmmc_23_set_sleep(struct device *dev, int slot, int sleep,
        if (cardsleep) {
                /* VCC can be turned off if card is asleep */
                if (sleep)
-                       err = mmc_regulator_set_ocr(host->vcc, 0);
+                       err = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
                else
-                       err = mmc_regulator_set_ocr(host->vcc, vdd);
+                       err = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
        } else
                err = regulator_set_mode(host->vcc, mode);
        if (err)
@@ -2130,8 +2135,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
 
        /* Since we do only SG emulation, we can have as many segs
         * as we want. */
-       mmc->max_phys_segs = 1024;
-       mmc->max_hw_segs = 1024;
+       mmc->max_segs = 1024;
 
        mmc->max_blk_size = 512;       /* Block Length at max can be 1024 */
        mmc->max_blk_count = 0xFFFF;    /* No. of Blocks is 16 bits */
index 0a4e43f..7257738 100644 (file)
@@ -99,14 +99,25 @@ static inline void pxamci_init_ocr(struct pxamci_host *host)
        }
 }
 
-static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd)
+static inline int pxamci_set_power(struct pxamci_host *host,
+                                   unsigned char power_mode,
+                                   unsigned int vdd)
 {
        int on;
 
-#ifdef CONFIG_REGULATOR
-       if (host->vcc)
-               mmc_regulator_set_ocr(host->vcc, vdd);
-#endif
+       if (host->vcc) {
+               int ret;
+
+               if (power_mode == MMC_POWER_UP) {
+                       ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
+                       if (ret)
+                               return ret;
+               } else if (power_mode == MMC_POWER_OFF) {
+                       ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
+                       if (ret)
+                               return ret;
+               }
+       }
        if (!host->vcc && host->pdata &&
            gpio_is_valid(host->pdata->gpio_power)) {
                on = ((1 << vdd) & host->pdata->ocr_mask);
@@ -115,6 +126,8 @@ static inline void pxamci_set_power(struct pxamci_host *host, unsigned int vdd)
        }
        if (!host->vcc && host->pdata && host->pdata->setpower)
                host->pdata->setpower(mmc_dev(host->mmc), vdd);
+
+       return 0;
 }
 
 static void pxamci_stop_clock(struct pxamci_host *host)
@@ -490,9 +503,21 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        }
 
        if (host->power_mode != ios->power_mode) {
+               int ret;
+
                host->power_mode = ios->power_mode;
 
-               pxamci_set_power(host, ios->vdd);
+               ret = pxamci_set_power(host, ios->power_mode, ios->vdd);
+               if (ret) {
+                       dev_err(mmc_dev(mmc), "unable to set power\n");
+                       /*
+                        * The .set_ios() function in the mmc_host_ops
+                        * struct return void, and failing to set the
+                        * power should be rare so we print an error and
+                        * return here.
+                        */
+                       return;
+               }
 
                if (ios->power_mode == MMC_POWER_ON)
                        host->cmdat |= CMDAT_INIT;
@@ -503,8 +528,8 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        else
                host->cmdat &= ~CMDAT_SD_4DAT;
 
-       pr_debug("PXAMCI: clkrt = %x cmdat = %x\n",
-                host->clkrt, host->cmdat);
+       dev_dbg(mmc_dev(mmc), "PXAMCI: clkrt = %x cmdat = %x\n",
+               host->clkrt, host->cmdat);
 }
 
 static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable)
@@ -576,7 +601,7 @@ static int pxamci_probe(struct platform_device *pdev)
         * We can do SG-DMA, but we don't because we never know how much
         * data we successfully wrote to the card.
         */
-       mmc->max_phys_segs = NR_SG;
+       mmc->max_segs = NR_SG;
 
        /*
         * Our hardware DMA can handle a maximum of one page per SG entry.
index 976330d..1ccd4b2 100644 (file)
@@ -1736,8 +1736,7 @@ static int __devinit s3cmci_probe(struct platform_device *pdev)
        mmc->max_req_size       = 4095 * 512;
        mmc->max_seg_size       = mmc->max_req_size;
 
-       mmc->max_phys_segs      = 128;
-       mmc->max_hw_segs        = 128;
+       mmc->max_segs           = 128;
 
        dbg(host, dbg_debug,
            "probe: mode:%s mapped mci_base:%p irq:%u irq_cd:%u dma:%u.\n",
index b7050b3..9ebd1d7 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/mmc/host.h>
-#include <linux/sdhci-pltfm.h>
+#include <linux/mmc/sdhci-pltfm.h>
 #include <mach/cns3xxx.h>
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
new file mode 100644 (file)
index 0000000..2e9cca1
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Freescale eSDHC i.MX controller driver for the platform bus.
+ *
+ * derived from the OF-version.
+ *
+ * Copyright (c) 2010 Pengutronix e.K.
+ *   Author: Wolfram Sang <w.sang@pengutronix.de>
+ *
+ * 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.
+ */
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sdhci-pltfm.h>
+#include "sdhci.h"
+#include "sdhci-pltfm.h"
+#include "sdhci-esdhc.h"
+
+static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg)
+{
+       void __iomem *base = host->ioaddr + (reg & ~0x3);
+       u32 shift = (reg & 0x3) * 8;
+
+       writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
+}
+
+static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
+{
+       if (unlikely(reg == SDHCI_HOST_VERSION))
+               reg ^= 2;
+
+       return readw(host->ioaddr + reg);
+}
+
+static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+       switch (reg) {
+       case SDHCI_TRANSFER_MODE:
+               /*
+                * Postpone this write, we must do it together with a
+                * command write that is down below.
+                */
+               pltfm_host->scratchpad = val;
+               return;
+       case SDHCI_COMMAND:
+               writel(val << 16 | pltfm_host->scratchpad,
+                       host->ioaddr + SDHCI_TRANSFER_MODE);
+               return;
+       case SDHCI_BLOCK_SIZE:
+               val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
+               break;
+       }
+       esdhc_clrset_le(host, 0xffff, val, reg);
+}
+
+static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
+{
+       u32 new_val;
+
+       switch (reg) {
+       case SDHCI_POWER_CONTROL:
+               /*
+                * FSL put some DMA bits here
+                * If your board has a regulator, code should be here
+                */
+               return;
+       case SDHCI_HOST_CONTROL:
+               /* FSL messed up here, so we can just keep those two */
+               new_val = val & (SDHCI_CTRL_LED | SDHCI_CTRL_4BITBUS);
+               /* ensure the endianess */
+               new_val |= ESDHC_HOST_CONTROL_LE;
+               /* DMA mode bits are shifted */
+               new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5;
+
+               esdhc_clrset_le(host, 0xffff, new_val, reg);
+               return;
+       }
+       esdhc_clrset_le(host, 0xff, val, reg);
+}
+
+static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+       return clk_get_rate(pltfm_host->clk);
+}
+
+static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+       return clk_get_rate(pltfm_host->clk) / 256 / 16;
+}
+
+static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pdata)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct clk *clk;
+
+       clk = clk_get(mmc_dev(host->mmc), NULL);
+       if (IS_ERR(clk)) {
+               dev_err(mmc_dev(host->mmc), "clk err\n");
+               return PTR_ERR(clk);
+       }
+       clk_enable(clk);
+       pltfm_host->clk = clk;
+
+       return 0;
+}
+
+static void esdhc_pltfm_exit(struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+       clk_disable(pltfm_host->clk);
+       clk_put(pltfm_host->clk);
+}
+
+static struct sdhci_ops sdhci_esdhc_ops = {
+       .read_w = esdhc_readw_le,
+       .write_w = esdhc_writew_le,
+       .write_b = esdhc_writeb_le,
+       .set_clock = esdhc_set_clock,
+       .get_max_clock = esdhc_pltfm_get_max_clock,
+       .get_min_clock = esdhc_pltfm_get_min_clock,
+};
+
+struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
+       .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_MULTIBLOCK
+                       | SDHCI_QUIRK_BROKEN_ADMA,
+       /* ADMA has issues. Might be fixable */
+       /* NO_MULTIBLOCK might be MX35 only (Errata: ENGcm07207) */
+       .ops = &sdhci_esdhc_ops,
+       .init = esdhc_pltfm_init,
+       .exit = esdhc_pltfm_exit,
+};
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
new file mode 100644 (file)
index 0000000..afaf1bc
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Freescale eSDHC controller driver generics for OF and pltfm.
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ * Copyright (c) 2009 MontaVista Software, Inc.
+ * Copyright (c) 2010 Pengutronix e.K.
+ *   Author: Wolfram Sang <w.sang@pengutronix.de>
+ *
+ * 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.
+ */
+
+#ifndef _DRIVERS_MMC_SDHCI_ESDHC_H
+#define _DRIVERS_MMC_SDHCI_ESDHC_H
+
+/*
+ * Ops and quirks for the Freescale eSDHC controller.
+ */
+
+#define ESDHC_DEFAULT_QUIRKS   (SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \
+                               SDHCI_QUIRK_BROKEN_CARD_DETECTION | \
+                               SDHCI_QUIRK_NO_BUSY_IRQ | \
+                               SDHCI_QUIRK_NONSTANDARD_CLOCK | \
+                               SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \
+                               SDHCI_QUIRK_PIO_NEEDS_DELAY | \
+                               SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET | \
+                               SDHCI_QUIRK_NO_CARD_NO_RESET)
+
+#define ESDHC_SYSTEM_CONTROL   0x2c
+#define ESDHC_CLOCK_MASK       0x0000fff0
+#define ESDHC_PREDIV_SHIFT     8
+#define ESDHC_DIVIDER_SHIFT    4
+#define ESDHC_CLOCK_PEREN      0x00000004
+#define ESDHC_CLOCK_HCKEN      0x00000002
+#define ESDHC_CLOCK_IPGEN      0x00000001
+
+/* pltfm-specific */
+#define ESDHC_HOST_CONTROL_LE  0x20
+
+/* OF-specific */
+#define ESDHC_DMA_SYSCTL       0x40c
+#define ESDHC_DMA_SNOOP                0x00000040
+
+#define ESDHC_HOST_CONTROL_RES 0x05
+
+static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+       int pre_div = 2;
+       int div = 1;
+       u32 temp;
+
+       temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+       temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
+               | ESDHC_CLOCK_MASK);
+       sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+
+       if (clock == 0)
+               goto out;
+
+       while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
+               pre_div *= 2;
+
+       while (host->max_clk / pre_div / div > clock && div < 16)
+               div++;
+
+       dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
+               clock, host->max_clk / pre_div / div);
+
+       pre_div >>= 1;
+       div--;
+
+       temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+       temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
+               | (div << ESDHC_DIVIDER_SHIFT)
+               | (pre_div << ESDHC_PREDIV_SHIFT));
+       sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+       mdelay(100);
+out:
+       host->clock = clock;
+}
+
+#endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */
index c8623de..fcd0e1f 100644 (file)
 #include <linux/mmc/host.h>
 #include "sdhci-of.h"
 #include "sdhci.h"
-
-/*
- * Ops and quirks for the Freescale eSDHC controller.
- */
-
-#define ESDHC_DMA_SYSCTL       0x40c
-#define ESDHC_DMA_SNOOP                0x00000040
-
-#define ESDHC_SYSTEM_CONTROL   0x2c
-#define ESDHC_CLOCK_MASK       0x0000fff0
-#define ESDHC_PREDIV_SHIFT     8
-#define ESDHC_DIVIDER_SHIFT    4
-#define ESDHC_CLOCK_PEREN      0x00000004
-#define ESDHC_CLOCK_HCKEN      0x00000002
-#define ESDHC_CLOCK_IPGEN      0x00000001
-
-#define ESDHC_HOST_CONTROL_RES 0x05
+#include "sdhci-esdhc.h"
 
 static u16 esdhc_readw(struct sdhci_host *host, int reg)
 {
@@ -68,51 +52,20 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
        sdhci_be32bs_writeb(host, val, reg);
 }
 
-static void esdhc_set_clock(struct sdhci_host *host, unsigned int clock)
-{
-       int pre_div = 2;
-       int div = 1;
-
-       clrbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN |
-                 ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN | ESDHC_CLOCK_MASK);
-
-       if (clock == 0)
-               goto out;
-
-       while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
-               pre_div *= 2;
-
-       while (host->max_clk / pre_div / div > clock && div < 16)
-               div++;
-
-       dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
-               clock, host->max_clk / pre_div / div);
-
-       pre_div >>= 1;
-       div--;
-
-       setbits32(host->ioaddr + ESDHC_SYSTEM_CONTROL, ESDHC_CLOCK_IPGEN |
-                 ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN |
-                 div << ESDHC_DIVIDER_SHIFT | pre_div << ESDHC_PREDIV_SHIFT);
-       mdelay(100);
-out:
-       host->clock = clock;
-}
-
-static int esdhc_enable_dma(struct sdhci_host *host)
+static int esdhc_of_enable_dma(struct sdhci_host *host)
 {
        setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
        return 0;
 }
 
-static unsigned int esdhc_get_max_clock(struct sdhci_host *host)
+static unsigned int esdhc_of_get_max_clock(struct sdhci_host *host)
 {
        struct sdhci_of_host *of_host = sdhci_priv(host);
 
        return of_host->clock;
 }
 
-static unsigned int esdhc_get_min_clock(struct sdhci_host *host)
+static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
 {
        struct sdhci_of_host *of_host = sdhci_priv(host);
 
@@ -120,14 +73,7 @@ static unsigned int esdhc_get_min_clock(struct sdhci_host *host)
 }
 
 struct sdhci_of_data sdhci_esdhc = {
-       .quirks = SDHCI_QUIRK_FORCE_BLK_SZ_2048 |
-                 SDHCI_QUIRK_BROKEN_CARD_DETECTION |
-                 SDHCI_QUIRK_NO_BUSY_IRQ |
-                 SDHCI_QUIRK_NONSTANDARD_CLOCK |
-                 SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
-                 SDHCI_QUIRK_PIO_NEEDS_DELAY |
-                 SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET |
-                 SDHCI_QUIRK_NO_CARD_NO_RESET,
+       .quirks = ESDHC_DEFAULT_QUIRKS,
        .ops = {
                .read_l = sdhci_be32bs_readl,
                .read_w = esdhc_readw,
@@ -136,8 +82,8 @@ struct sdhci_of_data sdhci_esdhc = {
                .write_w = esdhc_writew,
                .write_b = esdhc_writeb,
                .set_clock = esdhc_set_clock,
-               .enable_dma = esdhc_enable_dma,
-               .get_max_clock = esdhc_get_max_clock,
-               .get_min_clock = esdhc_get_min_clock,
+               .enable_dma = esdhc_of_enable_dma,
+               .get_max_clock = esdhc_of_get_max_clock,
+               .get_min_clock = esdhc_of_get_min_clock,
        },
 };
index e8aa99d..55746ba 100644 (file)
@@ -145,6 +145,37 @@ static const struct sdhci_pci_fixes sdhci_cafe = {
                          SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
 };
 
+/*
+ * ADMA operation is disabled for Moorestown platform due to
+ * hardware bugs.
+ */
+static int mrst_hc1_probe(struct sdhci_pci_chip *chip)
+{
+       /*
+        * slots number is fixed here for MRST as SDIO3 is never used and has
+        * hardware bugs.
+        */
+       chip->num_slots = 1;
+       return 0;
+}
+
+static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = {
+       .quirks         = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT,
+};
+
+static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1 = {
+       .quirks         = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT,
+       .probe          = mrst_hc1_probe,
+};
+
+static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = {
+       .quirks         = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+};
+
+static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc_sdio = {
+       .quirks         = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+};
+
 static int jmicron_pmos(struct sdhci_pci_chip *chip, int on)
 {
        u8 scratch;
@@ -494,6 +525,62 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
                .driver_data    = (kernel_ulong_t)&sdhci_via,
        },
 
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_MRST_SD0,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_mrst_hc0,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_MRST_SD1,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_mrst_hc1,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_MFD_SD,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_mfd_sd,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_MFD_SDIO1,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_MFD_SDIO2,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_MFD_EMMC0,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_MFD_EMMC1,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_intel_mfd_emmc_sdio,
+       },
+
        {       /* Generic SD host controller */
                PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
        },
@@ -818,6 +905,8 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
                        goto free;
        }
 
+       slots = chip->num_slots;        /* Quirk may have changed this */
+
        for (i = 0;i < slots;i++) {
                slot = sdhci_pci_probe_slot(pdev, chip, first_bar + i);
                if (IS_ERR(slot)) {
index e045e3c..0502f89 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/mmc/host.h>
 
 #include <linux/io.h>
-#include <linux/sdhci-pltfm.h>
+#include <linux/mmc/sdhci-pltfm.h>
 
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
@@ -52,14 +52,17 @@ static struct sdhci_ops sdhci_pltfm_ops = {
 
 static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
 {
-       struct sdhci_pltfm_data *pdata = pdev->dev.platform_data;
        const struct platform_device_id *platid = platform_get_device_id(pdev);
+       struct sdhci_pltfm_data *pdata;
        struct sdhci_host *host;
+       struct sdhci_pltfm_host *pltfm_host;
        struct resource *iomem;
        int ret;
 
-       if (!pdata && platid && platid->driver_data)
+       if (platid && platid->driver_data)
                pdata = (void *)platid->driver_data;
+       else
+               pdata = pdev->dev.platform_data;
 
        iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!iomem) {
@@ -71,16 +74,19 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "Invalid iomem size. You may "
                        "experience problems.\n");
 
-       if (pdev->dev.parent)
-               host = sdhci_alloc_host(pdev->dev.parent, 0);
+       /* Some PCI-based MFD need the parent here */
+       if (pdev->dev.parent != &platform_bus)
+               host = sdhci_alloc_host(pdev->dev.parent, sizeof(*pltfm_host));
        else
-               host = sdhci_alloc_host(&pdev->dev, 0);
+               host = sdhci_alloc_host(&pdev->dev, sizeof(*pltfm_host));
 
        if (IS_ERR(host)) {
                ret = PTR_ERR(host);
                goto err;
        }
 
+       pltfm_host = sdhci_priv(host);
+
        host->hw_name = "platform";
        if (pdata && pdata->ops)
                host->ops = pdata->ops;
@@ -105,7 +111,7 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev)
        }
 
        if (pdata && pdata->init) {
-               ret = pdata->init(host);
+               ret = pdata->init(host, pdata);
                if (ret)
                        goto err_plat_init;
        }
@@ -160,11 +166,33 @@ static const struct platform_device_id sdhci_pltfm_ids[] = {
        { "sdhci", },
 #ifdef CONFIG_MMC_SDHCI_CNS3XXX
        { "sdhci-cns3xxx", (kernel_ulong_t)&sdhci_cns3xxx_pdata },
+#endif
+#ifdef CONFIG_MMC_SDHCI_ESDHC_IMX
+       { "sdhci-esdhc-imx", (kernel_ulong_t)&sdhci_esdhc_imx_pdata },
 #endif
        { },
 };
 MODULE_DEVICE_TABLE(platform, sdhci_pltfm_ids);
 
+#ifdef CONFIG_PM
+static int sdhci_pltfm_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct sdhci_host *host = platform_get_drvdata(dev);
+
+       return sdhci_suspend_host(host, state);
+}
+
+static int sdhci_pltfm_resume(struct platform_device *dev)
+{
+       struct sdhci_host *host = platform_get_drvdata(dev);
+
+       return sdhci_resume_host(host);
+}
+#else
+#define sdhci_pltfm_suspend    NULL
+#define sdhci_pltfm_resume     NULL
+#endif /* CONFIG_PM */
+
 static struct platform_driver sdhci_pltfm_driver = {
        .driver = {
                .name   = "sdhci",
@@ -173,6 +201,8 @@ static struct platform_driver sdhci_pltfm_driver = {
        .probe          = sdhci_pltfm_probe,
        .remove         = __devexit_p(sdhci_pltfm_remove),
        .id_table       = sdhci_pltfm_ids,
+       .suspend        = sdhci_pltfm_suspend,
+       .resume         = sdhci_pltfm_resume,
 };
 
 /*****************************************************************************\
index 900f329..c1bfe48 100644 (file)
 #ifndef _DRIVERS_MMC_SDHCI_PLTFM_H
 #define _DRIVERS_MMC_SDHCI_PLTFM_H
 
-#include <linux/sdhci-pltfm.h>
+#include <linux/clk.h>
+#include <linux/types.h>
+#include <linux/mmc/sdhci-pltfm.h>
+
+struct sdhci_pltfm_host {
+       struct clk *clk;
+       u32 scratchpad; /* to handle quirks across io-accessor calls */
+};
 
 extern struct sdhci_pltfm_data sdhci_cns3xxx_pdata;
+extern struct sdhci_pltfm_data sdhci_esdhc_imx_pdata;
 
 #endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */
diff --git a/drivers/mmc/host/sdhci-pxa.c b/drivers/mmc/host/sdhci-pxa.c
new file mode 100644 (file)
index 0000000..fc406ac
--- /dev/null
@@ -0,0 +1,253 @@
+/* linux/drivers/mmc/host/sdhci-pxa.c
+ *
+ * Copyright (C) 2010 Marvell International Ltd.
+ *             Zhangfei Gao <zhangfei.gao@marvell.com>
+ *             Kevin Wang <dwang4@marvell.com>
+ *             Mingwei Wang <mwwang@marvell.com>
+ *             Philip Rakity <prakity@marvell.com>
+ *             Mark Brown <markb@marvell.com>
+ *
+ * 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.
+ */
+
+/* Supports:
+ * SDHCI support for MMP2/PXA910/PXA168
+ *
+ * Refer to sdhci-s3c.c.
+ */
+
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/mmc/host.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <plat/sdhci.h>
+#include "sdhci.h"
+
+#define DRIVER_NAME    "sdhci-pxa"
+
+#define SD_FIFO_PARAM          0x104
+#define DIS_PAD_SD_CLK_GATE    0x400
+
+struct sdhci_pxa {
+       struct sdhci_host               *host;
+       struct sdhci_pxa_platdata       *pdata;
+       struct clk                      *clk;
+       struct resource                 *res;
+
+       u8 clk_enable;
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * SDHCI core callbacks                                                      *
+ *                                                                           *
+\*****************************************************************************/
+static void set_clock(struct sdhci_host *host, unsigned int clock)
+{
+       struct sdhci_pxa *pxa = sdhci_priv(host);
+       u32 tmp = 0;
+
+       if (clock == 0) {
+               if (pxa->clk_enable) {
+                       clk_disable(pxa->clk);
+                       pxa->clk_enable = 0;
+               }
+       } else {
+               if (0 == pxa->clk_enable) {
+                       if (pxa->pdata->flags & PXA_FLAG_DISABLE_CLOCK_GATING) {
+                               tmp = readl(host->ioaddr + SD_FIFO_PARAM);
+                               tmp |= DIS_PAD_SD_CLK_GATE;
+                               writel(tmp, host->ioaddr + SD_FIFO_PARAM);
+                       }
+                       clk_enable(pxa->clk);
+                       pxa->clk_enable = 1;
+               }
+       }
+}
+
+static struct sdhci_ops sdhci_pxa_ops = {
+       .set_clock = set_clock,
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Device probing/removal                                                    *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __devinit sdhci_pxa_probe(struct platform_device *pdev)
+{
+       struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
+       struct device *dev = &pdev->dev;
+       struct sdhci_host *host = NULL;
+       struct resource *iomem = NULL;
+       struct sdhci_pxa *pxa = NULL;
+       int ret, irq;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(dev, "no irq specified\n");
+               return irq;
+       }
+
+       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!iomem) {
+               dev_err(dev, "no memory specified\n");
+               return -ENOENT;
+       }
+
+       host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pxa));
+       if (IS_ERR(host)) {
+               dev_err(dev, "failed to alloc host\n");
+               return PTR_ERR(host);
+       }
+
+       pxa = sdhci_priv(host);
+       pxa->host = host;
+       pxa->pdata = pdata;
+       pxa->clk_enable = 0;
+
+       pxa->clk = clk_get(dev, "PXA-SDHCLK");
+       if (IS_ERR(pxa->clk)) {
+               dev_err(dev, "failed to get io clock\n");
+               ret = PTR_ERR(pxa->clk);
+               goto out;
+       }
+
+       pxa->res = request_mem_region(iomem->start, resource_size(iomem),
+                                     mmc_hostname(host->mmc));
+       if (!pxa->res) {
+               dev_err(&pdev->dev, "cannot request region\n");
+               ret = -EBUSY;
+               goto out;
+       }
+
+       host->ioaddr = ioremap(iomem->start, resource_size(iomem));
+       if (!host->ioaddr) {
+               dev_err(&pdev->dev, "failed to remap registers\n");
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       host->hw_name = "MMC";
+       host->ops = &sdhci_pxa_ops;
+       host->irq = irq;
+       host->quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+
+       if (pdata->quirks)
+               host->quirks |= pdata->quirks;
+
+       ret = sdhci_add_host(host);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to add host\n");
+               goto out;
+       }
+
+       if (pxa->pdata->max_speed)
+               host->mmc->f_max = pxa->pdata->max_speed;
+
+       platform_set_drvdata(pdev, host);
+
+       return 0;
+out:
+       if (host) {
+               clk_put(pxa->clk);
+               if (host->ioaddr)
+                       iounmap(host->ioaddr);
+               if (pxa->res)
+                       release_mem_region(pxa->res->start,
+                                          resource_size(pxa->res));
+               sdhci_free_host(host);
+       }
+
+       return ret;
+}
+
+static int __devexit sdhci_pxa_remove(struct platform_device *pdev)
+{
+       struct sdhci_host *host = platform_get_drvdata(pdev);
+       struct sdhci_pxa *pxa = sdhci_priv(host);
+       int dead = 0;
+       u32 scratch;
+
+       if (host) {
+               scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
+               if (scratch == (u32)-1)
+                       dead = 1;
+
+               sdhci_remove_host(host, dead);
+
+               if (host->ioaddr)
+                       iounmap(host->ioaddr);
+               if (pxa->res)
+                       release_mem_region(pxa->res->start,
+                                          resource_size(pxa->res));
+               if (pxa->clk_enable) {
+                       clk_disable(pxa->clk);
+                       pxa->clk_enable = 0;
+               }
+               clk_put(pxa->clk);
+
+               sdhci_free_host(host);
+               platform_set_drvdata(pdev, NULL);
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int sdhci_pxa_suspend(struct platform_device *dev, pm_message_t state)
+{
+       struct sdhci_host *host = platform_get_drvdata(dev);
+
+       return sdhci_suspend_host(host, state);
+}
+
+static int sdhci_pxa_resume(struct platform_device *dev)
+{
+       struct sdhci_host *host = platform_get_drvdata(dev);
+
+       return sdhci_resume_host(host);
+}
+#else
+#define sdhci_pxa_suspend      NULL
+#define sdhci_pxa_resume       NULL
+#endif
+
+static struct platform_driver sdhci_pxa_driver = {
+       .probe          = sdhci_pxa_probe,
+       .remove         = __devexit_p(sdhci_pxa_remove),
+       .suspend        = sdhci_pxa_suspend,
+       .resume         = sdhci_pxa_resume,
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Driver init/exit                                                          *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __init sdhci_pxa_init(void)
+{
+       return platform_driver_register(&sdhci_pxa_driver);
+}
+
+static void __exit sdhci_pxa_exit(void)
+{
+       platform_driver_unregister(&sdhci_pxa_driver);
+}
+
+module_init(sdhci_pxa_init);
+module_exit(sdhci_pxa_exit);
+
+MODULE_DESCRIPTION("SDH controller driver for PXA168/PXA910/MMP2");
+MODULE_AUTHOR("Zhangfei Gao <zhangfei.gao@marvell.com>");
+MODULE_LICENSE("GPL v2");
index 401527d..782c0ee 100644 (file)
@@ -47,7 +47,8 @@ static void sdhci_finish_command(struct sdhci_host *);
 
 static void sdhci_dumpregs(struct sdhci_host *host)
 {
-       printk(KERN_DEBUG DRIVER_NAME ": ============== REGISTER DUMP ==============\n");
+       printk(KERN_DEBUG DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n",
+               mmc_hostname(host->mmc));
 
        printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n",
                sdhci_readl(host, SDHCI_DMA_ADDRESS),
@@ -1001,13 +1002,28 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
        if (clock == 0)
                goto out;
 
-       for (div = 1;div < 256;div *= 2) {
-               if ((host->max_clk / div) <= clock)
-                       break;
+       if (host->version >= SDHCI_SPEC_300) {
+               /* Version 3.00 divisors must be a multiple of 2. */
+               if (host->max_clk <= clock)
+                       div = 1;
+               else {
+                       for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) {
+                               if ((host->max_clk / div) <= clock)
+                                       break;
+                       }
+               }
+       } else {
+               /* Version 2.00 divisors must be a power of 2. */
+               for (div = 1; div < SDHCI_MAX_DIV_SPEC_200; div *= 2) {
+                       if ((host->max_clk / div) <= clock)
+                               break;
+               }
        }
        div >>= 1;
 
-       clk = div << SDHCI_DIVIDER_SHIFT;
+       clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
+       clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
+               << SDHCI_DIVIDER_HI_SHIFT;
        clk |= SDHCI_CLOCK_INT_EN;
        sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
@@ -1034,11 +1050,9 @@ out:
 
 static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
 {
-       u8 pwr;
+       u8 pwr = 0;
 
-       if (power == (unsigned short)-1)
-               pwr = 0;
-       else {
+       if (power != (unsigned short)-1) {
                switch (1 << power) {
                case MMC_VDD_165_195:
                        pwr = SDHCI_POWER_180;
@@ -1168,6 +1182,9 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        else
                sdhci_set_power(host, ios->vdd);
 
+       if (host->ops->platform_send_init_74_clocks)
+               host->ops->platform_send_init_74_clocks(host, ios->power_mode);
+
        ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
 
        if (ios->bus_width == MMC_BUS_WIDTH_8)
@@ -1180,8 +1197,9 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        else
                ctrl &= ~SDHCI_CTRL_4BITBUS;
 
-       if (ios->timing == MMC_TIMING_SD_HS &&
-           !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT))
+       if ((ios->timing == MMC_TIMING_SD_HS ||
+            ios->timing == MMC_TIMING_MMC_HS)
+           && !(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT))
                ctrl |= SDHCI_CTRL_HISPD;
        else
                ctrl &= ~SDHCI_CTRL_HISPD;
@@ -1205,22 +1223,25 @@ static int sdhci_get_ro(struct mmc_host *mmc)
 {
        struct sdhci_host *host;
        unsigned long flags;
-       int present;
+       int is_readonly;
 
        host = mmc_priv(mmc);
 
        spin_lock_irqsave(&host->lock, flags);
 
        if (host->flags & SDHCI_DEVICE_DEAD)
-               present = 0;
+               is_readonly = 0;
+       else if (host->ops->get_ro)
+               is_readonly = host->ops->get_ro(host);
        else
-               present = sdhci_readl(host, SDHCI_PRESENT_STATE);
+               is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE)
+                               & SDHCI_WRITE_PROTECT);
 
        spin_unlock_irqrestore(&host->lock, flags);
 
-       if (host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT)
-               return !!(present & SDHCI_WRITE_PROTECT);
-       return !(present & SDHCI_WRITE_PROTECT);
+       /* This quirk needs to be replaced by a callback-function later */
+       return host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT ?
+               !is_readonly : is_readonly;
 }
 
 static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
@@ -1427,7 +1448,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
                sdhci_finish_command(host);
 }
 
-#ifdef DEBUG
+#ifdef CONFIG_MMC_DEBUG
 static void sdhci_show_adma_error(struct sdhci_host *host)
 {
        const char *name = mmc_hostname(host->mmc);
@@ -1708,7 +1729,7 @@ int sdhci_add_host(struct sdhci_host *host)
        host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
        host->version = (host->version & SDHCI_SPEC_VER_MASK)
                                >> SDHCI_SPEC_VER_SHIFT;
-       if (host->version > SDHCI_SPEC_200) {
+       if (host->version > SDHCI_SPEC_300) {
                printk(KERN_ERR "%s: Unknown controller version (%d). "
                        "You may experience problems.\n", mmc_hostname(mmc),
                        host->version);
@@ -1779,8 +1800,13 @@ int sdhci_add_host(struct sdhci_host *host)
                mmc_dev(host->mmc)->dma_mask = &host->dma_mask;
        }
 
-       host->max_clk =
-               (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
+       if (host->version >= SDHCI_SPEC_300)
+               host->max_clk = (caps & SDHCI_CLOCK_V3_BASE_MASK)
+                       >> SDHCI_CLOCK_BASE_SHIFT;
+       else
+               host->max_clk = (caps & SDHCI_CLOCK_BASE_MASK)
+                       >> SDHCI_CLOCK_BASE_SHIFT;
+
        host->max_clk *= 1000000;
        if (host->max_clk == 0 || host->quirks &
                        SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) {
@@ -1815,18 +1841,21 @@ int sdhci_add_host(struct sdhci_host *host)
        mmc->ops = &sdhci_ops;
        if (host->ops->get_min_clock)
                mmc->f_min = host->ops->get_min_clock(host);
+       else if (host->version >= SDHCI_SPEC_300)
+               mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
        else
-               mmc->f_min = host->max_clk / 256;
+               mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
        mmc->f_max = host->max_clk;
        mmc->caps |= MMC_CAP_SDIO_IRQ;
 
        if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
-               mmc->caps |= MMC_CAP_4_BIT_DATA;
+               mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
 
        if (caps & SDHCI_CAN_DO_HISPD)
-               mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+               mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
 
-       if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
+       if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
+           mmc_card_is_removable(mmc))
                mmc->caps |= MMC_CAP_NEEDS_POLL;
 
        mmc->ocr_avail = 0;
@@ -1850,12 +1879,11 @@ int sdhci_add_host(struct sdhci_host *host)
         * can do scatter/gather or not.
         */
        if (host->flags & SDHCI_USE_ADMA)
-               mmc->max_hw_segs = 128;
+               mmc->max_segs = 128;
        else if (host->flags & SDHCI_USE_SDMA)
-               mmc->max_hw_segs = 1;
+               mmc->max_segs = 1;
        else /* PIO */
-               mmc->max_hw_segs = 128;
-       mmc->max_phys_segs = 128;
+               mmc->max_segs = 128;
 
        /*
         * Maximum number of sectors in one transfer. Limited by DMA boundary
index d316bc7..b7b8a3b 100644 (file)
@@ -1,6 +1,8 @@
 /*
  *  linux/drivers/mmc/host/sdhci.h - Secure Digital Host Controller Interface driver
  *
+ * Header file for Host Controller registers and I/O accessors.
+ *
  *  Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * the Free Software Foundation; either version 2 of the License, or (at
  * your option) any later version.
  */
-#ifndef __SDHCI_H
-#define __SDHCI_H
+#ifndef __SDHCI_HW_H
+#define __SDHCI_HW_H
 
 #include <linux/scatterlist.h>
 #include <linux/compiler.h>
 #include <linux/types.h>
 #include <linux/io.h>
 
+#include <linux/mmc/sdhci.h>
+
 /*
  * Controller registers
  */
 
 #define SDHCI_CLOCK_CONTROL    0x2C
 #define  SDHCI_DIVIDER_SHIFT   8
+#define  SDHCI_DIVIDER_HI_SHIFT        6
+#define  SDHCI_DIV_MASK        0xFF
+#define  SDHCI_DIV_MASK_LEN    8
+#define  SDHCI_DIV_HI_MASK     0x300
 #define  SDHCI_CLOCK_CARD_EN   0x0004
 #define  SDHCI_CLOCK_INT_STABLE        0x0002
 #define  SDHCI_CLOCK_INT_EN    0x0001
 #define  SDHCI_TIMEOUT_CLK_SHIFT 0
 #define  SDHCI_TIMEOUT_CLK_UNIT        0x00000080
 #define  SDHCI_CLOCK_BASE_MASK 0x00003F00
+#define  SDHCI_CLOCK_V3_BASE_MASK      0x0000FF00
 #define  SDHCI_CLOCK_BASE_SHIFT        8
 #define  SDHCI_MAX_BLOCK_MASK  0x00030000
 #define  SDHCI_MAX_BLOCK_SHIFT  16
 #define  SDHCI_SPEC_VER_SHIFT  0
 #define   SDHCI_SPEC_100       0
 #define   SDHCI_SPEC_200       1
+#define   SDHCI_SPEC_300       2
 
-struct sdhci_ops;
-
-struct sdhci_host {
-       /* Data set by hardware interface driver */
-       const char              *hw_name;       /* Hardware bus name */
-
-       unsigned int            quirks;         /* Deviations from spec. */
-
-/* Controller doesn't honor resets unless we touch the clock register */
-#define SDHCI_QUIRK_CLOCK_BEFORE_RESET                 (1<<0)
-/* Controller has bad caps bits, but really supports DMA */
-#define SDHCI_QUIRK_FORCE_DMA                          (1<<1)
-/* Controller doesn't like to be reset when there is no card inserted. */
-#define SDHCI_QUIRK_NO_CARD_NO_RESET                   (1<<2)
-/* Controller doesn't like clearing the power reg before a change */
-#define SDHCI_QUIRK_SINGLE_POWER_WRITE                 (1<<3)
-/* Controller has flaky internal state so reset it on each ios change */
-#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS              (1<<4)
-/* Controller has an unusable DMA engine */
-#define SDHCI_QUIRK_BROKEN_DMA                         (1<<5)
-/* Controller has an unusable ADMA engine */
-#define SDHCI_QUIRK_BROKEN_ADMA                                (1<<6)
-/* Controller can only DMA from 32-bit aligned addresses */
-#define SDHCI_QUIRK_32BIT_DMA_ADDR                     (1<<7)
-/* Controller can only DMA chunk sizes that are a multiple of 32 bits */
-#define SDHCI_QUIRK_32BIT_DMA_SIZE                     (1<<8)
-/* Controller can only ADMA chunks that are a multiple of 32 bits */
-#define SDHCI_QUIRK_32BIT_ADMA_SIZE                    (1<<9)
-/* Controller needs to be reset after each request to stay stable */
-#define SDHCI_QUIRK_RESET_AFTER_REQUEST                        (1<<10)
-/* Controller needs voltage and power writes to happen separately */
-#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER            (1<<11)
-/* Controller provides an incorrect timeout value for transfers */
-#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL                 (1<<12)
-/* Controller has an issue with buffer bits for small transfers */
-#define SDHCI_QUIRK_BROKEN_SMALL_PIO                   (1<<13)
-/* Controller does not provide transfer-complete interrupt when not busy */
-#define SDHCI_QUIRK_NO_BUSY_IRQ                                (1<<14)
-/* Controller has unreliable card detection */
-#define SDHCI_QUIRK_BROKEN_CARD_DETECTION              (1<<15)
-/* Controller reports inverted write-protect state */
-#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT             (1<<16)
-/* Controller has nonstandard clock management */
-#define SDHCI_QUIRK_NONSTANDARD_CLOCK                  (1<<17)
-/* Controller does not like fast PIO transfers */
-#define SDHCI_QUIRK_PIO_NEEDS_DELAY                    (1<<18)
-/* Controller losing signal/interrupt enable states after reset */
-#define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET           (1<<19)
-/* Controller has to be forced to use block size of 2048 bytes */
-#define SDHCI_QUIRK_FORCE_BLK_SZ_2048                  (1<<20)
-/* Controller cannot do multi-block transfers */
-#define SDHCI_QUIRK_NO_MULTIBLOCK                      (1<<21)
-/* Controller can only handle 1-bit data transfers */
-#define SDHCI_QUIRK_FORCE_1_BIT_DATA                   (1<<22)
-/* Controller needs 10ms delay between applying power and clock */
-#define SDHCI_QUIRK_DELAY_AFTER_POWER                  (1<<23)
-/* Controller uses SDCLK instead of TMCLK for data timeouts */
-#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK            (1<<24)
-/* Controller reports wrong base clock capability */
-#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN              (1<<25)
-/* Controller cannot support End Attribute in NOP ADMA descriptor */
-#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC              (1<<26)
-/* Controller is missing device caps. Use caps provided by host */
-#define SDHCI_QUIRK_MISSING_CAPS                       (1<<27)
-/* Controller uses Auto CMD12 command to stop the transfer */
-#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12             (1<<28)
-/* Controller doesn't have HISPD bit field in HI-SPEED SD card */
-#define SDHCI_QUIRK_NO_HISPD_BIT                       (1<<29)
-
-       int                     irq;            /* Device IRQ */
-       void __iomem *          ioaddr;         /* Mapped address */
-
-       const struct sdhci_ops  *ops;           /* Low level hw interface */
-
-       struct regulator        *vmmc;          /* Power regulator */
-
-       /* Internal data */
-       struct mmc_host         *mmc;           /* MMC structure */
-       u64                     dma_mask;       /* custom DMA mask */
-
-#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
-       struct led_classdev     led;            /* LED control */
-       char   led_name[32];
-#endif
-
-       spinlock_t              lock;           /* Mutex */
-
-       int                     flags;          /* Host attributes */
-#define SDHCI_USE_SDMA         (1<<0)          /* Host is SDMA capable */
-#define SDHCI_USE_ADMA         (1<<1)          /* Host is ADMA capable */
-#define SDHCI_REQ_USE_DMA      (1<<2)          /* Use DMA for this req. */
-#define SDHCI_DEVICE_DEAD      (1<<3)          /* Device unresponsive */
-
-       unsigned int            version;        /* SDHCI spec. version */
-
-       unsigned int            max_clk;        /* Max possible freq (MHz) */
-       unsigned int            timeout_clk;    /* Timeout freq (KHz) */
-
-       unsigned int            clock;          /* Current clock (MHz) */
-       u8                      pwr;            /* Current voltage */
-
-       struct mmc_request      *mrq;           /* Current request */
-       struct mmc_command      *cmd;           /* Current command */
-       struct mmc_data         *data;          /* Current data request */
-       unsigned int            data_early:1;   /* Data finished before cmd */
-
-       struct sg_mapping_iter  sg_miter;       /* SG state for PIO */
-       unsigned int            blocks;         /* remaining PIO blocks */
-
-       int                     sg_count;       /* Mapped sg entries */
-
-       u8                      *adma_desc;     /* ADMA descriptor table */
-       u8                      *align_buffer;  /* Bounce buffer */
-
-       dma_addr_t              adma_addr;      /* Mapped ADMA descr. table */
-       dma_addr_t              align_addr;     /* Mapped bounce buffer */
-
-       struct tasklet_struct   card_tasklet;   /* Tasklet structures */
-       struct tasklet_struct   finish_tasklet;
-
-       struct timer_list       timer;          /* Timer for timeouts */
-
-       unsigned int            caps;           /* Alternative capabilities */
-
-       unsigned long           private[0] ____cacheline_aligned;
-};
+/*
+ * End of controller registers.
+ */
 
+#define SDHCI_MAX_DIV_SPEC_200 256
+#define SDHCI_MAX_DIV_SPEC_300 2046
 
 struct sdhci_ops {
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
@@ -323,6 +212,9 @@ struct sdhci_ops {
        unsigned int    (*get_max_clock)(struct sdhci_host *host);
        unsigned int    (*get_min_clock)(struct sdhci_host *host);
        unsigned int    (*get_timeout_clock)(struct sdhci_host *host);
+       void (*platform_send_init_74_clocks)(struct sdhci_host *host,
+                                            u8 power_mode);
+       unsigned int    (*get_ro)(struct sdhci_host *host);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
@@ -427,4 +319,4 @@ extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state);
 extern int sdhci_resume_host(struct sdhci_host *host);
 #endif
 
-#endif /* __SDHCI_H */
+#endif /* __SDHCI_HW_H */
index 5d3f824..0f06b80 100644 (file)
@@ -846,8 +846,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
        mmc->caps = MMC_CAP_MMC_HIGHSPEED;
        if (pd->caps)
                mmc->caps |= pd->caps;
-       mmc->max_phys_segs = 128;
-       mmc->max_hw_segs = 128;
+       mmc->max_segs = 128;
        mmc->max_blk_size = 512;
        mmc->max_blk_count = 65535;
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
index cec9995..457c26e 100644 (file)
@@ -978,11 +978,10 @@ static int tifm_sd_probe(struct tifm_dev *sock)
        mmc->f_max = 24000000;
 
        mmc->max_blk_count = 2048;
-       mmc->max_hw_segs = mmc->max_blk_count;
+       mmc->max_segs = mmc->max_blk_count;
        mmc->max_blk_size = min(TIFM_MMCSD_MAX_BLOCK_SIZE, PAGE_SIZE);
        mmc->max_seg_size = mmc->max_blk_count * mmc->max_blk_size;
        mmc->max_req_size = mmc->max_seg_size;
-       mmc->max_phys_segs = mmc->max_hw_segs;
 
        sock->card_event = tifm_sd_card_event;
        sock->data_event = tifm_sd_data_event;
diff --git a/drivers/mmc/host/ushc.c b/drivers/mmc/host/ushc.c
new file mode 100644 (file)
index 0000000..b4ead4a
--- /dev/null
@@ -0,0 +1,566 @@
+/*
+ * USB SD Host Controller (USHC) controller driver.
+ *
+ * Copyright (C) 2010 Cambridge Silicon Radio Ltd.
+ *
+ * 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.
+ *
+ * Notes:
+ *   - Only version 2 devices are supported.
+ *   - Version 2 devices only support SDIO cards/devices (R2 response is
+ *     unsupported).
+ *
+ * References:
+ *   [USHC] USB SD Host Controller specification (CS-118793-SP)
+ */
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/mmc/host.h>
+
+enum ushc_request {
+       USHC_GET_CAPS  = 0x00,
+       USHC_HOST_CTRL = 0x01,
+       USHC_PWR_CTRL  = 0x02,
+       USHC_CLK_FREQ  = 0x03,
+       USHC_EXEC_CMD  = 0x04,
+       USHC_READ_RESP = 0x05,
+       USHC_RESET     = 0x06,
+};
+
+enum ushc_request_type {
+       USHC_GET_CAPS_TYPE  = USB_DIR_IN  | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+       USHC_HOST_CTRL_TYPE = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+       USHC_PWR_CTRL_TYPE  = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+       USHC_CLK_FREQ_TYPE  = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+       USHC_EXEC_CMD_TYPE  = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+       USHC_READ_RESP_TYPE = USB_DIR_IN  | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+       USHC_RESET_TYPE     = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+};
+
+#define USHC_GET_CAPS_VERSION_MASK 0xff
+#define USHC_GET_CAPS_3V3      (1 << 8)
+#define USHC_GET_CAPS_3V0      (1 << 9)
+#define USHC_GET_CAPS_1V8      (1 << 10)
+#define USHC_GET_CAPS_HIGH_SPD (1 << 16)
+
+#define USHC_HOST_CTRL_4BIT     (1 << 1)
+#define USHC_HOST_CTRL_HIGH_SPD (1 << 0)
+
+#define USHC_PWR_CTRL_OFF 0x00
+#define USHC_PWR_CTRL_3V3 0x01
+#define USHC_PWR_CTRL_3V0 0x02
+#define USHC_PWR_CTRL_1V8 0x03
+
+#define USHC_READ_RESP_BUSY        (1 << 4)
+#define USHC_READ_RESP_ERR_TIMEOUT (1 << 3)
+#define USHC_READ_RESP_ERR_CRC     (1 << 2)
+#define USHC_READ_RESP_ERR_DAT     (1 << 1)
+#define USHC_READ_RESP_ERR_CMD     (1 << 0)
+#define USHC_READ_RESP_ERR_MASK    0x0f
+
+struct ushc_cbw {
+       __u8 signature;
+       __u8 cmd_idx;
+       __le16 block_size;
+       __le32 arg;
+} __attribute__((packed));
+
+#define USHC_CBW_SIGNATURE 'C'
+
+struct ushc_csw {
+       __u8 signature;
+       __u8 status;
+       __le32 response;
+} __attribute__((packed));
+
+#define USHC_CSW_SIGNATURE 'S'
+
+struct ushc_int_data {
+       u8 status;
+       u8 reserved[3];
+};
+
+#define USHC_INT_STATUS_SDIO_INT     (1 << 1)
+#define USHC_INT_STATUS_CARD_PRESENT (1 << 0)
+
+
+struct ushc_data {
+       struct usb_device *usb_dev;
+       struct mmc_host *mmc;
+
+       struct urb *int_urb;
+       struct ushc_int_data *int_data;
+
+       struct urb *cbw_urb;
+       struct ushc_cbw *cbw;
+
+       struct urb *data_urb;
+
+       struct urb *csw_urb;
+       struct ushc_csw *csw;
+
+       spinlock_t lock;
+       struct mmc_request *current_req;
+       u32 caps;
+       u16 host_ctrl;
+       unsigned long flags;
+       u8 last_status;
+       int clock_freq;
+};
+
+#define DISCONNECTED    0
+#define INT_EN          1
+#define IGNORE_NEXT_INT 2
+
+static void data_callback(struct urb *urb);
+
+static int ushc_hw_reset(struct ushc_data *ushc)
+{
+       return usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
+                              USHC_RESET, USHC_RESET_TYPE,
+                              0, 0, NULL, 0, 100);
+}
+
+static int ushc_hw_get_caps(struct ushc_data *ushc)
+{
+       int ret;
+       int version;
+
+       ret = usb_control_msg(ushc->usb_dev, usb_rcvctrlpipe(ushc->usb_dev, 0),
+                             USHC_GET_CAPS, USHC_GET_CAPS_TYPE,
+                             0, 0, &ushc->caps, sizeof(ushc->caps), 100);
+       if (ret < 0)
+               return ret;
+
+       ushc->caps = le32_to_cpu(ushc->caps);
+
+       version = ushc->caps & USHC_GET_CAPS_VERSION_MASK;
+       if (version != 0x02) {
+               dev_err(&ushc->usb_dev->dev, "controller version %d is not supported\n", version);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ushc_hw_set_host_ctrl(struct ushc_data *ushc, u16 mask, u16 val)
+{
+       u16 host_ctrl;
+       int ret;
+
+       host_ctrl = (ushc->host_ctrl & ~mask) | val;
+       ret = usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
+                             USHC_HOST_CTRL, USHC_HOST_CTRL_TYPE,
+                             host_ctrl, 0, NULL, 0, 100);
+       if (ret < 0)
+               return ret;
+       ushc->host_ctrl = host_ctrl;
+       return 0;
+}
+
+static void int_callback(struct urb *urb)
+{
+       struct ushc_data *ushc = urb->context;
+       u8 status, last_status;
+
+       if (urb->status < 0)
+               return;
+
+       status = ushc->int_data->status;
+       last_status = ushc->last_status;
+       ushc->last_status = status;
+
+       /*
+        * Ignore the card interrupt status on interrupt transfers that
+        * were submitted while card interrupts where disabled.
+        *
+        * This avoid occasional spurious interrupts when enabling
+        * interrupts immediately after clearing the source on the card.
+        */
+
+       if (!test_and_clear_bit(IGNORE_NEXT_INT, &ushc->flags)
+           && test_bit(INT_EN, &ushc->flags)
+           && status & USHC_INT_STATUS_SDIO_INT) {
+               mmc_signal_sdio_irq(ushc->mmc);
+       }
+
+       if ((status ^ last_status) & USHC_INT_STATUS_CARD_PRESENT)
+               mmc_detect_change(ushc->mmc, msecs_to_jiffies(100));
+
+       if (!test_bit(INT_EN, &ushc->flags))
+               set_bit(IGNORE_NEXT_INT, &ushc->flags);
+       usb_submit_urb(ushc->int_urb, GFP_ATOMIC);
+}
+
+static void cbw_callback(struct urb *urb)
+{
+       struct ushc_data *ushc = urb->context;
+
+       if (urb->status != 0) {
+               usb_unlink_urb(ushc->data_urb);
+               usb_unlink_urb(ushc->csw_urb);
+       }
+}
+
+static void data_callback(struct urb *urb)
+{
+       struct ushc_data *ushc = urb->context;
+
+       if (urb->status != 0)
+               usb_unlink_urb(ushc->csw_urb);
+}
+
+static void csw_callback(struct urb *urb)
+{
+       struct ushc_data *ushc = urb->context;
+       struct mmc_request *req = ushc->current_req;
+       int status;
+
+       status = ushc->csw->status;
+
+       if (urb->status != 0) {
+               req->cmd->error = urb->status;
+       } else if (status & USHC_READ_RESP_ERR_CMD) {
+               if (status & USHC_READ_RESP_ERR_CRC)
+                       req->cmd->error = -EIO;
+               else
+                       req->cmd->error = -ETIMEDOUT;
+       }
+       if (req->data) {
+               if (status & USHC_READ_RESP_ERR_DAT) {
+                       if (status & USHC_READ_RESP_ERR_CRC)
+                               req->data->error = -EIO;
+                       else
+                               req->data->error = -ETIMEDOUT;
+                       req->data->bytes_xfered = 0;
+               } else {
+                       req->data->bytes_xfered = req->data->blksz * req->data->blocks;
+               }
+       }
+
+       req->cmd->resp[0] = le32_to_cpu(ushc->csw->response);
+
+       mmc_request_done(ushc->mmc, req);
+}
+
+static void ushc_request(struct mmc_host *mmc, struct mmc_request *req)
+{
+       struct ushc_data *ushc = mmc_priv(mmc);
+       int ret;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ushc->lock, flags);
+
+       if (test_bit(DISCONNECTED, &ushc->flags)) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       /* Version 2 firmware doesn't support the R2 response format. */
+       if (req->cmd->flags & MMC_RSP_136) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* The Astoria's data FIFOs don't work with clock speeds < 5MHz so
+          limit commands with data to 6MHz or more. */
+       if (req->data && ushc->clock_freq < 6000000) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ushc->current_req = req;
+
+       /* Start cmd with CBW. */
+       ushc->cbw->cmd_idx = cpu_to_le16(req->cmd->opcode);
+       if (req->data)
+               ushc->cbw->block_size = cpu_to_le16(req->data->blksz);
+       else
+               ushc->cbw->block_size = 0;
+       ushc->cbw->arg = cpu_to_le32(req->cmd->arg);
+
+       ret = usb_submit_urb(ushc->cbw_urb, GFP_ATOMIC);
+       if (ret < 0)
+               goto out;
+
+       /* Submit data (if any). */
+       if (req->data) {
+               struct mmc_data *data = req->data;
+               int pipe;
+
+               if (data->flags & MMC_DATA_READ)
+                       pipe = usb_rcvbulkpipe(ushc->usb_dev, 6);
+               else
+                       pipe = usb_sndbulkpipe(ushc->usb_dev, 2);
+
+               usb_fill_bulk_urb(ushc->data_urb, ushc->usb_dev, pipe,
+                                 sg_virt(data->sg), data->sg->length,
+                                 data_callback, ushc);
+               ret = usb_submit_urb(ushc->data_urb, GFP_ATOMIC);
+               if (ret < 0)
+                       goto out;
+       }
+
+       /* Submit CSW. */
+       ret = usb_submit_urb(ushc->csw_urb, GFP_ATOMIC);
+       if (ret < 0)
+               goto out;
+
+out:
+       spin_unlock_irqrestore(&ushc->lock, flags);
+       if (ret < 0) {
+               usb_unlink_urb(ushc->cbw_urb);
+               usb_unlink_urb(ushc->data_urb);
+               req->cmd->error = ret;
+               mmc_request_done(mmc, req);
+       }
+}
+
+static int ushc_set_power(struct ushc_data *ushc, unsigned char power_mode)
+{
+       u16 voltage;
+
+       switch (power_mode) {
+       case MMC_POWER_OFF:
+               voltage = USHC_PWR_CTRL_OFF;
+               break;
+       case MMC_POWER_UP:
+       case MMC_POWER_ON:
+               voltage = USHC_PWR_CTRL_3V3;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
+                              USHC_PWR_CTRL, USHC_PWR_CTRL_TYPE,
+                              voltage, 0, NULL, 0, 100);
+}
+
+static int ushc_set_bus_width(struct ushc_data *ushc, int bus_width)
+{
+       return ushc_hw_set_host_ctrl(ushc, USHC_HOST_CTRL_4BIT,
+                                    bus_width == 4 ? USHC_HOST_CTRL_4BIT : 0);
+}
+
+static int ushc_set_bus_freq(struct ushc_data *ushc, int clk, bool enable_hs)
+{
+       int ret;
+
+       /* Hardware can't detect interrupts while the clock is off. */
+       if (clk == 0)
+               clk = 400000;
+
+       ret = ushc_hw_set_host_ctrl(ushc, USHC_HOST_CTRL_HIGH_SPD,
+                                   enable_hs ? USHC_HOST_CTRL_HIGH_SPD : 0);
+       if (ret < 0)
+               return ret;
+
+       ret = usb_control_msg(ushc->usb_dev, usb_sndctrlpipe(ushc->usb_dev, 0),
+                             USHC_CLK_FREQ, USHC_CLK_FREQ_TYPE,
+                             clk & 0xffff, (clk >> 16) & 0xffff, NULL, 0, 100);
+       if (ret < 0)
+               return ret;
+
+       ushc->clock_freq = clk;
+       return 0;
+}
+
+static void ushc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct ushc_data *ushc = mmc_priv(mmc);
+
+       ushc_set_power(ushc, ios->power_mode);
+       ushc_set_bus_width(ushc, 1 << ios->bus_width);
+       ushc_set_bus_freq(ushc, ios->clock, ios->timing == MMC_TIMING_SD_HS);
+}
+
+static int ushc_get_cd(struct mmc_host *mmc)
+{
+       struct ushc_data *ushc = mmc_priv(mmc);
+
+       return !!(ushc->last_status & USHC_INT_STATUS_CARD_PRESENT);
+}
+
+static void ushc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+       struct ushc_data *ushc = mmc_priv(mmc);
+
+       if (enable)
+               set_bit(INT_EN, &ushc->flags);
+       else
+               clear_bit(INT_EN, &ushc->flags);
+}
+
+static void ushc_clean_up(struct ushc_data *ushc)
+{
+       usb_free_urb(ushc->int_urb);
+       usb_free_urb(ushc->csw_urb);
+       usb_free_urb(ushc->data_urb);
+       usb_free_urb(ushc->cbw_urb);
+
+       kfree(ushc->int_data);
+       kfree(ushc->cbw);
+       kfree(ushc->csw);
+
+       mmc_free_host(ushc->mmc);
+}
+
+static const struct mmc_host_ops ushc_ops = {
+       .request         = ushc_request,
+       .set_ios         = ushc_set_ios,
+       .get_cd          = ushc_get_cd,
+       .enable_sdio_irq = ushc_enable_sdio_irq,
+};
+
+static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+       struct usb_device *usb_dev = interface_to_usbdev(intf);
+       struct mmc_host *mmc;
+       struct ushc_data *ushc;
+       int ret = -ENOMEM;
+
+       mmc = mmc_alloc_host(sizeof(struct ushc_data), &intf->dev);
+       if (mmc == NULL)
+               return -ENOMEM;
+       ushc = mmc_priv(mmc);
+       usb_set_intfdata(intf, ushc);
+
+       ushc->usb_dev = usb_dev;
+       ushc->mmc = mmc;
+
+       spin_lock_init(&ushc->lock);
+
+       ret = ushc_hw_reset(ushc);
+       if (ret < 0)
+               goto err;
+
+       /* Read capabilities. */
+       ret = ushc_hw_get_caps(ushc);
+       if (ret < 0)
+               goto err;
+
+       mmc->ops = &ushc_ops;
+
+       mmc->f_min = 400000;
+       mmc->f_max = 50000000;
+       mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
+       mmc->caps |= (ushc->caps & USHC_GET_CAPS_HIGH_SPD) ? MMC_CAP_SD_HIGHSPEED : 0;
+
+       mmc->max_seg_size  = 512*511;
+       mmc->max_segs      = 1;
+       mmc->max_req_size  = 512*511;
+       mmc->max_blk_size  = 512;
+       mmc->max_blk_count = 511;
+
+       ushc->int_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (ushc->int_urb == NULL)
+               goto err;
+       ushc->int_data = kzalloc(sizeof(struct ushc_int_data), GFP_KERNEL);
+       if (ushc->int_data == NULL)
+               goto err;
+       usb_fill_int_urb(ushc->int_urb, ushc->usb_dev,
+                        usb_rcvintpipe(usb_dev,
+                                       intf->cur_altsetting->endpoint[0].desc.bEndpointAddress),
+                        ushc->int_data, sizeof(struct ushc_int_data),
+                        int_callback, ushc,
+                        intf->cur_altsetting->endpoint[0].desc.bInterval);
+
+       ushc->cbw_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (ushc->cbw_urb == NULL)
+               goto err;
+       ushc->cbw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL);
+       if (ushc->cbw == NULL)
+               goto err;
+       ushc->cbw->signature = USHC_CBW_SIGNATURE;
+
+       usb_fill_bulk_urb(ushc->cbw_urb, ushc->usb_dev, usb_sndbulkpipe(usb_dev, 2),
+                         ushc->cbw, sizeof(struct ushc_cbw),
+                         cbw_callback, ushc);
+
+       ushc->data_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (ushc->data_urb == NULL)
+               goto err;
+
+       ushc->csw_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (ushc->csw_urb == NULL)
+               goto err;
+       ushc->csw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL);
+       if (ushc->csw == NULL)
+               goto err;
+       usb_fill_bulk_urb(ushc->csw_urb, ushc->usb_dev, usb_rcvbulkpipe(usb_dev, 6),
+                         ushc->csw, sizeof(struct ushc_csw),
+                         csw_callback, ushc);
+
+       ret = mmc_add_host(ushc->mmc);
+       if (ret)
+               goto err;
+
+       ret = usb_submit_urb(ushc->int_urb, GFP_KERNEL);
+       if (ret < 0) {
+               mmc_remove_host(ushc->mmc);
+               goto err;
+       }
+
+       return 0;
+
+err:
+       ushc_clean_up(ushc);
+       return ret;
+}
+
+static void ushc_disconnect(struct usb_interface *intf)
+{
+       struct ushc_data *ushc = usb_get_intfdata(intf);
+
+       spin_lock_irq(&ushc->lock);
+       set_bit(DISCONNECTED, &ushc->flags);
+       spin_unlock_irq(&ushc->lock);
+
+       usb_kill_urb(ushc->int_urb);
+       usb_kill_urb(ushc->cbw_urb);
+       usb_kill_urb(ushc->data_urb);
+       usb_kill_urb(ushc->csw_urb);
+
+       mmc_remove_host(ushc->mmc);
+
+       ushc_clean_up(ushc);
+}
+
+static struct usb_device_id ushc_id_table[] = {
+       /* CSR USB SD Host Controller */
+       { USB_DEVICE(0x0a12, 0x5d10) },
+       { },
+};
+MODULE_DEVICE_TABLE(usb, ushc_id_table);
+
+static struct usb_driver ushc_driver = {
+       .name       = "ushc",
+       .id_table   = ushc_id_table,
+       .probe      = ushc_probe,
+       .disconnect = ushc_disconnect,
+};
+
+static int __init ushc_init(void)
+{
+       return usb_register(&ushc_driver);
+}
+module_init(ushc_init);
+
+static void __exit ushc_exit(void)
+{
+       usb_deregister(&ushc_driver);
+}
+module_exit(ushc_exit);
+
+MODULE_DESCRIPTION("USB SD Host Controller driver");
+MODULE_AUTHOR("David Vrabel <david.vrabel@csr.com>");
+MODULE_LICENSE("GPL");
index 19f2d72..9ed84dd 100644 (file)
@@ -1050,8 +1050,7 @@ static void via_init_mmc_host(struct via_crdr_mmc_host *host)
        mmc->ops = &via_sdc_ops;
 
        /*Hardware cannot do scatter lists*/
-       mmc->max_hw_segs = 1;
-       mmc->max_phys_segs = 1;
+       mmc->max_segs = 1;
 
        mmc->max_blk_size = VIA_CRDR_MAX_BLOCK_LENGTH;
        mmc->max_blk_count = VIA_CRDR_MAX_BLOCK_COUNT;
index 0012f5d..7fca0a3 100644 (file)
@@ -1235,8 +1235,7 @@ static int __devinit wbsd_alloc_mmc(struct device *dev)
         * Maximum number of segments. Worst case is one sector per segment
         * so this will be 64kB/512.
         */
-       mmc->max_hw_segs = 128;
-       mmc->max_phys_segs = 128;
+       mmc->max_segs = 128;
 
        /*
         * Maximum request size. Also limited by 64KiB buffer.
index 6b75250..8ce0827 100644 (file)
@@ -48,6 +48,7 @@ struct mmc_ext_csd {
        unsigned int            sa_timeout;             /* Units: 100ns */
        unsigned int            hs_max_dtr;
        unsigned int            sectors;
+       unsigned int            card_type;
        unsigned int            hc_erase_size;          /* In sectors */
        unsigned int            hc_erase_timeout;       /* In milliseconds */
        unsigned int            sec_trim_mult;  /* Secure trim multiplier  */
@@ -113,6 +114,7 @@ struct mmc_card {
 #define MMC_STATE_READONLY     (1<<1)          /* card is read-only */
 #define MMC_STATE_HIGHSPEED    (1<<2)          /* card is in high speed mode */
 #define MMC_STATE_BLOCKADDR    (1<<3)          /* card uses block-addressing */
+#define MMC_STATE_HIGHSPEED_DDR (1<<4)         /* card is in high speed mode */
        unsigned int            quirks;         /* card quirks */
 #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
@@ -154,11 +156,13 @@ struct mmc_card {
 #define mmc_card_readonly(c)   ((c)->state & MMC_STATE_READONLY)
 #define mmc_card_highspeed(c)  ((c)->state & MMC_STATE_HIGHSPEED)
 #define mmc_card_blockaddr(c)  ((c)->state & MMC_STATE_BLOCKADDR)
+#define mmc_card_ddr_mode(c)   ((c)->state & MMC_STATE_HIGHSPEED_DDR)
 
 #define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
 #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
+#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
 
 static inline int mmc_card_lenient_fn0(const struct mmc_card *c)
 {
@@ -173,6 +177,8 @@ static inline int mmc_blksz_for_byte_mode(const struct mmc_card *c)
 #define mmc_card_name(c)       ((c)->cid.prod_name)
 #define mmc_card_id(c)         (dev_name(&(c)->dev))
 
+#define mmc_dev_to_card(d)     container_of(d, struct mmc_card, dev)
+
 #define mmc_list_to_card(l)    container_of(l, struct mmc_card, node)
 #define mmc_get_drvdata(c)     dev_get_drvdata(&(c)->dev)
 #define mmc_set_drvdata(c,d)   dev_set_drvdata(&(c)->dev, d)
index 7429033..64e013f 100644 (file)
@@ -153,6 +153,8 @@ extern int mmc_can_secure_erase_trim(struct mmc_card *card);
 extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
                                   unsigned int nr);
 
+extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
+
 extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *);
 extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int);
 
index 1575b52..6d87f68 100644 (file)
@@ -50,6 +50,12 @@ struct mmc_ios {
 #define MMC_TIMING_LEGACY      0
 #define MMC_TIMING_MMC_HS      1
 #define MMC_TIMING_SD_HS       2
+
+       unsigned char   ddr;                    /* dual data rate used */
+
+#define MMC_SDR_MODE           0
+#define MMC_1_2V_DDR_MODE      1
+#define MMC_1_8V_DDR_MODE      2
 };
 
 struct mmc_host_ops {
@@ -123,6 +129,7 @@ struct mmc_host {
        const struct mmc_host_ops *ops;
        unsigned int            f_min;
        unsigned int            f_max;
+       unsigned int            f_init;
        u32                     ocr_avail;
        struct notifier_block   pm_notify;
 
@@ -157,13 +164,16 @@ struct mmc_host {
 #define MMC_CAP_NONREMOVABLE   (1 << 8)        /* Nonremovable e.g. eMMC */
 #define MMC_CAP_WAIT_WHILE_BUSY        (1 << 9)        /* Waits while card is busy */
 #define MMC_CAP_ERASE          (1 << 10)       /* Allow erase/trim commands */
+#define MMC_CAP_1_8V_DDR       (1 << 11)       /* can support */
+                                               /* DDR mode at 1.8V */
+#define MMC_CAP_1_2V_DDR       (1 << 12)       /* can support */
+                                               /* DDR mode at 1.2V */
 
        mmc_pm_flag_t           pm_caps;        /* supported pm features */
 
        /* host specific block data */
        unsigned int            max_seg_size;   /* see blk_queue_max_segment_size */
-       unsigned short          max_hw_segs;    /* see blk_queue_max_hw_segments */
-       unsigned short          max_phys_segs;  /* see blk_queue_max_phys_segments */
+       unsigned short          max_segs;       /* see blk_queue_max_segments */
        unsigned short          unused;
        unsigned int            max_req_size;   /* maximum number of bytes in one req */
        unsigned int            max_blk_size;   /* maximum size of one mmc block */
@@ -212,6 +222,10 @@ struct mmc_host {
        struct led_trigger      *led;           /* activity led */
 #endif
 
+#ifdef CONFIG_REGULATOR
+       bool                    regulator_enabled; /* regulator state */
+#endif
+
        struct dentry           *debugfs_root;
 
        unsigned long           private[0] ____cacheline_aligned;
@@ -236,8 +250,8 @@ static inline void *mmc_priv(struct mmc_host *host)
 extern int mmc_suspend_host(struct mmc_host *);
 extern int mmc_resume_host(struct mmc_host *);
 
-extern void mmc_power_save_host(struct mmc_host *host);
-extern void mmc_power_restore_host(struct mmc_host *host);
+extern int mmc_power_save_host(struct mmc_host *host);
+extern int mmc_power_restore_host(struct mmc_host *host);
 
 extern void mmc_detect_change(struct mmc_host *, unsigned long delay);
 extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
@@ -250,8 +264,24 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
 
 struct regulator;
 
+#ifdef CONFIG_REGULATOR
 int mmc_regulator_get_ocrmask(struct regulator *supply);
-int mmc_regulator_set_ocr(struct regulator *supply, unsigned short vdd_bit);
+int mmc_regulator_set_ocr(struct mmc_host *mmc,
+                       struct regulator *supply,
+                       unsigned short vdd_bit);
+#else
+static inline int mmc_regulator_get_ocrmask(struct regulator *supply)
+{
+       return 0;
+}
+
+static inline int mmc_regulator_set_ocr(struct mmc_host *mmc,
+                                struct regulator *supply,
+                                unsigned short vdd_bit)
+{
+       return 0;
+}
+#endif
 
 int mmc_card_awake(struct mmc_host *host);
 int mmc_card_sleep(struct mmc_host *host);
@@ -268,5 +298,13 @@ static inline void mmc_set_disable_delay(struct mmc_host *host,
        host->disable_delay = disable_delay;
 }
 
+/* Module parameter */
+extern int mmc_assume_removable;
+
+static inline int mmc_card_is_removable(struct mmc_host *host)
+{
+       return !(host->caps & MMC_CAP_NONREMOVABLE) && mmc_assume_removable;
+}
+
 #endif
 
index dd11ae5..956fbd8 100644 (file)
@@ -277,11 +277,19 @@ struct _mmc_csd {
 
 #define EXT_CSD_CARD_TYPE_26   (1<<0)  /* Card can run at 26MHz */
 #define EXT_CSD_CARD_TYPE_52   (1<<1)  /* Card can run at 52MHz */
-#define EXT_CSD_CARD_TYPE_MASK 0x3     /* Mask out reserved and DDR bits */
+#define EXT_CSD_CARD_TYPE_MASK 0xF     /* Mask out reserved bits */
+#define EXT_CSD_CARD_TYPE_DDR_1_8V  (1<<2)   /* Card can run at 52MHz */
+                                            /* DDR mode @1.8V or 3V I/O */
+#define EXT_CSD_CARD_TYPE_DDR_1_2V  (1<<3)   /* Card can run at 52MHz */
+                                            /* DDR mode @1.2V I/O */
+#define EXT_CSD_CARD_TYPE_DDR_52       (EXT_CSD_CARD_TYPE_DDR_1_8V  \
+                                       | EXT_CSD_CARD_TYPE_DDR_1_2V)
 
 #define EXT_CSD_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
 #define EXT_CSD_BUS_WIDTH_8    2       /* Card is in 8 bit mode */
+#define EXT_CSD_DDR_BUS_WIDTH_4        5       /* Card is in 4 bit DDR mode */
+#define EXT_CSD_DDR_BUS_WIDTH_8        6       /* Card is in 8 bit DDR mode */
 
 #define EXT_CSD_SEC_ER_EN      BIT(0)
 #define EXT_CSD_SEC_BD_BLK_EN  BIT(2)
similarity index 93%
rename from include/linux/sdhci-pltfm.h
rename to include/linux/mmc/sdhci-pltfm.h
index 0239bd7..548d59d 100644 (file)
@@ -28,7 +28,7 @@ struct sdhci_host;
 struct sdhci_pltfm_data {
        struct sdhci_ops *ops;
        unsigned int quirks;
-       int (*init)(struct sdhci_host *host);
+       int (*init)(struct sdhci_host *host, struct sdhci_pltfm_data *pdata);
        void (*exit)(struct sdhci_host *host);
 };
 
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
new file mode 100644 (file)
index 0000000..1fdc673
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ *  linux/include/linux/mmc/sdhci.h - Secure Digital Host Controller Interface
+ *
+ *  Copyright (C) 2005-2008 Pierre Ossman, 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+#ifndef __SDHCI_H
+#define __SDHCI_H
+
+#include <linux/scatterlist.h>
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/mmc/host.h>
+
+struct sdhci_host {
+       /* Data set by hardware interface driver */
+       const char *hw_name;    /* Hardware bus name */
+
+       unsigned int quirks;    /* Deviations from spec. */
+
+/* Controller doesn't honor resets unless we touch the clock register */
+#define SDHCI_QUIRK_CLOCK_BEFORE_RESET                 (1<<0)
+/* Controller has bad caps bits, but really supports DMA */
+#define SDHCI_QUIRK_FORCE_DMA                          (1<<1)
+/* Controller doesn't like to be reset when there is no card inserted. */
+#define SDHCI_QUIRK_NO_CARD_NO_RESET                   (1<<2)
+/* Controller doesn't like clearing the power reg before a change */
+#define SDHCI_QUIRK_SINGLE_POWER_WRITE                 (1<<3)
+/* Controller has flaky internal state so reset it on each ios change */
+#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS              (1<<4)
+/* Controller has an unusable DMA engine */
+#define SDHCI_QUIRK_BROKEN_DMA                         (1<<5)
+/* Controller has an unusable ADMA engine */
+#define SDHCI_QUIRK_BROKEN_ADMA                                (1<<6)
+/* Controller can only DMA from 32-bit aligned addresses */
+#define SDHCI_QUIRK_32BIT_DMA_ADDR                     (1<<7)
+/* Controller can only DMA chunk sizes that are a multiple of 32 bits */
+#define SDHCI_QUIRK_32BIT_DMA_SIZE                     (1<<8)
+/* Controller can only ADMA chunks that are a multiple of 32 bits */
+#define SDHCI_QUIRK_32BIT_ADMA_SIZE                    (1<<9)
+/* Controller needs to be reset after each request to stay stable */
+#define SDHCI_QUIRK_RESET_AFTER_REQUEST                        (1<<10)
+/* Controller needs voltage and power writes to happen separately */
+#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER            (1<<11)
+/* Controller provides an incorrect timeout value for transfers */
+#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL                 (1<<12)
+/* Controller has an issue with buffer bits for small transfers */
+#define SDHCI_QUIRK_BROKEN_SMALL_PIO                   (1<<13)
+/* Controller does not provide transfer-complete interrupt when not busy */
+#define SDHCI_QUIRK_NO_BUSY_IRQ                                (1<<14)
+/* Controller has unreliable card detection */
+#define SDHCI_QUIRK_BROKEN_CARD_DETECTION              (1<<15)
+/* Controller reports inverted write-protect state */
+#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT             (1<<16)
+/* Controller has nonstandard clock management */
+#define SDHCI_QUIRK_NONSTANDARD_CLOCK                  (1<<17)
+/* Controller does not like fast PIO transfers */
+#define SDHCI_QUIRK_PIO_NEEDS_DELAY                    (1<<18)
+/* Controller losing signal/interrupt enable states after reset */
+#define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET           (1<<19)
+/* Controller has to be forced to use block size of 2048 bytes */
+#define SDHCI_QUIRK_FORCE_BLK_SZ_2048                  (1<<20)
+/* Controller cannot do multi-block transfers */
+#define SDHCI_QUIRK_NO_MULTIBLOCK                      (1<<21)
+/* Controller can only handle 1-bit data transfers */
+#define SDHCI_QUIRK_FORCE_1_BIT_DATA                   (1<<22)
+/* Controller needs 10ms delay between applying power and clock */
+#define SDHCI_QUIRK_DELAY_AFTER_POWER                  (1<<23)
+/* Controller uses SDCLK instead of TMCLK for data timeouts */
+#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK            (1<<24)
+/* Controller reports wrong base clock capability */
+#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN              (1<<25)
+/* Controller cannot support End Attribute in NOP ADMA descriptor */
+#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC              (1<<26)
+/* Controller is missing device caps. Use caps provided by host */
+#define SDHCI_QUIRK_MISSING_CAPS                       (1<<27)
+/* Controller uses Auto CMD12 command to stop the transfer */
+#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12             (1<<28)
+/* Controller doesn't have HISPD bit field in HI-SPEED SD card */
+#define SDHCI_QUIRK_NO_HISPD_BIT                       (1<<29)
+
+       int irq;                /* Device IRQ */
+       void __iomem *ioaddr;   /* Mapped address */
+
+       const struct sdhci_ops *ops;    /* Low level hw interface */
+
+       struct regulator *vmmc; /* Power regulator */
+
+       /* Internal data */
+       struct mmc_host *mmc;   /* MMC structure */
+       u64 dma_mask;           /* custom DMA mask */
+
+#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+       struct led_classdev led;        /* LED control */
+       char led_name[32];
+#endif
+
+       spinlock_t lock;        /* Mutex */
+
+       int flags;              /* Host attributes */
+#define SDHCI_USE_SDMA         (1<<0)  /* Host is SDMA capable */
+#define SDHCI_USE_ADMA         (1<<1)  /* Host is ADMA capable */
+#define SDHCI_REQ_USE_DMA      (1<<2)  /* Use DMA for this req. */
+#define SDHCI_DEVICE_DEAD      (1<<3)  /* Device unresponsive */
+
+       unsigned int version;   /* SDHCI spec. version */
+
+       unsigned int max_clk;   /* Max possible freq (MHz) */
+       unsigned int timeout_clk;       /* Timeout freq (KHz) */
+
+       unsigned int clock;     /* Current clock (MHz) */
+       u8 pwr;                 /* Current voltage */
+
+       struct mmc_request *mrq;        /* Current request */
+       struct mmc_command *cmd;        /* Current command */
+       struct mmc_data *data;  /* Current data request */
+       unsigned int data_early:1;      /* Data finished before cmd */
+
+       struct sg_mapping_iter sg_miter;        /* SG state for PIO */
+       unsigned int blocks;    /* remaining PIO blocks */
+
+       int sg_count;           /* Mapped sg entries */
+
+       u8 *adma_desc;          /* ADMA descriptor table */
+       u8 *align_buffer;       /* Bounce buffer */
+
+       dma_addr_t adma_addr;   /* Mapped ADMA descr. table */
+       dma_addr_t align_addr;  /* Mapped bounce buffer */
+
+       struct tasklet_struct card_tasklet;     /* Tasklet structures */
+       struct tasklet_struct finish_tasklet;
+
+       struct timer_list timer;        /* Timer for timeouts */
+
+       unsigned int caps;      /* Alternative capabilities */
+
+       unsigned long private[0] ____cacheline_aligned;
+};
+#endif /* __SDHCI_H */
index b4c3d1b..30d9183 100644 (file)
 #define PCI_DEVICE_ID_INTEL_82375      0x0482
 #define PCI_DEVICE_ID_INTEL_82424      0x0483
 #define PCI_DEVICE_ID_INTEL_82378      0x0484
+#define PCI_DEVICE_ID_INTEL_MRST_SD0   0x0807
+#define PCI_DEVICE_ID_INTEL_MRST_SD1   0x0808
+#define PCI_DEVICE_ID_INTEL_MFD_SD     0x0820
+#define PCI_DEVICE_ID_INTEL_MFD_SDIO1  0x0821
+#define PCI_DEVICE_ID_INTEL_MFD_SDIO2  0x0822
+#define PCI_DEVICE_ID_INTEL_MFD_EMMC0  0x0823
+#define PCI_DEVICE_ID_INTEL_MFD_EMMC1  0x0824
 #define PCI_DEVICE_ID_INTEL_I960       0x0960
 #define PCI_DEVICE_ID_INTEL_I960RM     0x0962
 #define PCI_DEVICE_ID_INTEL_8257X_SOL  0x1062