summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/drivers/mmc
diff options
context:
space:
mode:
authorSrikant Patnaik2015-01-11 12:28:04 +0530
committerSrikant Patnaik2015-01-11 12:28:04 +0530
commit871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch)
tree8718f573808810c2a1e8cb8fb6ac469093ca2784 /ANDROID_3.4.5/drivers/mmc
parent9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff)
downloadFOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.gz
FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.bz2
FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.zip
Moved, renamed, and deleted files
The original directory structure was scattered and unorganized. Changes are basically to make it look like kernel structure.
Diffstat (limited to 'ANDROID_3.4.5/drivers/mmc')
-rw-r--r--ANDROID_3.4.5/drivers/mmc/Kconfig30
-rw-r--r--ANDROID_3.4.5/drivers/mmc/Makefile9
-rw-r--r--ANDROID_3.4.5/drivers/mmc/card/Kconfig78
-rw-r--r--ANDROID_3.4.5/drivers/mmc/card/Makefile10
-rw-r--r--ANDROID_3.4.5/drivers/mmc/card/block.c2088
-rw-r--r--ANDROID_3.4.5/drivers/mmc/card/mmc_test.c3055
-rw-r--r--ANDROID_3.4.5/drivers/mmc/card/queue.c438
-rw-r--r--ANDROID_3.4.5/drivers/mmc/card/queue.h49
-rw-r--r--ANDROID_3.4.5/drivers/mmc/card/sdio_uart.c1219
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/Kconfig46
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/Makefile12
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/bus.c454
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/bus.h31
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/cd-gpio.c83
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/core.c2958
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/core.h80
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/debugfs.c364
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/host.c498
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/host.h19
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/mmc.c1553
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/mmc_ops.c591
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/mmc_ops.h32
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/quirks.c91
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/sd.c1341
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/sd.h17
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/sd_ops.c399
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/sd_ops.h25
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/sdio.c1260
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/sdio_bus.c337
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/sdio_bus.h22
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/sdio_cis.c412
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/sdio_cis.h23
-rwxr-xr-xANDROID_3.4.5/drivers/mmc/core/sdio_io.c759
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/sdio_irq.c314
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/sdio_ops.c199
-rw-r--r--ANDROID_3.4.5/drivers/mmc/core/sdio_ops.h23
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/Kconfig646
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/Makefile63
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/at91_mci.c1219
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/at91_mci.h115
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/atmel-mci-regs.h143
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/atmel-mci.c2291
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/au1xmmc.c1228
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/bfin_sdh.c634
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/cb710-mmc.c788
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/cb710-mmc.h104
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/davinci_mmc.c1536
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/dw_mmc-pci.c158
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/dw_mmc-pltfm.c134
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/dw_mmc.c2221
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/dw_mmc.h185
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/imxmmc.c1169
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/imxmmc.h64
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/jz4740_mmc.c1019
-rwxr-xr-xANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.c2837
-rwxr-xr-xANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.h691
-rwxr-xr-xANDROID_3.4.5/drivers/mmc/host/mmc_atsmb1.c2405
-rwxr-xr-xANDROID_3.4.5/drivers/mmc/host/mmc_atsmb2.c2855
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/mmc_spi.c1554
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/mmci.c1606
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/mmci.h211
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/msm_sdcc.c1486
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/msm_sdcc.h256
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/mvsdio.c921
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/mvsdio.h190
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/mxcmmc.c1062
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/mxs-mmc.c873
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/of_mmc_spi.c181
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/omap.c1637
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/omap_hsmmc.c2209
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/pxamci.c879
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/pxamci.h90
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/s3cmci.c1921
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/s3cmci.h82
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sdhci-cns3xxx.c123
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sdhci-dove.c97
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sdhci-esdhc-imx.c613
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sdhci-esdhc.h81
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sdhci-of-esdhc.c204
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sdhci-of-hlwd.c100
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sdhci-pci-data.c5
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sdhci-pci.c1499
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sdhci-pltfm.c241
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sdhci-pltfm.h108
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sdhci-pxav2.c232
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sdhci-pxav3.c278
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sdhci-s3c.c756
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sdhci-spear.c321
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sdhci-tegra.c404
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sdhci.c3136
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sdhci.h390
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sdricoh_cs.c573
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sh_mmcif.c1454
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/sh_mobile_sdhi.c309
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/tifm_sd.c1093
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/tmio_mmc.c146
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/tmio_mmc.h200
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/tmio_mmc_dma.c336
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/tmio_mmc_pio.c1078
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/ushc.c569
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/via-sdmmc.c1358
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/vub300.c2503
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/wbsd.c2047
-rw-r--r--ANDROID_3.4.5/drivers/mmc/host/wbsd.h185
104 files changed, 0 insertions, 77021 deletions
diff --git a/ANDROID_3.4.5/drivers/mmc/Kconfig b/ANDROID_3.4.5/drivers/mmc/Kconfig
deleted file mode 100644
index f2eeb38e..00000000
--- a/ANDROID_3.4.5/drivers/mmc/Kconfig
+++ /dev/null
@@ -1,30 +0,0 @@
-#
-# MMC subsystem configuration
-#
-
-menuconfig MMC
- tristate "MMC/SD/SDIO card support"
- depends on HAS_IOMEM
- help
- This selects MultiMediaCard, Secure Digital and Secure
- Digital I/O support.
-
- If you want MMC/SD/SDIO support, you should say Y here and
- also to your specific host controller driver.
-
-config MMC_DEBUG
- bool "MMC debugging"
- depends on MMC != n
- help
- This is an option for use by developers; most people should
- say N here. This enables MMC core and driver debugging.
-
-if MMC
-
-source "drivers/mmc/core/Kconfig"
-
-source "drivers/mmc/card/Kconfig"
-
-source "drivers/mmc/host/Kconfig"
-
-endif # MMC
diff --git a/ANDROID_3.4.5/drivers/mmc/Makefile b/ANDROID_3.4.5/drivers/mmc/Makefile
deleted file mode 100644
index 400756ec..00000000
--- a/ANDROID_3.4.5/drivers/mmc/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Makefile for the kernel mmc device drivers.
-#
-
-subdir-ccflags-$(CONFIG_MMC_DEBUG) := -DDEBUG
-
-obj-$(CONFIG_MMC) += core/
-obj-$(CONFIG_MMC) += card/
-obj-$(subst m,y,$(CONFIG_MMC)) += host/
diff --git a/ANDROID_3.4.5/drivers/mmc/card/Kconfig b/ANDROID_3.4.5/drivers/mmc/card/Kconfig
deleted file mode 100644
index ebb4afe6..00000000
--- a/ANDROID_3.4.5/drivers/mmc/card/Kconfig
+++ /dev/null
@@ -1,78 +0,0 @@
-#
-# MMC/SD card drivers
-#
-
-comment "MMC/SD/SDIO Card Drivers"
-
-config MMC_BLOCK
- tristate "MMC block device driver"
- depends on BLOCK
- default y
- help
- Say Y here to enable the MMC block device driver support.
- This provides a block device driver, which you can use to
- 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"
- depends on MMC_BLOCK
- 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
- default y
- help
- SD/MMC is a high latency protocol where it is crucial to
- send large requests in order to get high performance. Many
- controllers, however, are restricted to continuous memory
- (i.e. they can't do scatter-gather), something the kernel
- rarely can provide.
-
- Say Y here to help these restricted hosts by bouncing
- requests back and forth from a large buffer. You will get
- a big performance gain at the cost of up to 64 KiB of
- physical memory.
-
- If unsure, say Y here.
-
-config MMC_BLOCK_DEFERRED_RESUME
- bool "Deferr MMC layer resume until I/O is requested"
- depends on MMC_BLOCK
- default n
- help
- Say Y here to enable deferred MMC resume until I/O
- is requested. This will reduce overall resume latency and
- save power when theres an SD card inserted but not being used.
-
-config SDIO_UART
- tristate "SDIO UART/GPS class support"
- help
- SDIO function driver for SDIO cards that implements the UART
- class, as well as the GPS class which appears like a UART.
-
-config MMC_TEST
- tristate "MMC host test driver"
- help
- Development driver that performs a series of reads and writes
- to a memory card in order to expose certain well known bugs
- in host controllers. The tests are executed by writing to the
- "test" file in debugfs under each card. Note that whatever is
- on your card will be overwritten by these tests.
-
- This driver is only of interest to those developing or
- testing a host driver. Most people should say N here.
diff --git a/ANDROID_3.4.5/drivers/mmc/card/Makefile b/ANDROID_3.4.5/drivers/mmc/card/Makefile
deleted file mode 100644
index c73b406a..00000000
--- a/ANDROID_3.4.5/drivers/mmc/card/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Makefile for MMC/SD card drivers
-#
-
-obj-$(CONFIG_MMC_BLOCK) += mmc_block.o
-mmc_block-objs := block.o queue.o
-obj-$(CONFIG_MMC_TEST) += mmc_test.o
-
-obj-$(CONFIG_SDIO_UART) += sdio_uart.o
-
diff --git a/ANDROID_3.4.5/drivers/mmc/card/block.c b/ANDROID_3.4.5/drivers/mmc/card/block.c
deleted file mode 100644
index 90a15016..00000000
--- a/ANDROID_3.4.5/drivers/mmc/card/block.c
+++ /dev/null
@@ -1,2088 +0,0 @@
-/*
- * Block driver for media (i.e., flash cards)
- *
- * Copyright 2002 Hewlett-Packard Company
- * Copyright 2005-2008 Pierre Ossman
- *
- * Use consistent with the GNU GPL is permitted,
- * provided that this copyright notice is
- * preserved in its entirety in all copies and derived works.
- *
- * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
- * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
- * FITNESS FOR ANY PARTICULAR PURPOSE.
- *
- * Many thanks to Alessandro Rubini and Jonathan Corbet!
- *
- * Author: Andrew Christian
- * 28 May 2002
- */
-#include <linux/moduleparam.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/hdreg.h>
-#include <linux/kdev_t.h>
-#include <linux/blkdev.h>
-#include <linux/mutex.h>
-#include <linux/scatterlist.h>
-#include <linux/string_helpers.h>
-#include <linux/delay.h>
-#include <linux/capability.h>
-#include <linux/compat.h>
-
-#include <linux/mmc/ioctl.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/sd.h>
-
-#include <asm/uaccess.h>
-
-#include "queue.h"
-
-MODULE_ALIAS("mmc:block");
-#ifdef MODULE_PARAM_PREFIX
-#undef MODULE_PARAM_PREFIX
-#endif
-#define MODULE_PARAM_PREFIX "mmcblk."
-
-#define INAND_CMD38_ARG_EXT_CSD 113
-#define INAND_CMD38_ARG_ERASE 0x00
-#define INAND_CMD38_ARG_TRIM 0x01
-#define INAND_CMD38_ARG_SECERASE 0x80
-#define INAND_CMD38_ARG_SECTRIM1 0x81
-#define INAND_CMD38_ARG_SECTRIM2 0x88
-
-static DEFINE_MUTEX(block_mutex);
-
-/*
- * The defaults come from config options but can be overriden by module
- * or bootarg options.
- */
-static int perdev_minors = CONFIG_MMC_BLOCK_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);
-static DECLARE_BITMAP(name_use, 256);
-
-/*
- * There is one mmc_blk_data per slot.
- */
-struct mmc_blk_data {
- spinlock_t lock;
- struct gendisk *disk;
- struct mmc_queue queue;
- struct list_head part;
-
- unsigned int flags;
-#define MMC_BLK_CMD23 (1 << 0) /* Can do SET_BLOCK_COUNT for multiblock */
-#define MMC_BLK_REL_WR (1 << 1) /* MMC Reliable write support */
-
- unsigned int usage;
- unsigned int read_only;
- unsigned int part_type;
- unsigned int name_idx;
- unsigned int reset_done;
-#define MMC_BLK_READ BIT(0)
-#define MMC_BLK_WRITE BIT(1)
-#define MMC_BLK_DISCARD BIT(2)
-#define MMC_BLK_SECDISCARD BIT(3)
-
- /*
- * Only set in main mmc_blk_data associated
- * with mmc_card with mmc_set_drvdata, and keeps
- * track of the current selected device partition.
- */
- unsigned int part_curr;
- struct device_attribute force_ro;
- struct device_attribute power_ro_lock;
- int area_type;
-};
-
-static DEFINE_MUTEX(open_lock);
-
-enum mmc_blk_status {
- MMC_BLK_SUCCESS = 0,
- MMC_BLK_PARTIAL,
- MMC_BLK_CMD_ERR,
- MMC_BLK_RETRY,
- MMC_BLK_ABORT,
- MMC_BLK_DATA_ERR,
- MMC_BLK_ECC_ERR,
- MMC_BLK_NOMEDIUM,
-};
-
-module_param(perdev_minors, int, 0444);
-MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
-
-
-#if 0
-#define DBG(x...) printk(KERN_ALERT x)
-#else
-#define DBG(x...) do { } while (0)
-#endif
-
-
-static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
-{
- struct mmc_blk_data *md;
- DBG("[%s] s\n",__func__);
- mutex_lock(&open_lock);
- md = disk->private_data;
- if (md && md->usage == 0)
- md = NULL;
- if (md)
- md->usage++;
- mutex_unlock(&open_lock);
- DBG("[%s] e\n",__func__);
- return md;
-}
-
-static inline int mmc_get_devidx(struct gendisk *disk)
-{
- int devidx = disk->first_minor / perdev_minors;
- DBG("[%s] s\n",__func__);
- return devidx;
-}
-
-static void mmc_blk_put(struct mmc_blk_data *md)
-{
- DBG("[%s] s\n",__func__);
- mutex_lock(&open_lock);
- md->usage--;
- if (md->usage == 0) {
- int devidx = mmc_get_devidx(md->disk);
- blk_cleanup_queue(md->queue.queue);
-
- __clear_bit(devidx, dev_use);
-
- put_disk(md->disk);
- kfree(md);
- }
- mutex_unlock(&open_lock);
- DBG("[%s] e\n",__func__);
-}
-
-static ssize_t power_ro_lock_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- int ret;
- struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
- struct mmc_card *card = md->queue.card;
- int locked = 0;
- DBG("[%s] s\n",__func__);
-
- if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PERM_WP_EN)
- locked = 2;
- else if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_EN)
- locked = 1;
-
- ret = snprintf(buf, PAGE_SIZE, "%d\n", locked);
- DBG("[%s] e\n",__func__);
- return ret;
-}
-
-static ssize_t power_ro_lock_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int ret;
- struct mmc_blk_data *md, *part_md;
- struct mmc_card *card;
- unsigned long set;
- DBG("[%s] s\n",__func__);
-
- if (kstrtoul(buf, 0, &set)) {
- DBG("[%s] e1\n",__func__);
- return -EINVAL;
- }
-
- if (set != 1) {
- DBG("[%s] e2\n",__func__);
- return count;
- }
-
- md = mmc_blk_get(dev_to_disk(dev));
- card = md->queue.card;
-
- mmc_claim_host(card->host);
-
- ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
- card->ext_csd.boot_ro_lock |
- EXT_CSD_BOOT_WP_B_PWR_WP_EN,
- card->ext_csd.part_time);
- if (ret)
- pr_err("%s: Locking boot partition ro until next power on failed: %d\n", md->disk->disk_name, ret);
- else
- card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN;
-
- mmc_release_host(card->host);
-
- if (!ret) {
- pr_info("%s: Locking boot partition ro until next power on\n",
- md->disk->disk_name);
- set_disk_ro(md->disk, 1);
-
- list_for_each_entry(part_md, &md->part, part)
- if (part_md->area_type == MMC_BLK_DATA_AREA_BOOT) {
- pr_info("%s: Locking boot partition ro until next power on\n", part_md->disk->disk_name);
- set_disk_ro(part_md->disk, 1);
- }
- }
-
- mmc_blk_put(md);
- DBG("[%s] e3\n",__func__);
- return count;
-}
-
-static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- int ret;
- struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
- DBG("[%s] s\n",__func__);
-
- ret = snprintf(buf, PAGE_SIZE, "%d",
- get_disk_ro(dev_to_disk(dev)) ^
- md->read_only);
- mmc_blk_put(md);
- DBG("[%s] e\n",__func__);
- return ret;
-}
-
-static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int ret;
- char *end;
- struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
- unsigned long set = simple_strtoul(buf, &end, 0);
- DBG("[%s] s\n",__func__);
-
- if (end == buf) {
- ret = -EINVAL;
- goto out;
- }
-
- set_disk_ro(dev_to_disk(dev), set || md->read_only);
- ret = count;
-out:
- mmc_blk_put(md);
- DBG("[%s] e\n",__func__);
- return ret;
-}
-
-static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
-{
- struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
- int ret = -ENXIO;
- DBG("[%s] s\n",__func__);
-
- mutex_lock(&block_mutex);
- if (md) {
- if (md->usage == 2)
- check_disk_change(bdev);
- ret = 0;
-
- if ((mode & FMODE_WRITE) && md->read_only) {
- mmc_blk_put(md);
- ret = -EROFS;
- }
- }
- mutex_unlock(&block_mutex);
- DBG("[%s] e\n",__func__);
- return ret;
-}
-
-static int mmc_blk_release(struct gendisk *disk, fmode_t mode)
-{
- struct mmc_blk_data *md = disk->private_data;
- DBG("[%s] s\n",__func__);
-
- mutex_lock(&block_mutex);
- mmc_blk_put(md);
- mutex_unlock(&block_mutex);
- DBG("[%s] e\n",__func__);
- return 0;
-}
-
-static int
-mmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
- DBG("[%s] s\n",__func__);
- geo->cylinders = get_capacity(bdev->bd_disk) / (4 * 16);
- geo->heads = 4;
- geo->sectors = 16;
- DBG("[%s] e\n",__func__);
- return 0;
-}
-
-struct mmc_blk_ioc_data {
- struct mmc_ioc_cmd ic;
- unsigned char *buf;
- u64 buf_bytes;
-};
-
-static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
- struct mmc_ioc_cmd __user *user)
-{
- struct mmc_blk_ioc_data *idata;
- int err;
- DBG("[%s] s\n",__func__);
-
- idata = kzalloc(sizeof(*idata), GFP_KERNEL);
- if (!idata) {
- err = -ENOMEM;
- goto out;
- }
-
- if (copy_from_user(&idata->ic, user, sizeof(idata->ic))) {
- err = -EFAULT;
- goto idata_err;
- }
-
- idata->buf_bytes = (u64) idata->ic.blksz * idata->ic.blocks;
- if (idata->buf_bytes > MMC_IOC_MAX_BYTES) {
- err = -EOVERFLOW;
- goto idata_err;
- }
-
- if (!idata->buf_bytes) {
- DBG("[%s] e1\n",__func__);
- return idata;
- }
-
- idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL);
- if (!idata->buf) {
- err = -ENOMEM;
- goto idata_err;
- }
-
- if (copy_from_user(idata->buf, (void __user *)(unsigned long)
- idata->ic.data_ptr, idata->buf_bytes)) {
- err = -EFAULT;
- goto copy_err;
- }
- DBG("[%s] e2\n",__func__);
- return idata;
-
-copy_err:
- kfree(idata->buf);
-idata_err:
- kfree(idata);
-out:
- DBG("[%s] e3\n",__func__);
- return ERR_PTR(err);
-}
-
-static int mmc_blk_ioctl_cmd(struct block_device *bdev,
- struct mmc_ioc_cmd __user *ic_ptr)
-{
- struct mmc_blk_ioc_data *idata;
- struct mmc_blk_data *md;
- struct mmc_card *card;
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
- struct mmc_request mrq = {NULL};
- struct scatterlist sg;
- int err;
- DBG("[%s] s\n",__func__);
- /*
- * The caller must have CAP_SYS_RAWIO, and must be calling this on the
- * whole block device, not on a partition. This prevents overspray
- * between sibling partitions.
- */
- if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains)) {
- DBG("[%s] e1\n",__func__);
- return -EPERM;
- }
-
- idata = mmc_blk_ioctl_copy_from_user(ic_ptr);
- if (IS_ERR(idata)) {
- DBG("[%s] e2\n",__func__);
- return PTR_ERR(idata);
- }
-
- md = mmc_blk_get(bdev->bd_disk);
- if (!md) {
- err = -EINVAL;
- goto cmd_done;
- }
-
- card = md->queue.card;
- if (IS_ERR(card)) {
- err = PTR_ERR(card);
- goto cmd_done;
- }
-
- cmd.opcode = idata->ic.opcode;
- cmd.arg = idata->ic.arg;
- cmd.flags = idata->ic.flags;
-
- if (idata->buf_bytes) {
- data.sg = &sg;
- data.sg_len = 1;
- data.blksz = idata->ic.blksz;
- data.blocks = idata->ic.blocks;
-
- sg_init_one(data.sg, idata->buf, idata->buf_bytes);
-
- if (idata->ic.write_flag)
- data.flags = MMC_DATA_WRITE;
- else
- data.flags = MMC_DATA_READ;
-
- /* data.flags must already be set before doing this. */
- mmc_set_data_timeout(&data, card);
-
- /* Allow overriding the timeout_ns for empirical tuning. */
- if (idata->ic.data_timeout_ns)
- data.timeout_ns = idata->ic.data_timeout_ns;
-
- if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
- /*
- * Pretend this is a data transfer and rely on the
- * host driver to compute timeout. When all host
- * drivers support cmd.cmd_timeout for R1B, this
- * can be changed to:
- *
- * mrq.data = NULL;
- * cmd.cmd_timeout = idata->ic.cmd_timeout_ms;
- */
- data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000;
- }
-
- mrq.data = &data;
- }
-
- mrq.cmd = &cmd;
-
- mmc_claim_host(card->host);
-
- if (idata->ic.is_acmd) {
- err = mmc_app_cmd(card->host, card);
- if (err)
- goto cmd_rel_host;
- }
-
- mmc_wait_for_req(card->host, &mrq);
-
- if (cmd.error) {
- dev_err(mmc_dev(card->host), "%s: cmd error %d\n",
- __func__, cmd.error);
- err = cmd.error;
- goto cmd_rel_host;
- }
- if (data.error) {
- dev_err(mmc_dev(card->host), "%s: data error %d\n",
- __func__, data.error);
- err = data.error;
- goto cmd_rel_host;
- }
-
- /*
- * According to the SD specs, some commands require a delay after
- * issuing the command.
- */
- if (idata->ic.postsleep_min_us)
- usleep_range(idata->ic.postsleep_min_us, idata->ic.postsleep_max_us);
-
- if (copy_to_user(&(ic_ptr->response), cmd.resp, sizeof(cmd.resp))) {
- err = -EFAULT;
- goto cmd_rel_host;
- }
-
- if (!idata->ic.write_flag) {
- if (copy_to_user((void __user *)(unsigned long) idata->ic.data_ptr,
- idata->buf, idata->buf_bytes)) {
- err = -EFAULT;
- goto cmd_rel_host;
- }
- }
-
-cmd_rel_host:
- mmc_release_host(card->host);
-
-cmd_done:
- mmc_blk_put(md);
- kfree(idata->buf);
- kfree(idata);
- DBG("[%s] e3\n",__func__);
- return err;
-}
-
-static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg)
-{
- int ret = -EINVAL;
- DBG("[%s] s\n",__func__);
- if (cmd == MMC_IOC_CMD)
- ret = mmc_blk_ioctl_cmd(bdev, (struct mmc_ioc_cmd __user *)arg);
- DBG("[%s] e\n",__func__);
- return ret;
-}
-
-#ifdef CONFIG_COMPAT
-static int mmc_blk_compat_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg)
-{
- DBG("[%s] s\n",__func__);
- return mmc_blk_ioctl(bdev, mode, cmd, (unsigned long) compat_ptr(arg));
-}
-#endif
-
-static const struct block_device_operations mmc_bdops = {
- .open = mmc_blk_open,
- .release = mmc_blk_release,
- .getgeo = mmc_blk_getgeo,
- .owner = THIS_MODULE,
- .ioctl = mmc_blk_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = mmc_blk_compat_ioctl,
-#endif
-};
-
-static inline int mmc_blk_part_switch(struct mmc_card *card,
- struct mmc_blk_data *md)
-{
- int ret;
- struct mmc_blk_data *main_md = mmc_get_drvdata(card);
- DBG("[%s] s\n",__func__);
-
- if (main_md->part_curr == md->part_type) {
- DBG("[%s] e1\n",__func__);
- return 0;
- }
-
- if (mmc_card_mmc(card)) {
- u8 part_config = card->ext_csd.part_config;
-
- part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
- part_config |= md->part_type;
-
- ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_PART_CONFIG, part_config,
- card->ext_csd.part_time);
- if (ret) {
- DBG("[%s] e2\n",__func__);
- return ret;
- }
-
- card->ext_csd.part_config = part_config;
- }
-
- main_md->part_curr = md->part_type;
- DBG("[%s] e3\n",__func__);
- return 0;
-}
-
-static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
-{
- int err;
- u32 result;
- __be32 *blocks;
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
- unsigned int timeout_us;
-
- struct scatterlist sg;
- DBG("[%s] s\n",__func__);
-
- cmd.opcode = MMC_APP_CMD;
- cmd.arg = card->rca << 16;
- //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
- if (err) {
- DBG("[%s] e1\n",__func__);
- return (u32)-1;
- }
- if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD)) {
- DBG("[%s] e2\n",__func__);
- return (u32)-1;
- }
-
- memset(&cmd, 0, sizeof(struct mmc_command));
-
- cmd.opcode = SD_APP_SEND_NUM_WR_BLKS;
- cmd.arg = 0;
- //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
- data.timeout_ns = card->csd.tacc_ns * 100;
- data.timeout_clks = card->csd.tacc_clks * 100;
-
- timeout_us = data.timeout_ns / 1000;
- timeout_us += data.timeout_clks * 1000 /
- (card->host->ios.clock / 1000);
-
- if (timeout_us > 100000) {
- data.timeout_ns = 100000000;
- data.timeout_clks = 0;
- }
-
- data.blksz = 4;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-
- mrq.cmd = &cmd;
- mrq.data = &data;
-
- blocks = kmalloc(4, GFP_KERNEL);
- if (!blocks) {
- DBG("[%s] e3\n",__func__);
- return (u32)-1;
- }
-
- sg_init_one(&sg, blocks, 4);
-
- mmc_wait_for_req(card->host, &mrq);
-
- result = ntohl(*blocks);
- kfree(blocks);
-
- if (cmd.error || data.error)
- result = (u32)-1;
- DBG("[%s] e4\n",__func__);
- return result;
-}
-
-static int send_stop(struct mmc_card *card, u32 *status)
-{
- struct mmc_command cmd = {0};
- int err;
- DBG("[%s] s\n",__func__);
-
- cmd.opcode = MMC_STOP_TRANSMISSION;
- //cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
- cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
- err = mmc_wait_for_cmd(card->host, &cmd, 5);
- if (err == 0)
- *status = cmd.resp[0];
- DBG("[%s] e\n",__func__);
- return err;
-}
-
-static int get_card_status(struct mmc_card *card, u32 *status, int retries)
-{
- struct mmc_command cmd = {0};
- int err;
- DBG("[%s] s\n",__func__);
-
- cmd.opcode = MMC_SEND_STATUS;
- if (!mmc_host_is_spi(card->host))
- cmd.arg = card->rca << 16;
- //cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(card->host, &cmd, retries);
- if (err == 0)
- *status = cmd.resp[0];
- DBG("[%s] e\n",__func__);
- return err;
-}
-
-#define ERR_NOMEDIUM 3
-#define ERR_RETRY 2
-#define ERR_ABORT 1
-#define ERR_CONTINUE 0
-
-static int mmc_blk_cmd_error(struct request *req, const char *name, int error,
- bool status_valid, u32 status)
-{
- DBG("[%s] s\n",__func__);
- switch (error) {
- case -EILSEQ:
- /* response crc error, retry the r/w cmd */
- pr_err("%s: %s sending %s command, card status %#x\n",
- req->rq_disk->disk_name, "response CRC error",
- name, status);
- DBG("[%s] e1\n",__func__);
- return ERR_RETRY;
-
- case -ETIMEDOUT:
- pr_err("%s: %s sending %s command, card status %#x\n",
- req->rq_disk->disk_name, "timed out", name, status);
-
- /* If the status cmd initially failed, retry the r/w cmd */
- if (!status_valid) {
- pr_err("%s: status not valid, retrying timeout\n", req->rq_disk->disk_name);
- DBG("[%s] e2\n",__func__);
- return ERR_RETRY;
- }
- /*
- * If it was a r/w cmd crc error, or illegal command
- * (eg, issued in wrong state) then retry - we should
- * have corrected the state problem above.
- */
- if (status & (R1_COM_CRC_ERROR | R1_ILLEGAL_COMMAND)) {
- pr_err("%s: command error, retrying timeout\n", req->rq_disk->disk_name);
- DBG("[%s] e3\n",__func__);
- return ERR_RETRY;
- }
-
- /* Otherwise abort the command */
- pr_err("%s: not retrying timeout\n", req->rq_disk->disk_name);
- DBG("[%s] e4\n",__func__);
- return ERR_ABORT;
-
- default:
- /* We don't understand the error code the driver gave us */
- pr_err("%s: unknown error %d sending read/write command, card status %#x\n",
- req->rq_disk->disk_name, error, status);
- DBG("[%s] e5\n",__func__);
- return ERR_ABORT;
- }
-}
-
-/*
- * Initial r/w and stop cmd error recovery.
- * We don't know whether the card received the r/w cmd or not, so try to
- * restore things back to a sane state. Essentially, we do this as follows:
- * - Obtain card status. If the first attempt to obtain card status fails,
- * the status word will reflect the failed status cmd, not the failed
- * r/w cmd. If we fail to obtain card status, it suggests we can no
- * longer communicate with the card.
- * - Check the card state. If the card received the cmd but there was a
- * transient problem with the response, it might still be in a data transfer
- * mode. Try to send it a stop command. If this fails, we can't recover.
- * - If the r/w cmd failed due to a response CRC error, it was probably
- * transient, so retry the cmd.
- * - If the r/w cmd timed out, but we didn't get the r/w cmd status, retry.
- * - If the r/w cmd timed out, and the r/w cmd failed due to CRC error or
- * illegal cmd, retry.
- * Otherwise we don't understand what happened, so abort.
- */
-static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
- struct mmc_blk_request *brq, int *ecc_err)
-{
- bool prev_cmd_status_valid = true;
- u32 status, stop_status = 0;
- int err, retry;
- DBG("[%s] s\n",__func__);
-
- if (mmc_card_removed(card)) {
- DBG("[%s] e1\n",__func__);
- return ERR_NOMEDIUM;
- }
- /*
- * Try to get card status which indicates both the card state
- * and why there was no response. If the first attempt fails,
- * we can't be sure the returned status is for the r/w command.
- */
- for (retry = 2; retry >= 0; retry--) {
- err = get_card_status(card, &status, 0);
- if (!err)
- break;
-
- prev_cmd_status_valid = false;
- pr_err("%s: error %d sending status command, %sing\n",
- req->rq_disk->disk_name, err, retry ? "retry" : "abort");
- }
-
- /* We couldn't get a response from the card. Give up. */
- if (err) {
- /* Check if the card is removed */
- if (mmc_detect_card_removed(card->host)) {
- DBG("[%s] e1\n",__func__);
- return ERR_NOMEDIUM;
- }
- DBG("[%s] e2\n",__func__);
- return ERR_ABORT;
- }
-
- /* Flag ECC errors */
- if ((status & R1_CARD_ECC_FAILED) ||
- (brq->stop.resp[0] & R1_CARD_ECC_FAILED) ||
- (brq->cmd.resp[0] & R1_CARD_ECC_FAILED))
- *ecc_err = 1;
-
- /*
- * Check the current card state. If it is in some data transfer
- * mode, tell it to stop (and hopefully transition back to TRAN.)
- */
- if (R1_CURRENT_STATE(status) == R1_STATE_DATA ||
- R1_CURRENT_STATE(status) == R1_STATE_RCV) {
- err = send_stop(card, &stop_status);
- if (err)
- pr_err("%s: error %d sending stop command\n",
- req->rq_disk->disk_name, err);
-
- /*
- * If the stop cmd also timed out, the card is probably
- * not present, so abort. Other errors are bad news too.
- */
- if (err) {
- DBG("[%s] e4\n",__func__);
- return ERR_ABORT;
- }
- if (stop_status & R1_CARD_ECC_FAILED)
- *ecc_err = 1;
- }
-
- /* Check for set block count errors */
- if (brq->sbc.error) {
- DBG("[%s] e5\n",__func__);
- return mmc_blk_cmd_error(req, "SET_BLOCK_COUNT", brq->sbc.error,
- prev_cmd_status_valid, status);
- }
- /* Check for r/w command errors */
- if (brq->cmd.error) {
- DBG("[%s] e6\n",__func__);
- return mmc_blk_cmd_error(req, "r/w cmd", brq->cmd.error,
- prev_cmd_status_valid, status);
- }
- /* Data errors */
- if (!brq->stop.error) {
- DBG("[%s] e7\n",__func__);
- return ERR_CONTINUE;
- }
-
- /* Now for stop errors. These aren't fatal to the transfer. */
- pr_err("%s: error %d sending stop command, original cmd response %#x, card status %#x\n",
- req->rq_disk->disk_name, brq->stop.error,
- brq->cmd.resp[0], status);
-
- /*
- * Subsitute in our own stop status as this will give the error
- * state which happened during the execution of the r/w command.
- */
- if (stop_status) {
- brq->stop.resp[0] = stop_status;
- brq->stop.error = 0;
- }
- DBG("[%s] e8\n",__func__);
- return ERR_CONTINUE;
-}
-
-static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,
- int type)
-{
- int err;
- DBG("[%s] s\n",__func__);
-
- if (md->reset_done & type) {
- DBG("[%s] e1\n",__func__);
- return -EEXIST;
- }
-
- md->reset_done |= type;
- err = mmc_hw_reset(host);
- /* Ensure we switch back to the correct partition */
- if (err != -EOPNOTSUPP) {
- struct mmc_blk_data *main_md = mmc_get_drvdata(host->card);
- int part_err;
-
- main_md->part_curr = main_md->part_type;
- part_err = mmc_blk_part_switch(host->card, md);
- if (part_err) {
- /*
- * We have failed to get back into the correct
- * partition, so we need to abort the whole request.
- */
- DBG("[%s] e2\n",__func__);
- return -ENODEV;
- }
- }
- DBG("[%s] e3\n",__func__);
- return err;
-}
-
-static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type)
-{
- DBG("[%s] s\n",__func__);
- md->reset_done &= ~type;
- DBG("[%s] e\n",__func__);
-}
-
-static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
-{
- struct mmc_blk_data *md = mq->data;
- struct mmc_card *card = md->queue.card;
- unsigned int from, nr, arg;
- int err = 0, type = MMC_BLK_DISCARD;
- DBG("[%s] s\n",__func__);
-
- if (!mmc_can_erase(card)) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- from = blk_rq_pos(req);
- nr = blk_rq_sectors(req);
-
- if (mmc_can_discard(card))
- arg = MMC_DISCARD_ARG;
- else if (mmc_can_trim(card))
- arg = MMC_TRIM_ARG;
- else
- arg = MMC_ERASE_ARG;
-retry:
- if (card->quirks & MMC_QUIRK_INAND_CMD38) {
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- INAND_CMD38_ARG_EXT_CSD,
- arg == MMC_TRIM_ARG ?
- INAND_CMD38_ARG_TRIM :
- INAND_CMD38_ARG_ERASE,
- 0);
- if (err)
- goto out;
- }
- err = mmc_erase(card, from, nr, arg);
-out:
- if (err == -EIO && !mmc_blk_reset(md, card->host, type))
- goto retry;
- if (!err)
- mmc_blk_reset_success(md, type);
- spin_lock_irq(&md->lock);
- __blk_end_request(req, err, blk_rq_bytes(req));
- spin_unlock_irq(&md->lock);
- DBG("[%s] e\n",__func__);
- return err ? 0 : 1;
-}
-
-static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
- struct request *req)
-{
- struct mmc_blk_data *md = mq->data;
- struct mmc_card *card = md->queue.card;
- unsigned int from, nr, arg, trim_arg, erase_arg;
- int err = 0, type = MMC_BLK_SECDISCARD;
- DBG("[%s] s\n",__func__);
-
- if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- from = blk_rq_pos(req);
- nr = blk_rq_sectors(req);
-
- /* The sanitize operation is supported at v4.5 only */
- if (mmc_can_sanitize(card)) {
- erase_arg = MMC_ERASE_ARG;
- trim_arg = MMC_TRIM_ARG;
- } else {
- erase_arg = MMC_SECURE_ERASE_ARG;
- trim_arg = MMC_SECURE_TRIM1_ARG;
- }
-
- if (mmc_erase_group_aligned(card, from, nr))
- arg = erase_arg;
- else if (mmc_can_trim(card))
- arg = trim_arg;
- else {
- err = -EINVAL;
- goto out;
- }
-retry:
- if (card->quirks & MMC_QUIRK_INAND_CMD38) {
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- INAND_CMD38_ARG_EXT_CSD,
- arg == MMC_SECURE_TRIM1_ARG ?
- INAND_CMD38_ARG_SECTRIM1 :
- INAND_CMD38_ARG_SECERASE,
- 0);
- if (err)
- goto out_retry;
- }
-
- err = mmc_erase(card, from, nr, arg);
- if (err == -EIO)
- goto out_retry;
- if (err)
- goto out;
-
- if (arg == MMC_SECURE_TRIM1_ARG) {
- if (card->quirks & MMC_QUIRK_INAND_CMD38) {
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- INAND_CMD38_ARG_EXT_CSD,
- INAND_CMD38_ARG_SECTRIM2,
- 0);
- if (err)
- goto out_retry;
- }
-
- err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG);
- if (err == -EIO)
- goto out_retry;
- if (err)
- goto out;
- }
-
- if (mmc_can_sanitize(card))
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_SANITIZE_START, 1, 0);
-out_retry:
- if (err && !mmc_blk_reset(md, card->host, type))
- goto retry;
- if (!err)
- mmc_blk_reset_success(md, type);
-out:
- spin_lock_irq(&md->lock);
- __blk_end_request(req, err, blk_rq_bytes(req));
- spin_unlock_irq(&md->lock);
- DBG("[%s] e\n",__func__);
- return err ? 0 : 1;
-}
-
-static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
-{
- struct mmc_blk_data *md = mq->data;
- struct mmc_card *card = md->queue.card;
- int ret = 0;
- DBG("[%s] s\n",__func__);
-
- ret = mmc_flush_cache(card);
- if (ret)
- ret = -EIO;
-
- spin_lock_irq(&md->lock);
- __blk_end_request_all(req, ret);
- spin_unlock_irq(&md->lock);
- DBG("[%s] e\n",__func__);
- return ret ? 0 : 1;
-}
-
-/*
- * Reformat current write as a reliable write, supporting
- * both legacy and the enhanced reliable write MMC cards.
- * In each transfer we'll handle only as much as a single
- * reliable write can handle, thus finish the request in
- * partial completions.
- */
-static inline void mmc_apply_rel_rw(struct mmc_blk_request *brq,
- struct mmc_card *card,
- struct request *req)
-{
- DBG("[%s] s\n",__func__);
- if (!(card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN)) {
- /* Legacy mode imposes restrictions on transfers. */
- if (!IS_ALIGNED(brq->cmd.arg, card->ext_csd.rel_sectors))
- brq->data.blocks = 1;
-
- if (brq->data.blocks > card->ext_csd.rel_sectors)
- brq->data.blocks = card->ext_csd.rel_sectors;
- else if (brq->data.blocks < card->ext_csd.rel_sectors)
- brq->data.blocks = 1;
- }
- DBG("[%s] e\n",__func__);
-}
-
-#define CMD_ERRORS \
- (R1_OUT_OF_RANGE | /* Command argument out of range */ \
- R1_ADDRESS_ERROR | /* Misaligned address */ \
- R1_BLOCK_LEN_ERROR | /* Transferred block length incorrect */\
- R1_WP_VIOLATION | /* Tried to write to protected block */ \
- R1_CC_ERROR | /* Card controller error */ \
- R1_ERROR) /* General/unknown error */
-
-static int mmc_blk_err_check(struct mmc_card *card,
- struct mmc_async_req *areq)
-{
- struct mmc_queue_req *mq_mrq = container_of(areq, struct mmc_queue_req,
- mmc_active);
- struct mmc_blk_request *brq = &mq_mrq->brq;
- struct request *req = mq_mrq->req;
- int ecc_err = 0;
- DBG("[%s] s\n",__func__);
- /*
- * sbc.error indicates a problem with the set block count
- * command. No data will have been transferred.
- *
- * cmd.error indicates a problem with the r/w command. No
- * data will have been transferred.
- *
- * stop.error indicates a problem with the stop command. Data
- * may have been transferred, or may still be transferring.
- */
- if (brq->sbc.error || brq->cmd.error || brq->stop.error ||
- brq->data.error) {
- switch (mmc_blk_cmd_recovery(card, req, brq, &ecc_err)) {
- case ERR_RETRY:
- return MMC_BLK_RETRY;
- case ERR_ABORT:
- return MMC_BLK_ABORT;
- case ERR_NOMEDIUM:
- return MMC_BLK_NOMEDIUM;
- case ERR_CONTINUE:
- break;
- }
- }
-
- /*
- * Check for errors relating to the execution of the
- * initial command - such as address errors. No data
- * has been transferred.
- */
- if (brq->cmd.resp[0] & CMD_ERRORS) {
- pr_err("%s: r/w command failed, status = %#x\n",
- req->rq_disk->disk_name, brq->cmd.resp[0]);
- DBG("[%s] e1\n",__func__);
- return MMC_BLK_ABORT;
- }
-
- /*
- * Everything else is either success, or a data error of some
- * kind. If it was a write, we may have transitioned to
- * program mode, which we have to wait for it to complete.
- */
- if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
- u32 status;
- do {
- int err = get_card_status(card, &status, 5);
- if (err) {
- pr_err("%s: error %d requesting status\n",
- req->rq_disk->disk_name, err);
- DBG("[%s] e2\n",__func__);
- return MMC_BLK_CMD_ERR;
- }
- /*
- * Some cards mishandle the status bits,
- * so make sure to check both the busy
- * indication and the card state.
- */
- } while (!(status & R1_READY_FOR_DATA) ||
- (R1_CURRENT_STATE(status) == R1_STATE_PRG));
- }
-
- if (brq->data.error) {
- pr_err("%s: error %d transferring data, sector %u, nr %u, cmd response %#x, card status %#x\n",
- req->rq_disk->disk_name, brq->data.error,
- (unsigned)blk_rq_pos(req),
- (unsigned)blk_rq_sectors(req),
- brq->cmd.resp[0], brq->stop.resp[0]);
-
- if (rq_data_dir(req) == READ) {
- if (ecc_err) {
- DBG("[%s] e3\n",__func__);
- return MMC_BLK_ECC_ERR;
- }
- DBG("[%s] e4\n",__func__);
- return MMC_BLK_DATA_ERR;
- } else {
- DBG("[%s] e5\n",__func__);
- return MMC_BLK_CMD_ERR;
- }
- }
-
- if (!brq->data.bytes_xfered) {
- DBG("[%s] e6\n",__func__);
- return MMC_BLK_RETRY;
- }
-
- if (blk_rq_bytes(req) != brq->data.bytes_xfered) {
- DBG("[%s] e7\n",__func__);
- return MMC_BLK_PARTIAL;
- }
-
- DBG("[%s] e8\n",__func__);
- return MMC_BLK_SUCCESS;
-}
-
-static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
- struct mmc_card *card,
- int disable_multi,
- struct mmc_queue *mq)
-{
- u32 readcmd, writecmd;
- struct mmc_blk_request *brq = &mqrq->brq;
- struct request *req = mqrq->req;
- struct mmc_blk_data *md = mq->data;
- bool do_data_tag;
-
- /*
- * Reliable writes are used to implement Forced Unit Access and
- * REQ_META accesses, and are supported only on MMCs.
- *
- * XXX: this really needs a good explanation of why REQ_META
- * is treated special.
- */
- bool do_rel_wr = ((req->cmd_flags & REQ_FUA) ||
- (req->cmd_flags & REQ_META)) &&
- (rq_data_dir(req) == WRITE) &&
- (md->flags & MMC_BLK_REL_WR);
- DBG("[%s] s\n",__func__);
- memset(brq, 0, sizeof(struct mmc_blk_request));
- brq->mrq.cmd = &brq->cmd;
- brq->mrq.data = &brq->data;
-
- brq->cmd.arg = blk_rq_pos(req);
- if (!mmc_card_blockaddr(card))
- brq->cmd.arg <<= 9;
- //brq->cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
- brq->cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
- brq->data.blksz = 512;
- brq->stop.opcode = MMC_STOP_TRANSMISSION;
- brq->stop.arg = 0;
- //brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
- brq->stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
- brq->data.blocks = blk_rq_sectors(req);
-
- /*
- * The block layer doesn't support all sector count
- * restrictions, so we need to be prepared for too big
- * requests.
- */
- if (brq->data.blocks > card->host->max_blk_count)
- brq->data.blocks = card->host->max_blk_count;
-
- if (brq->data.blocks > 1) {
- /*
- * After a read error, we redo the request one sector
- * at a time in order to accurately determine which
- * sectors can be read successfully.
- */
- if (disable_multi)
- brq->data.blocks = 1;
-
- /* Some controllers can't do multiblock reads due to hw bugs */
- if (card->host->caps2 & MMC_CAP2_NO_MULTI_READ &&
- rq_data_dir(req) == READ)
- brq->data.blocks = 1;
- }
-
- if (brq->data.blocks > 1 || do_rel_wr) {
- /* SPI multiblock writes terminate using a special
- * token, not a STOP_TRANSMISSION request.
- */
- if (!mmc_host_is_spi(card->host) ||
- rq_data_dir(req) == READ)
- brq->mrq.stop = &brq->stop;
- readcmd = MMC_READ_MULTIPLE_BLOCK;
- writecmd = MMC_WRITE_MULTIPLE_BLOCK;
- } else {
- brq->mrq.stop = NULL;
- 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;
- } else {
- brq->cmd.opcode = writecmd;
- brq->data.flags |= MMC_DATA_WRITE;
- }
-
- if (do_rel_wr)
- mmc_apply_rel_rw(brq, card, req);
-
- /*
- * Data tag is used only during writing meta data to speed
- * up write and any subsequent read of this meta data
- */
- do_data_tag = (card->ext_csd.data_tag_unit_size) &&
- (req->cmd_flags & REQ_META) &&
- (rq_data_dir(req) == WRITE) &&
- ((brq->data.blocks * brq->data.blksz) >=
- card->ext_csd.data_tag_unit_size);
-
- /*
- * Pre-defined multi-block transfers are preferable to
- * open ended-ones (and necessary for reliable writes).
- * However, it is not sufficient to just send CMD23,
- * and avoid the final CMD12, as on an error condition
- * CMD12 (stop) needs to be sent anyway. This, coupled
- * with Auto-CMD23 enhancements provided by some
- * hosts, means that the complexity of dealing
- * with this is best left to the host. If CMD23 is
- * supported by card and host, we'll fill sbc in and let
- * the host deal with handling it correctly. This means
- * that for hosts that don't expose MMC_CAP_CMD23, no
- * change of behavior will be observed.
- *
- * N.B: Some MMC cards experience perf degradation.
- * We'll avoid using CMD23-bounded multiblock writes for
- * these, while retaining features like reliable writes.
- */
- if ((md->flags & MMC_BLK_CMD23) && mmc_op_multi(brq->cmd.opcode) &&
- (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23) ||
- do_data_tag)) {
- brq->sbc.opcode = MMC_SET_BLOCK_COUNT;
- brq->sbc.arg = brq->data.blocks |
- (do_rel_wr ? (1 << 31) : 0) |
- (do_data_tag ? (1 << 29) : 0);
- brq->sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
- brq->mrq.sbc = &brq->sbc;
- }
-
- mmc_set_data_timeout(&brq->data, card);
-
- brq->data.sg = mqrq->sg;
- brq->data.sg_len = mmc_queue_map_sg(mq, mqrq);
-
- /*
- * Adjust the sg list so it is the same size as the
- * request.
- */
- if (brq->data.blocks != blk_rq_sectors(req)) {
- int i, data_size = brq->data.blocks << 9;
- struct scatterlist *sg;
-
- for_each_sg(brq->data.sg, sg, brq->data.sg_len, i) {
- data_size -= sg->length;
- if (data_size <= 0) {
- sg->length += data_size;
- i++;
- break;
- }
- }
- brq->data.sg_len = i;
- }
-
- mqrq->mmc_active.mrq = &brq->mrq;
- mqrq->mmc_active.err_check = mmc_blk_err_check;
-
- mmc_queue_bounce_pre(mqrq);
- DBG("[%s] e\n",__func__);
-}
-
-static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card,
- struct mmc_blk_request *brq, struct request *req,
- int ret)
-{
- DBG("[%s] s\n",__func__);
- /*
- * If this is an SD card and we're writing, we can first
- * mark the known good sectors as ok.
- *
- * If the card is not SD, we can still ok written sectors
- * as reported by the controller (which might be less than
- * the real number of written sectors, but never more).
- */
- if (mmc_card_sd(card)) {
- u32 blocks;
-
- blocks = mmc_sd_num_wr_blocks(card);
- if (blocks != (u32)-1) {
- spin_lock_irq(&md->lock);
- ret = __blk_end_request(req, 0, blocks << 9);
- spin_unlock_irq(&md->lock);
- }
- } else {
- spin_lock_irq(&md->lock);
- ret = __blk_end_request(req, 0, brq->data.bytes_xfered);
- spin_unlock_irq(&md->lock);
- }
- DBG("[%s] e\n",__func__);
- return ret;
-}
-
-static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
-{
- struct mmc_blk_data *md = mq->data;
- struct mmc_card *card = md->queue.card;
- struct mmc_blk_request *brq = &mq->mqrq_cur->brq;
- int ret = 1, disable_multi = 0, retry = 0, type;
- enum mmc_blk_status status;
- struct mmc_queue_req *mq_rq;
- struct request *req;
- struct mmc_async_req *areq;
- DBG("[%s] s\n",__func__);
-
- if (!rqc && !mq->mqrq_prev->req) {
- DBG("[%s] e1\n",__func__);
- return 0;
- }
-
- do {
- if (rqc) {
- mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
- areq = &mq->mqrq_cur->mmc_active;
- } else
- areq = NULL;
- areq = mmc_start_req(card->host, areq, (int *) &status);
- if (!areq) {
- DBG("[%s] e2\n",__func__);
- return 0;
- }
-
- mq_rq = container_of(areq, struct mmc_queue_req, mmc_active);
- brq = &mq_rq->brq;
- req = mq_rq->req;
- type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
- mmc_queue_bounce_post(mq_rq);
-
- switch (status) {
- case MMC_BLK_SUCCESS:
- case MMC_BLK_PARTIAL:
- /*
- * A block was successfully transferred.
- */
- mmc_blk_reset_success(md, type);
- spin_lock_irq(&md->lock);
- ret = __blk_end_request(req, 0,
- brq->data.bytes_xfered);
- spin_unlock_irq(&md->lock);
- /*
- * If the blk_end_request function returns non-zero even
- * though all data has been transferred and no errors
- * were returned by the host controller, it's a bug.
- */
- if (status == MMC_BLK_SUCCESS && ret) {
- pr_err("%s BUG rq_tot %d d_xfer %d\n",
- __func__, blk_rq_bytes(req),
- brq->data.bytes_xfered);
- rqc = NULL;
- goto cmd_abort;
- }
- break;
- case MMC_BLK_CMD_ERR:
- ret = mmc_blk_cmd_err(md, card, brq, req, ret);
- if (!mmc_blk_reset(md, card->host, type))
- break;
- goto cmd_abort;
- case MMC_BLK_RETRY:
- if (retry++ < 5)
- break;
- /* Fall through */
- case MMC_BLK_ABORT:
- if (!mmc_blk_reset(md, card->host, type))
- break;
- goto cmd_abort;
- case MMC_BLK_DATA_ERR: {
- int err;
-
- err = mmc_blk_reset(md, card->host, type);
- if (!err)
- break;
- if (err == -ENODEV)
- goto cmd_abort;
- /* Fall through */
- }
- case MMC_BLK_ECC_ERR:
- if (brq->data.blocks > 1) {
- /* Redo read one sector at a time */
- pr_warning("%s: retrying using single block read\n",
- req->rq_disk->disk_name);
- disable_multi = 1;
- break;
- }
- /*
- * After an error, we redo I/O one sector at a
- * time, so we only reach here after trying to
- * read a single sector.
- */
- spin_lock_irq(&md->lock);
- ret = __blk_end_request(req, -EIO,
- brq->data.blksz);
- spin_unlock_irq(&md->lock);
- if (!ret)
- goto start_new_req;
- break;
- case MMC_BLK_NOMEDIUM:
- goto cmd_abort;
- }
-
- if (ret) {
- /*
- * In case of a incomplete request
- * prepare it again and resend.
- */
- mmc_blk_rw_rq_prep(mq_rq, card, disable_multi, mq);
- mmc_start_req(card->host, &mq_rq->mmc_active, NULL);
- }
- } while (ret);
- DBG("[%s] e3\n",__func__);
- return 1;
-
- cmd_abort:
- spin_lock_irq(&md->lock);
- if (mmc_card_removed(card))
- req->cmd_flags |= REQ_QUIET;
- while (ret)
- ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
- spin_unlock_irq(&md->lock);
-
- start_new_req:
- if (rqc) {
- mmc_blk_rw_rq_prep(mq->mqrq_cur, card, 0, mq);
- mmc_start_req(card->host, &mq->mqrq_cur->mmc_active, NULL);
- }
- DBG("[%s] e4\n",__func__);
- return 0;
-}
-
-static int
-mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card);
-
-static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
-{
- int ret;
- struct mmc_blk_data *md = mq->data;
- struct mmc_card *card = md->queue.card;
- DBG("[%s] s\n",__func__);
-
-#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
- if (mmc_bus_needs_resume(card->host)) {
- mmc_resume_bus(card->host);
- mmc_blk_set_blksize(md, card);
- }
-#endif
-
- if (req && !mq->mqrq_prev->req)
- /* claim host only for the first request */
- mmc_claim_host(card->host);
-
-#ifdef CONFIG_MMC_UNSAFE_RESUME
-/*
- if(card->host->card_attath_status == card_attach_status_change) {
- goto cmd_err;
- }
-*/
-#endif
-
- ret = mmc_blk_part_switch(card, md);
- if (ret) {
- if (req) {
- spin_lock_irq(&md->lock);
- __blk_end_request_all(req, -EIO);
- spin_unlock_irq(&md->lock);
- }
- ret = 0;
- goto out;
- }
-
- if (req && req->cmd_flags & REQ_DISCARD) {
- /* complete ongoing async transfer before issuing discard */
- if (card->host->areq)
- mmc_blk_issue_rw_rq(mq, NULL);
- if (req->cmd_flags & REQ_SECURE)
- ret = mmc_blk_issue_secdiscard_rq(mq, req);
- else
- ret = mmc_blk_issue_discard_rq(mq, req);
- } else if (req && req->cmd_flags & REQ_FLUSH) {
- /* complete ongoing async transfer before issuing flush */
- if (card->host->areq)
- mmc_blk_issue_rw_rq(mq, NULL);
- ret = mmc_blk_issue_flush(mq, req);
- } else {
- ret = mmc_blk_issue_rw_rq(mq, req);
- }
-
-out:
- if (!req)
- /* release host only when there are no more requests */
- mmc_release_host(card->host);
- DBG("[%s] e\n",__func__);
- return ret;
-}
-
-static inline int mmc_blk_readonly(struct mmc_card *card)
-{
- DBG("[%s] s\n",__func__);
- return mmc_card_readonly(card) ||
- !(card->csd.cmdclass & CCC_BLOCK_WRITE);
-}
-
-static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
- struct device *parent,
- sector_t size,
- bool default_ro,
- const char *subname,
- int area_type)
-{
- struct mmc_blk_data *md;
- int devidx, ret;
- DBG("[%s] s\n",__func__);
-
- devidx = find_first_zero_bit(dev_use, max_devices);
- if (devidx >= max_devices) {
- DBG("[%s] e1\n",__func__);
- return ERR_PTR(-ENOSPC);
- }
- __set_bit(devidx, dev_use);
-
- md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
- if (!md) {
- ret = -ENOMEM;
- goto out;
- }
-
- /*
- * !subname implies we are creating main mmc_blk_data that will be
- * associated with mmc_card with mmc_set_drvdata. Due to device
- * partitions, devidx will not coincide with a per-physical card
- * index anymore so we keep track of a name index.
- */
- if (!subname) {
- md->name_idx = find_first_zero_bit(name_use, max_devices);
- __set_bit(md->name_idx, name_use);
- } else
- md->name_idx = ((struct mmc_blk_data *)
- dev_to_disk(parent)->private_data)->name_idx;
-
- md->area_type = area_type;
-
- /*
- * Set the read-only status based on the supported commands
- * and the write protect switch.
- */
- md->read_only = mmc_blk_readonly(card);
-
- md->disk = alloc_disk(perdev_minors);
- if (md->disk == NULL) {
- ret = -ENOMEM;
- goto err_kfree;
- }
-
- spin_lock_init(&md->lock);
- INIT_LIST_HEAD(&md->part);
- md->usage = 1;
-
- ret = mmc_init_queue(&md->queue, card, &md->lock, subname);
- if (ret)
- goto err_putdisk;
-
- md->queue.issue_fn = mmc_blk_issue_rq;
- md->queue.data = md;
-
- md->disk->major = MMC_BLOCK_MAJOR;
- md->disk->first_minor = devidx * perdev_minors;
- md->disk->fops = &mmc_bdops;
- md->disk->private_data = md;
- md->disk->queue = md->queue.queue;
- md->disk->driverfs_dev = parent;
- set_disk_ro(md->disk, md->read_only || default_ro);
- md->disk->flags = GENHD_FL_EXT_DEVT;
-
- /*
- * As discussed on lkml, GENHD_FL_REMOVABLE should:
- *
- * - be set for removable media with permanent block devices
- * - be unset for removable block devices with permanent media
- *
- * Since MMC block devices clearly fall under the second
- * case, we do not set GENHD_FL_REMOVABLE. Userspace
- * should use the block device creation/destruction hotplug
- * messages to tell when the card is present.
- */
-
- /*snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
- "mmcblk%d%s", md->name_idx, subname ? subname : "");*/
-
- snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
- "mmcblk%d%s", card->host->wmt_host_index, subname ? subname : "");
-
- blk_queue_logical_block_size(md->queue.queue, 512);
- set_capacity(md->disk, size);
-
- if (mmc_host_cmd23(card->host)) {
- if (mmc_card_mmc(card) ||
- (mmc_card_sd(card) &&
- card->scr.cmds & SD_SCR_CMD23_SUPPORT))
- md->flags |= MMC_BLK_CMD23;
- }
-
- if (mmc_card_mmc(card) &&
- md->flags & MMC_BLK_CMD23 &&
- ((card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN) ||
- card->ext_csd.rel_sectors)) {
- md->flags |= MMC_BLK_REL_WR;
- blk_queue_flush(md->queue.queue, REQ_FLUSH | REQ_FUA);
- }
- DBG("[%s] e2\n",__func__);
- return md;
-
- err_putdisk:
- put_disk(md->disk);
- err_kfree:
- kfree(md);
- out:
- DBG("[%s] e3\n",__func__);
- return ERR_PTR(ret);
-}
-
-static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
-{
- sector_t size;
- struct mmc_blk_data *md;
- DBG("[%s] s\n",__func__);
-
- if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
- /*
- * The EXT_CSD sector count is in number or 512 byte
- * sectors.
- */
- size = card->ext_csd.sectors;
- } else {
- /*
- * The CSD capacity field is in units of read_blkbits.
- * set_capacity takes units of 512 bytes.
- */
- size = card->csd.capacity << (card->csd.read_blkbits - 9);
- }
-
- md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL,
- MMC_BLK_DATA_AREA_MAIN);
- DBG("[%s] e\n",__func__);
- return md;
-}
-
-static int mmc_blk_alloc_part(struct mmc_card *card,
- struct mmc_blk_data *md,
- unsigned int part_type,
- sector_t size,
- bool default_ro,
- const char *subname,
- int area_type)
-{
- char cap_str[10];
- struct mmc_blk_data *part_md;
- DBG("[%s] s\n",__func__);
-
- part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro,
- subname, area_type);
- if (IS_ERR(part_md)) {
- DBG("[%s] e1\n",__func__);
- return PTR_ERR(part_md);
- }
- part_md->part_type = part_type;
- list_add(&part_md->part, &md->part);
-
- string_get_size((u64)get_capacity(part_md->disk) << 9, STRING_UNITS_2,
- cap_str, sizeof(cap_str));
- pr_info("%s: %s %s partition %u %s\n",
- part_md->disk->disk_name, mmc_card_id(card),
- mmc_card_name(card), part_md->part_type, cap_str);
- DBG("[%s] e2\n",__func__);
- return 0;
-}
-
-/* MMC Physical partitions consist of two boot partitions and
- * up to four general purpose partitions.
- * For each partition enabled in EXT_CSD a block device will be allocatedi
- * to provide access to the partition.
- */
-
-static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
-{
- int idx, ret = 0;
- DBG("[%s] s\n",__func__);
-
- if (!mmc_card_mmc(card)) {
- DBG("[%s] e1\n",__func__);
- return 0;
- }
-
- for (idx = 0; idx < card->nr_parts; idx++) {
- if (card->part[idx].size) {
- ret = mmc_blk_alloc_part(card, md,
- card->part[idx].part_cfg,
- card->part[idx].size >> 9,
- card->part[idx].force_ro,
- card->part[idx].name,
- card->part[idx].area_type);
- if (ret) {
- DBG("[%s] e2\n",__func__);
- return ret;
- }
- }
- }
- DBG("[%s] e3\n",__func__);
- return ret;
-}
-
-static void mmc_blk_remove_req(struct mmc_blk_data *md)
-{
- struct mmc_card *card;
- DBG("[%s] s\n",__func__);
-
- if (md) {
- card = md->queue.card;
- if (md->disk->flags & GENHD_FL_UP) {
- device_remove_file(disk_to_dev(md->disk), &md->force_ro);
- if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
- card->ext_csd.boot_ro_lockable)
- device_remove_file(disk_to_dev(md->disk),
- &md->power_ro_lock);
-
- /* Stop new requests from getting into the queue */
- del_gendisk(md->disk);
- }
-
- /* Then flush out any already in there */
- mmc_cleanup_queue(&md->queue);
- mmc_blk_put(md);
- }
- DBG("[%s] e\n",__func__);
-}
-
-static void mmc_blk_remove_parts(struct mmc_card *card,
- struct mmc_blk_data *md)
-{
- struct list_head *pos, *q;
- struct mmc_blk_data *part_md;
- DBG("[%s] s\n",__func__);
-
- __clear_bit(md->name_idx, name_use);
- list_for_each_safe(pos, q, &md->part) {
- part_md = list_entry(pos, struct mmc_blk_data, part);
- list_del(pos);
- mmc_blk_remove_req(part_md);
- }
- DBG("[%s] e\n",__func__);
-}
-
-static int mmc_add_disk(struct mmc_blk_data *md)
-{
- int ret;
- struct mmc_card *card = md->queue.card;
- DBG("[%s] s\n",__func__);
-
- add_disk(md->disk);
- md->force_ro.show = force_ro_show;
- md->force_ro.store = force_ro_store;
- sysfs_attr_init(&md->force_ro.attr);
- md->force_ro.attr.name = "force_ro";
- md->force_ro.attr.mode = S_IRUGO | S_IWUSR;
- ret = device_create_file(disk_to_dev(md->disk), &md->force_ro);
- if (ret)
- goto force_ro_fail;
-
- if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
- card->ext_csd.boot_ro_lockable) {
- umode_t mode;
-
- if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_DIS)
- mode = S_IRUGO;
- else
- mode = S_IRUGO | S_IWUSR;
-
- md->power_ro_lock.show = power_ro_lock_show;
- md->power_ro_lock.store = power_ro_lock_store;
- sysfs_attr_init(&md->power_ro_lock.attr);
- md->power_ro_lock.attr.mode = mode;
- md->power_ro_lock.attr.name =
- "ro_lock_until_next_power_on";
- ret = device_create_file(disk_to_dev(md->disk),
- &md->power_ro_lock);
- if (ret)
- goto power_ro_lock_fail;
- }
- DBG("[%s] e1\n",__func__);
- return ret;
-
-power_ro_lock_fail:
- device_remove_file(disk_to_dev(md->disk), &md->force_ro);
-force_ro_fail:
- del_gendisk(md->disk);
- DBG("[%s] e2\n",__func__);
- return ret;
-}
-
-#define CID_MANFID_SANDISK 0x2
-#define CID_MANFID_TOSHIBA 0x11
-#define CID_MANFID_MICRON 0x13
-
-static const struct mmc_fixup blk_fixups[] =
-{
- MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk,
- MMC_QUIRK_INAND_CMD38),
- MMC_FIXUP("SEM04G", CID_MANFID_SANDISK, 0x100, add_quirk,
- MMC_QUIRK_INAND_CMD38),
- MMC_FIXUP("SEM08G", CID_MANFID_SANDISK, 0x100, add_quirk,
- MMC_QUIRK_INAND_CMD38),
- MMC_FIXUP("SEM16G", CID_MANFID_SANDISK, 0x100, add_quirk,
- MMC_QUIRK_INAND_CMD38),
- MMC_FIXUP("SEM32G", CID_MANFID_SANDISK, 0x100, add_quirk,
- MMC_QUIRK_INAND_CMD38),
-
- /*
- * Some MMC cards experience performance degradation with CMD23
- * instead of CMD12-bounded multiblock transfers. For now we'll
- * black list what's bad...
- * - Certain Toshiba cards.
- *
- * N.B. This doesn't affect SD cards.
- */
- MMC_FIXUP("MMC08G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
- MMC_QUIRK_BLK_NO_CMD23),
- MMC_FIXUP("MMC16G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
- MMC_QUIRK_BLK_NO_CMD23),
- MMC_FIXUP("MMC32G", CID_MANFID_TOSHIBA, CID_OEMID_ANY, add_quirk_mmc,
- MMC_QUIRK_BLK_NO_CMD23),
-
- /*
- * Some Micron MMC cards needs longer data read timeout than
- * indicated in CSD.
- */
- MMC_FIXUP(CID_NAME_ANY, CID_MANFID_MICRON, 0x200, add_quirk_mmc,
- MMC_QUIRK_LONG_READ_TIME),
-
- END_FIXUP
-};
-
-static int mmc_blk_probe(struct mmc_card *card)
-{
- struct mmc_blk_data *md, *part_md;
- char cap_str[10];
- DBG("[%s] s\n",__func__);
- /*
- * Check that the card supports the command class(es) we need.
- */
- if (!(card->csd.cmdclass & CCC_BLOCK_READ)) {
- DBG("[%s] e1\n",__func__);
- return -ENODEV;
- }
- md = mmc_blk_alloc(card);
- if (IS_ERR(md)) {
- DBG("[%s] e2\n",__func__);
- return PTR_ERR(md);
- }
-
- string_get_size((u64)get_capacity(md->disk) << 9, STRING_UNITS_2,
- cap_str, sizeof(cap_str));
- pr_info("%s: %s %s %s %s\n",
- md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
- cap_str, md->read_only ? "(ro)" : "");
-
- if (mmc_blk_alloc_parts(card, md))
- goto out;
-
- mmc_set_drvdata(card, md);
- mmc_fixup_device(card, blk_fixups);
-
-#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
- mmc_set_bus_resume_policy(card->host, 1);
-#endif
- if (mmc_add_disk(md))
- goto out;
-
- list_for_each_entry(part_md, &md->part, part) {
- if (mmc_add_disk(part_md))
- goto out;
- }
-
- DBG("[%s] e3\n",__func__);
- return 0;
-
- out:
- mmc_blk_remove_parts(card, md);
- mmc_blk_remove_req(md);
- DBG("[%s] e4\n",__func__);
- return 0;
-}
-
-static void mmc_blk_remove(struct mmc_card *card)
-{
- struct mmc_blk_data *md = mmc_get_drvdata(card);
- DBG("[%s] s\n",__func__);
-
- mmc_blk_remove_parts(card, md);
- mmc_claim_host(card->host);
- mmc_blk_part_switch(card, md);
- mmc_release_host(card->host);
- mmc_blk_remove_req(md);
- mmc_set_drvdata(card, NULL);
-#ifdef CONFIG_MMC_BLOCK_DEFERRED_RESUME
- mmc_set_bus_resume_policy(card->host, 0);
-#endif
- DBG("[%s] e\n",__func__);
-}
-
-#ifdef CONFIG_PM
-static int mmc_blk_suspend(struct mmc_card *card)
-{
- struct mmc_blk_data *part_md;
- struct mmc_blk_data *md = mmc_get_drvdata(card);
- DBG("[%s] s\n",__func__);
-
- if (md) {
- mmc_queue_suspend(&md->queue);
- list_for_each_entry(part_md, &md->part, part) {
- mmc_queue_suspend(&part_md->queue);
- }
- }
- DBG("[%s] e\n",__func__);
- return 0;
-}
-
-static int mmc_blk_resume(struct mmc_card *card)
-{
- struct mmc_blk_data *part_md;
- struct mmc_blk_data *md = mmc_get_drvdata(card);
- DBG("[%s] s\n",__func__);
-
- if (md) {
- /*
- * Resume involves the card going into idle state,
- * so current partition is always the main one.
- */
- md->part_curr = md->part_type;
- mmc_queue_resume(&md->queue);
- list_for_each_entry(part_md, &md->part, part) {
- mmc_queue_resume(&part_md->queue);
- }
- }
- DBG("[%s] e\n",__func__);
- return 0;
-}
-#else
-#define mmc_blk_suspend NULL
-#define mmc_blk_resume NULL
-#endif
-
-static struct mmc_driver mmc_driver = {
- .drv = {
- .name = "mmcblk",
- },
- .probe = mmc_blk_probe,
- .remove = mmc_blk_remove,
- .suspend = mmc_blk_suspend,
- .resume = mmc_blk_resume,
-};
-
-static int __init mmc_blk_init(void)
-{
- int res;
- DBG("[%s] s\n",__func__);
-
- 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;
-
- res = mmc_register_driver(&mmc_driver);
- if (res)
- goto out2;
- DBG("[%s] e1\n",__func__);
- return 0;
- out2:
- unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
- out:
- DBG("[%s] e2\n",__func__);
- return res;
-}
-
-static void __exit mmc_blk_exit(void)
-{
- DBG("[%s] s\n",__func__);
- mmc_unregister_driver(&mmc_driver);
- unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
- DBG("[%s] e\n",__func__);
-}
-
-module_init(mmc_blk_init);
-module_exit(mmc_blk_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");
-
diff --git a/ANDROID_3.4.5/drivers/mmc/card/mmc_test.c b/ANDROID_3.4.5/drivers/mmc/card/mmc_test.c
deleted file mode 100644
index 759714ed..00000000
--- a/ANDROID_3.4.5/drivers/mmc/card/mmc_test.c
+++ /dev/null
@@ -1,3055 +0,0 @@
-/*
- * linux/drivers/mmc/card/mmc_test.c
- *
- * Copyright 2007-2008 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/mmc/core.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/mmc.h>
-#include <linux/slab.h>
-
-#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>
-#include <linux/module.h>
-
-#define RESULT_OK 0
-#define RESULT_FAIL 1
-#define RESULT_UNSUP_HOST 2
-#define RESULT_UNSUP_CARD 3
-
-#define BUFFER_ORDER 2
-#define BUFFER_SIZE (PAGE_SIZE << BUFFER_ORDER)
-
-/*
- * Limit the test area size to the maximum MMC HC erase group size. Note that
- * the maximum SD allocation unit size is just 4MiB.
- */
-#define TEST_AREA_MAX_SIZE (128 * 1024 * 1024)
-
-/**
- * struct mmc_test_pages - pages allocated by 'alloc_pages()'.
- * @page: first page in the allocation
- * @order: order of the number of pages allocated
- */
-struct mmc_test_pages {
- struct page *page;
- unsigned int order;
-};
-
-/**
- * struct mmc_test_mem - allocated memory.
- * @arr: array of allocations
- * @cnt: number of allocations
- */
-struct mmc_test_mem {
- struct mmc_test_pages *arr;
- unsigned int cnt;
-};
-
-/**
- * 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_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
- * @sg: scatterlist
- */
-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
- * @iops: I/O operations per second (times 100)
- */
-struct mmc_test_transfer_result {
- struct list_head link;
- unsigned int count;
- unsigned int sectors;
- struct timespec ts;
- unsigned int rate;
- unsigned int iops;
-};
-
-/**
- * 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
- * @scratch: transfer buffer
- * @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;
-
- u8 scratch[BUFFER_SIZE];
- u8 *buffer;
-#ifdef CONFIG_HIGHMEM
- struct page *highmem;
-#endif
- struct mmc_test_area area;
- struct mmc_test_general_result *gr;
-};
-
-enum mmc_test_prep_media {
- MMC_TEST_PREP_NONE = 0,
- MMC_TEST_PREP_WRITE_FULL = 1 << 0,
- MMC_TEST_PREP_ERASE = 1 << 1,
-};
-
-struct mmc_test_multiple_rw {
- unsigned int *sg_len;
- unsigned int *bs;
- unsigned int len;
- unsigned int size;
- bool do_write;
- bool do_nonblock_req;
- enum mmc_test_prep_media prepare;
-};
-
-struct mmc_test_async_req {
- struct mmc_async_req areq;
- struct mmc_test_card *test;
-};
-
-/*******************************************************************/
-/* General helper functions */
-/*******************************************************************/
-
-/*
- * Configure correct block size in card
- */
-static int mmc_test_set_blksize(struct mmc_test_card *test, unsigned size)
-{
- return mmc_set_blocklen(test->card, size);
-}
-
-/*
- * Fill in the mmc_request structure given a set of transfer parameters.
- */
-static void mmc_test_prepare_mrq(struct mmc_test_card *test,
- struct mmc_request *mrq, struct scatterlist *sg, unsigned sg_len,
- unsigned dev_addr, unsigned blocks, unsigned blksz, int write)
-{
- BUG_ON(!mrq || !mrq->cmd || !mrq->data || !mrq->stop);
-
- if (blocks > 1) {
- mrq->cmd->opcode = write ?
- MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK;
- } else {
- mrq->cmd->opcode = write ?
- MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK;
- }
-
- mrq->cmd->arg = dev_addr;
- if (!mmc_card_blockaddr(test->card))
- mrq->cmd->arg <<= 9;
-
- mrq->cmd->flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
- if (blocks == 1)
- mrq->stop = NULL;
- else {
- mrq->stop->opcode = MMC_STOP_TRANSMISSION;
- mrq->stop->arg = 0;
- mrq->stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
- }
-
- mrq->data->blksz = blksz;
- mrq->data->blocks = blocks;
- mrq->data->flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
- mrq->data->sg = sg;
- mrq->data->sg_len = sg_len;
-
- mmc_set_data_timeout(mrq->data, test->card);
-}
-
-static int mmc_test_busy(struct mmc_command *cmd)
-{
- return !(cmd->resp[0] & R1_READY_FOR_DATA) ||
- (R1_CURRENT_STATE(cmd->resp[0]) == R1_STATE_PRG);
-}
-
-/*
- * Wait for the card to finish the busy state
- */
-static int mmc_test_wait_busy(struct mmc_test_card *test)
-{
- int ret, busy;
- struct mmc_command cmd = {0};
-
- busy = 0;
- do {
- memset(&cmd, 0, sizeof(struct mmc_command));
-
- cmd.opcode = MMC_SEND_STATUS;
- cmd.arg = test->card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
- ret = mmc_wait_for_cmd(test->card->host, &cmd, 0);
- if (ret)
- break;
-
- if (!busy && mmc_test_busy(&cmd)) {
- busy = 1;
- if (test->card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
- pr_info("%s: Warning: Host did not "
- "wait for busy state to end.\n",
- mmc_hostname(test->card->host));
- }
- } while (mmc_test_busy(&cmd));
-
- return ret;
-}
-
-/*
- * Transfer a single sector of kernel addressable data
- */
-static int mmc_test_buffer_transfer(struct mmc_test_card *test,
- u8 *buffer, unsigned addr, unsigned blksz, int write)
-{
- int ret;
-
- struct mmc_request mrq = {0};
- struct mmc_command cmd = {0};
- struct mmc_command stop = {0};
- struct mmc_data data = {0};
-
- struct scatterlist sg;
-
- mrq.cmd = &cmd;
- mrq.data = &data;
- mrq.stop = &stop;
-
- sg_init_one(&sg, buffer, blksz);
-
- mmc_test_prepare_mrq(test, &mrq, &sg, 1, addr, 1, blksz, write);
-
- mmc_wait_for_req(test->card->host, &mrq);
-
- if (cmd.error)
- return cmd.error;
- if (data.error)
- return data.error;
-
- ret = mmc_test_wait_busy(test);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static void mmc_test_free_mem(struct mmc_test_mem *mem)
-{
- if (!mem)
- return;
- while (mem->cnt--)
- __free_pages(mem->arr[mem->cnt].page,
- mem->arr[mem->cnt].order);
- kfree(mem->arr);
- kfree(mem);
-}
-
-/*
- * Allocate a lot of memory, preferably max_sz but at least min_sz. In case
- * 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 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 (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_segs,
- GFP_KERNEL);
- if (!mem->arr)
- goto out_free;
-
- while (max_page_cnt) {
- struct page *page;
- unsigned int order;
- gfp_t flags = GFP_KERNEL | GFP_DMA | __GFP_NOWARN |
- __GFP_NORETRY;
-
- order = get_order(max_seg_page_cnt << PAGE_SHIFT);
- while (1) {
- page = alloc_pages(flags, order);
- if (page || !order)
- break;
- order -= 1;
- }
- if (!page) {
- if (page_cnt < min_page_cnt)
- goto out_free;
- break;
- }
- mem->arr[mem->cnt].page = page;
- mem->arr[mem->cnt].order = order;
- mem->cnt += 1;
- if (max_page_cnt <= (1UL << order))
- 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;
-
-out_free:
- mmc_test_free_mem(mem);
- return NULL;
-}
-
-/*
- * Map memory into a scatterlist. Optionally allow the same memory to be
- * mapped more than once.
- */
-static int mmc_test_map_sg(struct mmc_test_mem *mem, unsigned long size,
- struct scatterlist *sglist, int repeat,
- unsigned int max_segs, unsigned int max_seg_sz,
- unsigned int *sg_len, int min_sg_len)
-{
- struct scatterlist *sg = NULL;
- unsigned int i;
- unsigned long sz = size;
-
- sg_init_table(sglist, max_segs);
- if (min_sg_len > max_segs)
- min_sg_len = max_segs;
-
- *sg_len = 0;
- do {
- for (i = 0; i < mem->cnt; i++) {
- unsigned long len = PAGE_SIZE << mem->arr[i].order;
-
- if (min_sg_len && (size / min_sg_len < len))
- len = ALIGN(size / min_sg_len, 512);
- if (len > sz)
- len = sz;
- if (len > max_seg_sz)
- len = max_seg_sz;
- if (sg)
- sg = sg_next(sg);
- else
- sg = sglist;
- if (!sg)
- return -EINVAL;
- sg_set_page(sg, mem->arr[i].page, len, 0);
- sz -= len;
- *sg_len += 1;
- if (!sz)
- break;
- }
- } while (sz && repeat);
-
- if (sz)
- return -EINVAL;
-
- if (sg)
- sg_mark_end(sg);
-
- return 0;
-}
-
-/*
- * Map memory into a scatterlist so that no pages are contiguous. Allow the
- * same memory to be mapped more than once.
- */
-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;
- unsigned int i = mem->cnt, cnt;
- unsigned long len;
- void *base, *addr, *last_addr = NULL;
-
- sg_init_table(sglist, max_segs);
-
- *sg_len = 0;
- while (sz) {
- base = page_address(mem->arr[--i].page);
- cnt = 1 << mem->arr[i].order;
- while (sz && cnt) {
- addr = base + PAGE_SIZE * --cnt;
- if (last_addr && last_addr + PAGE_SIZE == addr)
- continue;
- last_addr = addr;
- len = PAGE_SIZE;
- if (len > max_seg_sz)
- len = max_seg_sz;
- if (len > sz)
- len = sz;
- if (sg)
- sg = sg_next(sg);
- else
- sg = sglist;
- if (!sg)
- return -EINVAL;
- sg_set_page(sg, virt_to_page(addr), len, 0);
- sz -= len;
- *sg_len += 1;
- }
- if (i == 0)
- i = mem->cnt;
- }
-
- if (sg)
- sg_mark_end(sg);
-
- return 0;
-}
-
-/*
- * Calculate transfer rate in bytes per second.
- */
-static unsigned int mmc_test_rate(uint64_t bytes, struct timespec *ts)
-{
- uint64_t ns;
-
- ns = ts->tv_sec;
- ns *= 1000000000;
- ns += ts->tv_nsec;
-
- bytes *= 1000000000;
-
- while (ns > UINT_MAX) {
- bytes >>= 1;
- ns >>= 1;
- }
-
- if (!ns)
- return 0;
-
- do_div(bytes, (uint32_t)ns);
-
- 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, unsigned int iops)
-{
- 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;
- tr->iops = iops;
-
- list_add_tail(&tr->link, &test->gr->tr_lst);
-}
-
-/*
- * Print the transfer rate.
- */
-static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes,
- struct timespec *ts1, struct timespec *ts2)
-{
- unsigned int rate, iops, sectors = bytes >> 9;
- struct timespec ts;
-
- ts = timespec_sub(*ts2, *ts1);
-
- rate = mmc_test_rate(bytes, &ts);
- iops = mmc_test_rate(100, &ts); /* I/O ops per sec x 100 */
-
- pr_info("%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu "
- "seconds (%u kB/s, %u KiB/s, %u.%02u IOPS)\n",
- mmc_hostname(test->card->host), sectors, sectors >> 1,
- (sectors & 1 ? ".5" : ""), (unsigned long)ts.tv_sec,
- (unsigned long)ts.tv_nsec, rate / 1000, rate / 1024,
- iops / 100, iops % 100);
-
- mmc_test_save_transfer_result(test, 1, sectors, ts, rate, iops);
-}
-
-/*
- * Print the average transfer rate.
- */
-static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes,
- unsigned int count, struct timespec *ts1,
- struct timespec *ts2)
-{
- unsigned int rate, iops, sectors = bytes >> 9;
- uint64_t tot = bytes * count;
- struct timespec ts;
-
- ts = timespec_sub(*ts2, *ts1);
-
- rate = mmc_test_rate(tot, &ts);
- iops = mmc_test_rate(count * 100, &ts); /* I/O ops per sec x 100 */
-
- pr_info("%s: Transfer of %u x %u sectors (%u x %u%s KiB) took "
- "%lu.%09lu seconds (%u kB/s, %u KiB/s, "
- "%u.%02u IOPS, sg_len %d)\n",
- mmc_hostname(test->card->host), count, sectors, count,
- sectors >> 1, (sectors & 1 ? ".5" : ""),
- (unsigned long)ts.tv_sec, (unsigned long)ts.tv_nsec,
- rate / 1000, rate / 1024, iops / 100, iops % 100,
- test->area.sg_len);
-
- mmc_test_save_transfer_result(test, count, sectors, ts, rate, iops);
-}
-
-/*
- * Return the card size in sectors.
- */
-static unsigned int mmc_test_capacity(struct mmc_card *card)
-{
- if (!mmc_card_sd(card) && mmc_card_blockaddr(card))
- return card->ext_csd.sectors;
- else
- return card->csd.capacity << (card->csd.read_blkbits - 9);
-}
-
-/*******************************************************************/
-/* Test preparation and cleanup */
-/*******************************************************************/
-
-/*
- * Fill the first couple of sectors of the card with known data
- * so that bad reads/writes can be detected
- */
-static int __mmc_test_prepare(struct mmc_test_card *test, int write)
-{
- int ret, i;
-
- ret = mmc_test_set_blksize(test, 512);
- if (ret)
- return ret;
-
- if (write)
- memset(test->buffer, 0xDF, 512);
- else {
- for (i = 0;i < 512;i++)
- test->buffer[i] = i;
- }
-
- for (i = 0;i < BUFFER_SIZE / 512;i++) {
- ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int mmc_test_prepare_write(struct mmc_test_card *test)
-{
- return __mmc_test_prepare(test, 1);
-}
-
-static int mmc_test_prepare_read(struct mmc_test_card *test)
-{
- return __mmc_test_prepare(test, 0);
-}
-
-static int mmc_test_cleanup(struct mmc_test_card *test)
-{
- int ret, i;
-
- ret = mmc_test_set_blksize(test, 512);
- if (ret)
- return ret;
-
- memset(test->buffer, 0, 512);
-
- for (i = 0;i < BUFFER_SIZE / 512;i++) {
- ret = mmc_test_buffer_transfer(test, test->buffer, i, 512, 1);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-/*******************************************************************/
-/* Test execution helpers */
-/*******************************************************************/
-
-/*
- * Modifies the mmc_request to perform the "short transfer" tests
- */
-static void mmc_test_prepare_broken_mrq(struct mmc_test_card *test,
- struct mmc_request *mrq, int write)
-{
- BUG_ON(!mrq || !mrq->cmd || !mrq->data);
-
- if (mrq->data->blocks > 1) {
- mrq->cmd->opcode = write ?
- MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK;
- mrq->stop = NULL;
- } else {
- mrq->cmd->opcode = MMC_SEND_STATUS;
- mrq->cmd->arg = test->card->rca << 16;
- }
-}
-
-/*
- * Checks that a normal transfer didn't have any errors
- */
-static int mmc_test_check_result(struct mmc_test_card *test,
- struct mmc_request *mrq)
-{
- int ret;
-
- BUG_ON(!mrq || !mrq->cmd || !mrq->data);
-
- ret = 0;
-
- if (!ret && mrq->cmd->error)
- ret = mrq->cmd->error;
- if (!ret && mrq->data->error)
- ret = mrq->data->error;
- if (!ret && mrq->stop && mrq->stop->error)
- ret = mrq->stop->error;
- if (!ret && mrq->data->bytes_xfered !=
- mrq->data->blocks * mrq->data->blksz)
- ret = RESULT_FAIL;
-
- if (ret == -EINVAL)
- ret = RESULT_UNSUP_HOST;
-
- return ret;
-}
-
-static int mmc_test_check_result_async(struct mmc_card *card,
- struct mmc_async_req *areq)
-{
- struct mmc_test_async_req *test_async =
- container_of(areq, struct mmc_test_async_req, areq);
-
- mmc_test_wait_busy(test_async->test);
-
- return mmc_test_check_result(test_async->test, areq->mrq);
-}
-
-/*
- * Checks that a "short transfer" behaved as expected
- */
-static int mmc_test_check_broken_result(struct mmc_test_card *test,
- struct mmc_request *mrq)
-{
- int ret;
-
- BUG_ON(!mrq || !mrq->cmd || !mrq->data);
-
- ret = 0;
-
- if (!ret && mrq->cmd->error)
- ret = mrq->cmd->error;
- if (!ret && mrq->data->error == 0)
- ret = RESULT_FAIL;
- if (!ret && mrq->data->error != -ETIMEDOUT)
- ret = mrq->data->error;
- if (!ret && mrq->stop && mrq->stop->error)
- ret = mrq->stop->error;
- if (mrq->data->blocks > 1) {
- if (!ret && mrq->data->bytes_xfered > mrq->data->blksz)
- ret = RESULT_FAIL;
- } else {
- if (!ret && mrq->data->bytes_xfered > 0)
- ret = RESULT_FAIL;
- }
-
- if (ret == -EINVAL)
- ret = RESULT_UNSUP_HOST;
-
- return ret;
-}
-
-/*
- * Tests nonblock transfer with certain parameters
- */
-static void mmc_test_nonblock_reset(struct mmc_request *mrq,
- struct mmc_command *cmd,
- struct mmc_command *stop,
- struct mmc_data *data)
-{
- memset(mrq, 0, sizeof(struct mmc_request));
- memset(cmd, 0, sizeof(struct mmc_command));
- memset(data, 0, sizeof(struct mmc_data));
- memset(stop, 0, sizeof(struct mmc_command));
-
- mrq->cmd = cmd;
- mrq->data = data;
- mrq->stop = stop;
-}
-static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
- struct scatterlist *sg, unsigned sg_len,
- unsigned dev_addr, unsigned blocks,
- unsigned blksz, int write, int count)
-{
- struct mmc_request mrq1;
- struct mmc_command cmd1;
- struct mmc_command stop1;
- struct mmc_data data1;
-
- struct mmc_request mrq2;
- struct mmc_command cmd2;
- struct mmc_command stop2;
- struct mmc_data data2;
-
- struct mmc_test_async_req test_areq[2];
- struct mmc_async_req *done_areq;
- struct mmc_async_req *cur_areq = &test_areq[0].areq;
- struct mmc_async_req *other_areq = &test_areq[1].areq;
- int i;
- int ret;
-
- test_areq[0].test = test;
- test_areq[1].test = test;
-
- mmc_test_nonblock_reset(&mrq1, &cmd1, &stop1, &data1);
- mmc_test_nonblock_reset(&mrq2, &cmd2, &stop2, &data2);
-
- cur_areq->mrq = &mrq1;
- cur_areq->err_check = mmc_test_check_result_async;
- other_areq->mrq = &mrq2;
- other_areq->err_check = mmc_test_check_result_async;
-
- for (i = 0; i < count; i++) {
- mmc_test_prepare_mrq(test, cur_areq->mrq, sg, sg_len, dev_addr,
- blocks, blksz, write);
- done_areq = mmc_start_req(test->card->host, cur_areq, &ret);
-
- if (ret || (!done_areq && i > 0))
- goto err;
-
- if (done_areq) {
- if (done_areq->mrq == &mrq2)
- mmc_test_nonblock_reset(&mrq2, &cmd2,
- &stop2, &data2);
- else
- mmc_test_nonblock_reset(&mrq1, &cmd1,
- &stop1, &data1);
- }
- done_areq = cur_areq;
- cur_areq = other_areq;
- other_areq = done_areq;
- dev_addr += blocks;
- }
-
- done_areq = mmc_start_req(test->card->host, NULL, &ret);
-
- return ret;
-err:
- return ret;
-}
-
-/*
- * Tests a basic transfer with certain parameters
- */
-static int mmc_test_simple_transfer(struct mmc_test_card *test,
- struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
- unsigned blocks, unsigned blksz, int write)
-{
- struct mmc_request mrq = {0};
- struct mmc_command cmd = {0};
- struct mmc_command stop = {0};
- struct mmc_data data = {0};
-
- mrq.cmd = &cmd;
- mrq.data = &data;
- mrq.stop = &stop;
-
- mmc_test_prepare_mrq(test, &mrq, sg, sg_len, dev_addr,
- blocks, blksz, write);
-
- mmc_wait_for_req(test->card->host, &mrq);
-
- mmc_test_wait_busy(test);
-
- return mmc_test_check_result(test, &mrq);
-}
-
-/*
- * Tests a transfer where the card will fail completely or partly
- */
-static int mmc_test_broken_transfer(struct mmc_test_card *test,
- unsigned blocks, unsigned blksz, int write)
-{
- struct mmc_request mrq = {0};
- struct mmc_command cmd = {0};
- struct mmc_command stop = {0};
- struct mmc_data data = {0};
-
- struct scatterlist sg;
-
- mrq.cmd = &cmd;
- mrq.data = &data;
- mrq.stop = &stop;
-
- sg_init_one(&sg, test->buffer, blocks * blksz);
-
- mmc_test_prepare_mrq(test, &mrq, &sg, 1, 0, blocks, blksz, write);
- mmc_test_prepare_broken_mrq(test, &mrq, write);
-
- mmc_wait_for_req(test->card->host, &mrq);
-
- mmc_test_wait_busy(test);
-
- return mmc_test_check_broken_result(test, &mrq);
-}
-
-/*
- * Does a complete transfer test where data is also validated
- *
- * Note: mmc_test_prepare() must have been done before this call
- */
-static int mmc_test_transfer(struct mmc_test_card *test,
- struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
- unsigned blocks, unsigned blksz, int write)
-{
- int ret, i;
- unsigned long flags;
-
- if (write) {
- for (i = 0;i < blocks * blksz;i++)
- test->scratch[i] = i;
- } else {
- memset(test->scratch, 0, BUFFER_SIZE);
- }
- local_irq_save(flags);
- sg_copy_from_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
- local_irq_restore(flags);
-
- ret = mmc_test_set_blksize(test, blksz);
- if (ret)
- return ret;
-
- ret = mmc_test_simple_transfer(test, sg, sg_len, dev_addr,
- blocks, blksz, write);
- if (ret)
- return ret;
-
- if (write) {
- int sectors;
-
- ret = mmc_test_set_blksize(test, 512);
- if (ret)
- return ret;
-
- sectors = (blocks * blksz + 511) / 512;
- if ((sectors * 512) == (blocks * blksz))
- sectors++;
-
- if ((sectors * 512) > BUFFER_SIZE)
- return -EINVAL;
-
- memset(test->buffer, 0, sectors * 512);
-
- for (i = 0;i < sectors;i++) {
- ret = mmc_test_buffer_transfer(test,
- test->buffer + i * 512,
- dev_addr + i, 512, 0);
- if (ret)
- return ret;
- }
-
- for (i = 0;i < blocks * blksz;i++) {
- if (test->buffer[i] != (u8)i)
- return RESULT_FAIL;
- }
-
- for (;i < sectors * 512;i++) {
- if (test->buffer[i] != 0xDF)
- return RESULT_FAIL;
- }
- } else {
- local_irq_save(flags);
- sg_copy_to_buffer(sg, sg_len, test->scratch, BUFFER_SIZE);
- local_irq_restore(flags);
- for (i = 0;i < blocks * blksz;i++) {
- if (test->scratch[i] != (u8)i)
- return RESULT_FAIL;
- }
- }
-
- return 0;
-}
-
-/*******************************************************************/
-/* Tests */
-/*******************************************************************/
-
-struct mmc_test_case {
- const char *name;
-
- int (*prepare)(struct mmc_test_card *);
- int (*run)(struct mmc_test_card *);
- int (*cleanup)(struct mmc_test_card *);
-};
-
-static int mmc_test_basic_write(struct mmc_test_card *test)
-{
- int ret;
- struct scatterlist sg;
-
- ret = mmc_test_set_blksize(test, 512);
- if (ret)
- return ret;
-
- sg_init_one(&sg, test->buffer, 512);
-
- ret = mmc_test_simple_transfer(test, &sg, 1, 0, 1, 512, 1);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int mmc_test_basic_read(struct mmc_test_card *test)
-{
- int ret;
- struct scatterlist sg;
-
- ret = mmc_test_set_blksize(test, 512);
- if (ret)
- return ret;
-
- sg_init_one(&sg, test->buffer, 512);
-
- ret = mmc_test_simple_transfer(test, &sg, 1, 0, 1, 512, 0);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int mmc_test_verify_write(struct mmc_test_card *test)
-{
- int ret;
- struct scatterlist sg;
-
- sg_init_one(&sg, test->buffer, 512);
-
- ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int mmc_test_verify_read(struct mmc_test_card *test)
-{
- int ret;
- struct scatterlist sg;
-
- sg_init_one(&sg, test->buffer, 512);
-
- ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int mmc_test_multi_write(struct mmc_test_card *test)
-{
- int ret;
- unsigned int size;
- struct scatterlist sg;
-
- if (test->card->host->max_blk_count == 1)
- return RESULT_UNSUP_HOST;
-
- size = PAGE_SIZE * 2;
- size = min(size, test->card->host->max_req_size);
- size = min(size, test->card->host->max_seg_size);
- size = min(size, test->card->host->max_blk_count * 512);
-
- if (size < 1024)
- return RESULT_UNSUP_HOST;
-
- sg_init_one(&sg, test->buffer, size);
-
- ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int mmc_test_multi_read(struct mmc_test_card *test)
-{
- int ret;
- unsigned int size;
- struct scatterlist sg;
-
- if (test->card->host->max_blk_count == 1)
- return RESULT_UNSUP_HOST;
-
- size = PAGE_SIZE * 2;
- size = min(size, test->card->host->max_req_size);
- size = min(size, test->card->host->max_seg_size);
- size = min(size, test->card->host->max_blk_count * 512);
-
- if (size < 1024)
- return RESULT_UNSUP_HOST;
-
- sg_init_one(&sg, test->buffer, size);
-
- ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int mmc_test_pow2_write(struct mmc_test_card *test)
-{
- int ret, i;
- struct scatterlist sg;
-
- if (!test->card->csd.write_partial)
- return RESULT_UNSUP_CARD;
-
- for (i = 1; i < 512;i <<= 1) {
- sg_init_one(&sg, test->buffer, i);
- ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int mmc_test_pow2_read(struct mmc_test_card *test)
-{
- int ret, i;
- struct scatterlist sg;
-
- if (!test->card->csd.read_partial)
- return RESULT_UNSUP_CARD;
-
- for (i = 1; i < 512;i <<= 1) {
- sg_init_one(&sg, test->buffer, i);
- ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int mmc_test_weird_write(struct mmc_test_card *test)
-{
- int ret, i;
- struct scatterlist sg;
-
- if (!test->card->csd.write_partial)
- return RESULT_UNSUP_CARD;
-
- for (i = 3; i < 512;i += 7) {
- sg_init_one(&sg, test->buffer, i);
- ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 1);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int mmc_test_weird_read(struct mmc_test_card *test)
-{
- int ret, i;
- struct scatterlist sg;
-
- if (!test->card->csd.read_partial)
- return RESULT_UNSUP_CARD;
-
- for (i = 3; i < 512;i += 7) {
- sg_init_one(&sg, test->buffer, i);
- ret = mmc_test_transfer(test, &sg, 1, 0, 1, i, 0);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int mmc_test_align_write(struct mmc_test_card *test)
-{
- int ret, i;
- struct scatterlist sg;
-
- for (i = 1;i < 4;i++) {
- sg_init_one(&sg, test->buffer + i, 512);
- ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int mmc_test_align_read(struct mmc_test_card *test)
-{
- int ret, i;
- struct scatterlist sg;
-
- for (i = 1;i < 4;i++) {
- sg_init_one(&sg, test->buffer + i, 512);
- ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int mmc_test_align_multi_write(struct mmc_test_card *test)
-{
- int ret, i;
- unsigned int size;
- struct scatterlist sg;
-
- if (test->card->host->max_blk_count == 1)
- return RESULT_UNSUP_HOST;
-
- size = PAGE_SIZE * 2;
- size = min(size, test->card->host->max_req_size);
- size = min(size, test->card->host->max_seg_size);
- size = min(size, test->card->host->max_blk_count * 512);
-
- if (size < 1024)
- return RESULT_UNSUP_HOST;
-
- for (i = 1;i < 4;i++) {
- sg_init_one(&sg, test->buffer + i, size);
- ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int mmc_test_align_multi_read(struct mmc_test_card *test)
-{
- int ret, i;
- unsigned int size;
- struct scatterlist sg;
-
- if (test->card->host->max_blk_count == 1)
- return RESULT_UNSUP_HOST;
-
- size = PAGE_SIZE * 2;
- size = min(size, test->card->host->max_req_size);
- size = min(size, test->card->host->max_seg_size);
- size = min(size, test->card->host->max_blk_count * 512);
-
- if (size < 1024)
- return RESULT_UNSUP_HOST;
-
- for (i = 1;i < 4;i++) {
- sg_init_one(&sg, test->buffer + i, size);
- ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int mmc_test_xfersize_write(struct mmc_test_card *test)
-{
- int ret;
-
- ret = mmc_test_set_blksize(test, 512);
- if (ret)
- return ret;
-
- ret = mmc_test_broken_transfer(test, 1, 512, 1);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int mmc_test_xfersize_read(struct mmc_test_card *test)
-{
- int ret;
-
- ret = mmc_test_set_blksize(test, 512);
- if (ret)
- return ret;
-
- ret = mmc_test_broken_transfer(test, 1, 512, 0);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int mmc_test_multi_xfersize_write(struct mmc_test_card *test)
-{
- int ret;
-
- if (test->card->host->max_blk_count == 1)
- return RESULT_UNSUP_HOST;
-
- ret = mmc_test_set_blksize(test, 512);
- if (ret)
- return ret;
-
- ret = mmc_test_broken_transfer(test, 2, 512, 1);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int mmc_test_multi_xfersize_read(struct mmc_test_card *test)
-{
- int ret;
-
- if (test->card->host->max_blk_count == 1)
- return RESULT_UNSUP_HOST;
-
- ret = mmc_test_set_blksize(test, 512);
- if (ret)
- return ret;
-
- ret = mmc_test_broken_transfer(test, 2, 512, 0);
- if (ret)
- return ret;
-
- return 0;
-}
-
-#ifdef CONFIG_HIGHMEM
-
-static int mmc_test_write_high(struct mmc_test_card *test)
-{
- int ret;
- struct scatterlist sg;
-
- sg_init_table(&sg, 1);
- sg_set_page(&sg, test->highmem, 512, 0);
-
- ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int mmc_test_read_high(struct mmc_test_card *test)
-{
- int ret;
- struct scatterlist sg;
-
- sg_init_table(&sg, 1);
- sg_set_page(&sg, test->highmem, 512, 0);
-
- ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int mmc_test_multi_write_high(struct mmc_test_card *test)
-{
- int ret;
- unsigned int size;
- struct scatterlist sg;
-
- if (test->card->host->max_blk_count == 1)
- return RESULT_UNSUP_HOST;
-
- size = PAGE_SIZE * 2;
- size = min(size, test->card->host->max_req_size);
- size = min(size, test->card->host->max_seg_size);
- size = min(size, test->card->host->max_blk_count * 512);
-
- if (size < 1024)
- return RESULT_UNSUP_HOST;
-
- sg_init_table(&sg, 1);
- sg_set_page(&sg, test->highmem, size, 0);
-
- ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int mmc_test_multi_read_high(struct mmc_test_card *test)
-{
- int ret;
- unsigned int size;
- struct scatterlist sg;
-
- if (test->card->host->max_blk_count == 1)
- return RESULT_UNSUP_HOST;
-
- size = PAGE_SIZE * 2;
- size = min(size, test->card->host->max_req_size);
- size = min(size, test->card->host->max_seg_size);
- size = min(size, test->card->host->max_blk_count * 512);
-
- if (size < 1024)
- return RESULT_UNSUP_HOST;
-
- sg_init_table(&sg, 1);
- sg_set_page(&sg, test->highmem, size, 0);
-
- ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
- if (ret)
- return ret;
-
- return 0;
-}
-
-#else
-
-static int mmc_test_no_highmem(struct mmc_test_card *test)
-{
- pr_info("%s: Highmem not configured - test skipped\n",
- mmc_hostname(test->card->host));
- return 0;
-}
-
-#endif /* CONFIG_HIGHMEM */
-
-/*
- * Map sz bytes so that it can be transferred.
- */
-static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz,
- int max_scatter, int min_sg_len)
-{
- struct mmc_test_area *t = &test->area;
- int err;
-
- t->blocks = sz >> 9;
-
- if (max_scatter) {
- 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, min_sg_len);
- }
- if (err)
- pr_info("%s: Failed to map sg list\n",
- mmc_hostname(test->card->host));
- return err;
-}
-
-/*
- * Transfer bytes mapped by mmc_test_area_map().
- */
-static int mmc_test_area_transfer(struct mmc_test_card *test,
- unsigned int dev_addr, int write)
-{
- struct mmc_test_area *t = &test->area;
-
- return mmc_test_simple_transfer(test, t->sg, t->sg_len, dev_addr,
- t->blocks, 512, write);
-}
-
-/*
- * Map and transfer bytes for multiple transfers.
- */
-static int mmc_test_area_io_seq(struct mmc_test_card *test, unsigned long sz,
- unsigned int dev_addr, int write,
- int max_scatter, int timed, int count,
- bool nonblock, int min_sg_len)
-{
- struct timespec ts1, ts2;
- int ret = 0;
- int i;
- struct mmc_test_area *t = &test->area;
-
- /*
- * 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, min_sg_len);
- if (ret)
- return ret;
-
- if (timed)
- getnstimeofday(&ts1);
- if (nonblock)
- ret = mmc_test_nonblock_transfer(test, t->sg, t->sg_len,
- dev_addr, t->blocks, 512, write, count);
- else
- for (i = 0; i < count && ret == 0; i++) {
- ret = mmc_test_area_transfer(test, dev_addr, write);
- dev_addr += sz >> 9;
- }
-
- if (ret)
- return ret;
-
- if (timed)
- getnstimeofday(&ts2);
-
- if (timed)
- mmc_test_print_avg_rate(test, sz, count, &ts1, &ts2);
-
- return 0;
-}
-
-static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
- unsigned int dev_addr, int write, int max_scatter,
- int timed)
-{
- return mmc_test_area_io_seq(test, sz, dev_addr, write, max_scatter,
- timed, 1, false, 0);
-}
-
-/*
- * Write the test area entirely.
- */
-static int mmc_test_area_fill(struct mmc_test_card *test)
-{
- struct mmc_test_area *t = &test->area;
-
- return mmc_test_area_io(test, t->max_tfr, t->dev_addr, 1, 0, 0);
-}
-
-/*
- * Erase the test area entirely.
- */
-static int mmc_test_area_erase(struct mmc_test_card *test)
-{
- struct mmc_test_area *t = &test->area;
-
- if (!mmc_can_erase(test->card))
- return 0;
-
- return mmc_erase(test->card, t->dev_addr, t->max_sz >> 9,
- MMC_ERASE_ARG);
-}
-
-/*
- * Cleanup struct mmc_test_area.
- */
-static int mmc_test_area_cleanup(struct mmc_test_card *test)
-{
- struct mmc_test_area *t = &test->area;
-
- kfree(t->sg);
- mmc_test_free_mem(t->mem);
-
- return 0;
-}
-
-/*
- * Initialize an area for testing large transfers. The test area is set to the
- * middle of the card because cards may have different charateristics at the
- * front (for FAT file system optimization). Optionally, the area is erased
- * (if the card supports it) which may improve write performance. Optionally,
- * the area is filled with data for subsequent read tests.
- */
-static int mmc_test_area_init(struct mmc_test_card *test, int erase, int fill)
-{
- struct mmc_test_area *t = &test->area;
- unsigned long min_sz = 64 * 1024, sz;
- int ret;
-
- ret = mmc_test_set_blksize(test, 512);
- if (ret)
- return ret;
-
- /* Make the test area size about 4MiB */
- sz = (unsigned long)test->card->pref_erase << 9;
- t->max_sz = sz;
- while (t->max_sz < 4 * 1024 * 1024)
- t->max_sz += sz;
- while (t->max_sz > TEST_AREA_MAX_SIZE && t->max_sz > sz)
- t->max_sz -= sz;
-
- t->max_segs = test->card->host->max_segs;
- t->max_seg_sz = test->card->host->max_seg_size;
- t->max_seg_sz -= t->max_seg_sz % 512;
-
- 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 a max. sized transfer. Less is OK
- * because the same memory can be mapped into the scatterlist more than
- * 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_tfr, t->max_segs,
- t->max_seg_sz);
- if (!t->mem)
- return -ENOMEM;
-
- t->sg = kmalloc(sizeof(struct scatterlist) * t->max_segs, GFP_KERNEL);
- if (!t->sg) {
- ret = -ENOMEM;
- goto out_free;
- }
-
- t->dev_addr = mmc_test_capacity(test->card) / 2;
- t->dev_addr -= t->dev_addr % (t->max_sz >> 9);
-
- if (erase) {
- ret = mmc_test_area_erase(test);
- if (ret)
- goto out_free;
- }
-
- if (fill) {
- ret = mmc_test_area_fill(test);
- if (ret)
- goto out_free;
- }
-
- return 0;
-
-out_free:
- mmc_test_area_cleanup(test);
- return ret;
-}
-
-/*
- * Prepare for large transfers. Do not erase the test area.
- */
-static int mmc_test_area_prepare(struct mmc_test_card *test)
-{
- return mmc_test_area_init(test, 0, 0);
-}
-
-/*
- * Prepare for large transfers. Do erase the test area.
- */
-static int mmc_test_area_prepare_erase(struct mmc_test_card *test)
-{
- return mmc_test_area_init(test, 1, 0);
-}
-
-/*
- * Prepare for large transfers. Erase and fill the test area.
- */
-static int mmc_test_area_prepare_fill(struct mmc_test_card *test)
-{
- return mmc_test_area_init(test, 1, 1);
-}
-
-/*
- * Test best-case performance. Best-case performance is expected from
- * a single large transfer.
- *
- * An additional option (max_scatter) allows the measurement of the same
- * transfer but with no contiguous pages in the scatter list. This tests
- * the efficiency of DMA to handle scattered pages.
- */
-static int mmc_test_best_performance(struct mmc_test_card *test, int write,
- int max_scatter)
-{
- struct mmc_test_area *t = &test->area;
-
- return mmc_test_area_io(test, t->max_tfr, t->dev_addr, write,
- max_scatter, 1);
-}
-
-/*
- * Best-case read performance.
- */
-static int mmc_test_best_read_performance(struct mmc_test_card *test)
-{
- return mmc_test_best_performance(test, 0, 0);
-}
-
-/*
- * Best-case write performance.
- */
-static int mmc_test_best_write_performance(struct mmc_test_card *test)
-{
- return mmc_test_best_performance(test, 1, 0);
-}
-
-/*
- * Best-case read performance into scattered pages.
- */
-static int mmc_test_best_read_perf_max_scatter(struct mmc_test_card *test)
-{
- return mmc_test_best_performance(test, 0, 1);
-}
-
-/*
- * Best-case write performance from scattered pages.
- */
-static int mmc_test_best_write_perf_max_scatter(struct mmc_test_card *test)
-{
- return mmc_test_best_performance(test, 1, 1);
-}
-
-/*
- * Single read performance by transfer size.
- */
-static int mmc_test_profile_read_perf(struct mmc_test_card *test)
-{
- struct mmc_test_area *t = &test->area;
- unsigned long sz;
- unsigned int dev_addr;
- int ret;
-
- for (sz = 512; sz < t->max_tfr; sz <<= 1) {
- dev_addr = t->dev_addr + (sz >> 9);
- ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
- if (ret)
- return ret;
- }
- sz = t->max_tfr;
- dev_addr = t->dev_addr;
- return mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
-}
-
-/*
- * Single write performance by transfer size.
- */
-static int mmc_test_profile_write_perf(struct mmc_test_card *test)
-{
- struct mmc_test_area *t = &test->area;
- unsigned long sz;
- unsigned int dev_addr;
- int ret;
-
- ret = mmc_test_area_erase(test);
- if (ret)
- return ret;
- for (sz = 512; sz < t->max_tfr; sz <<= 1) {
- dev_addr = t->dev_addr + (sz >> 9);
- ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
- if (ret)
- return ret;
- }
- ret = mmc_test_area_erase(test);
- if (ret)
- return ret;
- sz = t->max_tfr;
- dev_addr = t->dev_addr;
- return mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
-}
-
-/*
- * Single trim performance by transfer size.
- */
-static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
-{
- struct mmc_test_area *t = &test->area;
- unsigned long sz;
- unsigned int dev_addr;
- struct timespec ts1, ts2;
- int ret;
-
- if (!mmc_can_trim(test->card))
- return RESULT_UNSUP_CARD;
-
- if (!mmc_can_erase(test->card))
- return RESULT_UNSUP_HOST;
-
- for (sz = 512; sz < t->max_sz; sz <<= 1) {
- dev_addr = t->dev_addr + (sz >> 9);
- getnstimeofday(&ts1);
- ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG);
- if (ret)
- return ret;
- getnstimeofday(&ts2);
- mmc_test_print_rate(test, sz, &ts1, &ts2);
- }
- dev_addr = t->dev_addr;
- getnstimeofday(&ts1);
- ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG);
- if (ret)
- return ret;
- getnstimeofday(&ts2);
- mmc_test_print_rate(test, sz, &ts1, &ts2);
- return 0;
-}
-
-static int mmc_test_seq_read_perf(struct mmc_test_card *test, unsigned long sz)
-{
- struct mmc_test_area *t = &test->area;
- unsigned int dev_addr, i, cnt;
- struct timespec ts1, ts2;
- int ret;
-
- cnt = t->max_sz / sz;
- dev_addr = t->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)
-{
- struct mmc_test_area *t = &test->area;
- unsigned long sz;
- int ret;
-
- for (sz = 512; sz < t->max_tfr; sz <<= 1) {
- ret = mmc_test_seq_read_perf(test, sz);
- if (ret)
- return ret;
- }
- sz = t->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)
-{
- struct mmc_test_area *t = &test->area;
- unsigned int dev_addr, i, cnt;
- struct timespec ts1, ts2;
- int ret;
-
- ret = mmc_test_area_erase(test);
- if (ret)
- return ret;
- cnt = t->max_sz / sz;
- dev_addr = t->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;
-}
-
-/*
- * Consecutive write performance by transfer size.
- */
-static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test)
-{
- struct mmc_test_area *t = &test->area;
- unsigned long sz;
- int ret;
-
- for (sz = 512; sz < t->max_tfr; sz <<= 1) {
- ret = mmc_test_seq_write_perf(test, sz);
- if (ret)
- return ret;
- }
- sz = t->max_tfr;
- return mmc_test_seq_write_perf(test, sz);
-}
-
-/*
- * Consecutive trim performance by transfer size.
- */
-static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test)
-{
- struct mmc_test_area *t = &test->area;
- unsigned long sz;
- unsigned int dev_addr, i, cnt;
- struct timespec ts1, ts2;
- int ret;
-
- if (!mmc_can_trim(test->card))
- return RESULT_UNSUP_CARD;
-
- if (!mmc_can_erase(test->card))
- return RESULT_UNSUP_HOST;
-
- for (sz = 512; sz <= t->max_sz; sz <<= 1) {
- ret = mmc_test_area_erase(test);
- if (ret)
- return ret;
- ret = mmc_test_area_fill(test);
- if (ret)
- return ret;
- cnt = t->max_sz / sz;
- dev_addr = t->dev_addr;
- getnstimeofday(&ts1);
- for (i = 0; i < cnt; i++) {
- ret = mmc_erase(test->card, dev_addr, sz >> 9,
- MMC_TRIM_ARG);
- if (ret)
- return ret;
- dev_addr += (sz >> 9);
- }
- getnstimeofday(&ts2);
- mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
- }
- return 0;
-}
-
-static unsigned int rnd_next = 1;
-
-static unsigned int mmc_test_rnd_num(unsigned int rnd_cnt)
-{
- uint64_t r;
-
- rnd_next = rnd_next * 1103515245 + 12345;
- r = (rnd_next >> 16) & 0x7fff;
- return (r * rnd_cnt) >> 15;
-}
-
-static int mmc_test_rnd_perf(struct mmc_test_card *test, int write, int print,
- unsigned long sz)
-{
- unsigned int dev_addr, cnt, rnd_addr, range1, range2, last_ea = 0, ea;
- unsigned int ssz;
- struct timespec ts1, ts2, ts;
- int ret;
-
- ssz = sz >> 9;
-
- rnd_addr = mmc_test_capacity(test->card) / 4;
- range1 = rnd_addr / test->card->pref_erase;
- range2 = range1 / ssz;
-
- getnstimeofday(&ts1);
- for (cnt = 0; cnt < UINT_MAX; cnt++) {
- getnstimeofday(&ts2);
- ts = timespec_sub(ts2, ts1);
- if (ts.tv_sec >= 10)
- break;
- ea = mmc_test_rnd_num(range1);
- if (ea == last_ea)
- ea -= 1;
- last_ea = ea;
- dev_addr = rnd_addr + test->card->pref_erase * ea +
- ssz * mmc_test_rnd_num(range2);
- ret = mmc_test_area_io(test, sz, dev_addr, write, 0, 0);
- if (ret)
- return ret;
- }
- if (print)
- mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
- return 0;
-}
-
-static int mmc_test_random_perf(struct mmc_test_card *test, int write)
-{
- struct mmc_test_area *t = &test->area;
- unsigned int next;
- unsigned long sz;
- int ret;
-
- for (sz = 512; sz < t->max_tfr; sz <<= 1) {
- /*
- * When writing, try to get more consistent results by running
- * the test twice with exactly the same I/O but outputting the
- * results only for the 2nd run.
- */
- if (write) {
- next = rnd_next;
- ret = mmc_test_rnd_perf(test, write, 0, sz);
- if (ret)
- return ret;
- rnd_next = next;
- }
- ret = mmc_test_rnd_perf(test, write, 1, sz);
- if (ret)
- return ret;
- }
- sz = t->max_tfr;
- if (write) {
- next = rnd_next;
- ret = mmc_test_rnd_perf(test, write, 0, sz);
- if (ret)
- return ret;
- rnd_next = next;
- }
- return mmc_test_rnd_perf(test, write, 1, sz);
-}
-
-/*
- * Random read performance by transfer size.
- */
-static int mmc_test_random_read_perf(struct mmc_test_card *test)
-{
- return mmc_test_random_perf(test, 0);
-}
-
-/*
- * Random write performance by transfer size.
- */
-static int mmc_test_random_write_perf(struct mmc_test_card *test)
-{
- return mmc_test_random_perf(test, 1);
-}
-
-static int mmc_test_seq_perf(struct mmc_test_card *test, int write,
- unsigned int tot_sz, int max_scatter)
-{
- struct mmc_test_area *t = &test->area;
- unsigned int dev_addr, i, cnt, sz, ssz;
- struct timespec ts1, ts2;
- int ret;
-
- sz = t->max_tfr;
-
- /*
- * In the case of a maximally scattered transfer, the maximum transfer
- * size is further limited by using PAGE_SIZE segments.
- */
- if (max_scatter) {
- 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;
- }
-
- ssz = sz >> 9;
- dev_addr = mmc_test_capacity(test->card) / 4;
- if (tot_sz > dev_addr << 9)
- tot_sz = dev_addr << 9;
- cnt = tot_sz / sz;
- dev_addr &= 0xffff0000; /* Round to 64MiB boundary */
-
- getnstimeofday(&ts1);
- for (i = 0; i < cnt; i++) {
- ret = mmc_test_area_io(test, sz, dev_addr, write,
- max_scatter, 0);
- if (ret)
- return ret;
- dev_addr += ssz;
- }
- getnstimeofday(&ts2);
-
- mmc_test_print_avg_rate(test, sz, cnt, &ts1, &ts2);
-
- return 0;
-}
-
-static int mmc_test_large_seq_perf(struct mmc_test_card *test, int write)
-{
- int ret, i;
-
- for (i = 0; i < 10; i++) {
- ret = mmc_test_seq_perf(test, write, 10 * 1024 * 1024, 1);
- if (ret)
- return ret;
- }
- for (i = 0; i < 5; i++) {
- ret = mmc_test_seq_perf(test, write, 100 * 1024 * 1024, 1);
- if (ret)
- return ret;
- }
- for (i = 0; i < 3; i++) {
- ret = mmc_test_seq_perf(test, write, 1000 * 1024 * 1024, 1);
- if (ret)
- return ret;
- }
-
- return ret;
-}
-
-/*
- * Large sequential read performance.
- */
-static int mmc_test_large_seq_read_perf(struct mmc_test_card *test)
-{
- return mmc_test_large_seq_perf(test, 0);
-}
-
-/*
- * Large sequential write performance.
- */
-static int mmc_test_large_seq_write_perf(struct mmc_test_card *test)
-{
- return mmc_test_large_seq_perf(test, 1);
-}
-
-static int mmc_test_rw_multiple(struct mmc_test_card *test,
- struct mmc_test_multiple_rw *tdata,
- unsigned int reqsize, unsigned int size,
- int min_sg_len)
-{
- unsigned int dev_addr;
- struct mmc_test_area *t = &test->area;
- int ret = 0;
-
- /* Set up test area */
- if (size > mmc_test_capacity(test->card) / 2 * 512)
- size = mmc_test_capacity(test->card) / 2 * 512;
- if (reqsize > t->max_tfr)
- reqsize = t->max_tfr;
- dev_addr = mmc_test_capacity(test->card) / 4;
- if ((dev_addr & 0xffff0000))
- dev_addr &= 0xffff0000; /* Round to 64MiB boundary */
- else
- dev_addr &= 0xfffff800; /* Round to 1MiB boundary */
- if (!dev_addr)
- goto err;
-
- if (reqsize > size)
- return 0;
-
- /* prepare test area */
- if (mmc_can_erase(test->card) &&
- tdata->prepare & MMC_TEST_PREP_ERASE) {
- ret = mmc_erase(test->card, dev_addr,
- size / 512, MMC_SECURE_ERASE_ARG);
- if (ret)
- ret = mmc_erase(test->card, dev_addr,
- size / 512, MMC_ERASE_ARG);
- if (ret)
- goto err;
- }
-
- /* Run test */
- ret = mmc_test_area_io_seq(test, reqsize, dev_addr,
- tdata->do_write, 0, 1, size / reqsize,
- tdata->do_nonblock_req, min_sg_len);
- if (ret)
- goto err;
-
- return ret;
- err:
- pr_info("[%s] error\n", __func__);
- return ret;
-}
-
-static int mmc_test_rw_multiple_size(struct mmc_test_card *test,
- struct mmc_test_multiple_rw *rw)
-{
- int ret = 0;
- int i;
- void *pre_req = test->card->host->ops->pre_req;
- void *post_req = test->card->host->ops->post_req;
-
- if (rw->do_nonblock_req &&
- ((!pre_req && post_req) || (pre_req && !post_req))) {
- pr_info("error: only one of pre/post is defined\n");
- return -EINVAL;
- }
-
- for (i = 0 ; i < rw->len && ret == 0; i++) {
- ret = mmc_test_rw_multiple(test, rw, rw->bs[i], rw->size, 0);
- if (ret)
- break;
- }
- return ret;
-}
-
-static int mmc_test_rw_multiple_sg_len(struct mmc_test_card *test,
- struct mmc_test_multiple_rw *rw)
-{
- int ret = 0;
- int i;
-
- for (i = 0 ; i < rw->len && ret == 0; i++) {
- ret = mmc_test_rw_multiple(test, rw, 512*1024, rw->size,
- rw->sg_len[i]);
- if (ret)
- break;
- }
- return ret;
-}
-
-/*
- * Multiple blocking write 4k to 4 MB chunks
- */
-static int mmc_test_profile_mult_write_blocking_perf(struct mmc_test_card *test)
-{
- unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
- 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
- struct mmc_test_multiple_rw test_data = {
- .bs = bs,
- .size = TEST_AREA_MAX_SIZE,
- .len = ARRAY_SIZE(bs),
- .do_write = true,
- .do_nonblock_req = false,
- .prepare = MMC_TEST_PREP_ERASE,
- };
-
- return mmc_test_rw_multiple_size(test, &test_data);
-};
-
-/*
- * Multiple non-blocking write 4k to 4 MB chunks
- */
-static int mmc_test_profile_mult_write_nonblock_perf(struct mmc_test_card *test)
-{
- unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
- 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
- struct mmc_test_multiple_rw test_data = {
- .bs = bs,
- .size = TEST_AREA_MAX_SIZE,
- .len = ARRAY_SIZE(bs),
- .do_write = true,
- .do_nonblock_req = true,
- .prepare = MMC_TEST_PREP_ERASE,
- };
-
- return mmc_test_rw_multiple_size(test, &test_data);
-}
-
-/*
- * Multiple blocking read 4k to 4 MB chunks
- */
-static int mmc_test_profile_mult_read_blocking_perf(struct mmc_test_card *test)
-{
- unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
- 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
- struct mmc_test_multiple_rw test_data = {
- .bs = bs,
- .size = TEST_AREA_MAX_SIZE,
- .len = ARRAY_SIZE(bs),
- .do_write = false,
- .do_nonblock_req = false,
- .prepare = MMC_TEST_PREP_NONE,
- };
-
- return mmc_test_rw_multiple_size(test, &test_data);
-}
-
-/*
- * Multiple non-blocking read 4k to 4 MB chunks
- */
-static int mmc_test_profile_mult_read_nonblock_perf(struct mmc_test_card *test)
-{
- unsigned int bs[] = {1 << 12, 1 << 13, 1 << 14, 1 << 15, 1 << 16,
- 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 22};
- struct mmc_test_multiple_rw test_data = {
- .bs = bs,
- .size = TEST_AREA_MAX_SIZE,
- .len = ARRAY_SIZE(bs),
- .do_write = false,
- .do_nonblock_req = true,
- .prepare = MMC_TEST_PREP_NONE,
- };
-
- return mmc_test_rw_multiple_size(test, &test_data);
-}
-
-/*
- * Multiple blocking write 1 to 512 sg elements
- */
-static int mmc_test_profile_sglen_wr_blocking_perf(struct mmc_test_card *test)
-{
- unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
- 1 << 7, 1 << 8, 1 << 9};
- struct mmc_test_multiple_rw test_data = {
- .sg_len = sg_len,
- .size = TEST_AREA_MAX_SIZE,
- .len = ARRAY_SIZE(sg_len),
- .do_write = true,
- .do_nonblock_req = false,
- .prepare = MMC_TEST_PREP_ERASE,
- };
-
- return mmc_test_rw_multiple_sg_len(test, &test_data);
-};
-
-/*
- * Multiple non-blocking write 1 to 512 sg elements
- */
-static int mmc_test_profile_sglen_wr_nonblock_perf(struct mmc_test_card *test)
-{
- unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
- 1 << 7, 1 << 8, 1 << 9};
- struct mmc_test_multiple_rw test_data = {
- .sg_len = sg_len,
- .size = TEST_AREA_MAX_SIZE,
- .len = ARRAY_SIZE(sg_len),
- .do_write = true,
- .do_nonblock_req = true,
- .prepare = MMC_TEST_PREP_ERASE,
- };
-
- return mmc_test_rw_multiple_sg_len(test, &test_data);
-}
-
-/*
- * Multiple blocking read 1 to 512 sg elements
- */
-static int mmc_test_profile_sglen_r_blocking_perf(struct mmc_test_card *test)
-{
- unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
- 1 << 7, 1 << 8, 1 << 9};
- struct mmc_test_multiple_rw test_data = {
- .sg_len = sg_len,
- .size = TEST_AREA_MAX_SIZE,
- .len = ARRAY_SIZE(sg_len),
- .do_write = false,
- .do_nonblock_req = false,
- .prepare = MMC_TEST_PREP_NONE,
- };
-
- return mmc_test_rw_multiple_sg_len(test, &test_data);
-}
-
-/*
- * Multiple non-blocking read 1 to 512 sg elements
- */
-static int mmc_test_profile_sglen_r_nonblock_perf(struct mmc_test_card *test)
-{
- unsigned int sg_len[] = {1, 1 << 3, 1 << 4, 1 << 5, 1 << 6,
- 1 << 7, 1 << 8, 1 << 9};
- struct mmc_test_multiple_rw test_data = {
- .sg_len = sg_len,
- .size = TEST_AREA_MAX_SIZE,
- .len = ARRAY_SIZE(sg_len),
- .do_write = false,
- .do_nonblock_req = true,
- .prepare = MMC_TEST_PREP_NONE,
- };
-
- return mmc_test_rw_multiple_sg_len(test, &test_data);
-}
-
-/*
- * eMMC hardware reset.
- */
-static int mmc_test_hw_reset(struct mmc_test_card *test)
-{
- struct mmc_card *card = test->card;
- struct mmc_host *host = card->host;
- int err;
-
- err = mmc_hw_reset_check(host);
- if (!err)
- return RESULT_OK;
-
- if (err == -ENOSYS)
- return RESULT_FAIL;
-
- if (err != -EOPNOTSUPP)
- return err;
-
- if (!mmc_can_reset(card))
- return RESULT_UNSUP_CARD;
-
- return RESULT_UNSUP_HOST;
-}
-
-static const struct mmc_test_case mmc_test_cases[] = {
- {
- .name = "Basic write (no data verification)",
- .run = mmc_test_basic_write,
- },
-
- {
- .name = "Basic read (no data verification)",
- .run = mmc_test_basic_read,
- },
-
- {
- .name = "Basic write (with data verification)",
- .prepare = mmc_test_prepare_write,
- .run = mmc_test_verify_write,
- .cleanup = mmc_test_cleanup,
- },
-
- {
- .name = "Basic read (with data verification)",
- .prepare = mmc_test_prepare_read,
- .run = mmc_test_verify_read,
- .cleanup = mmc_test_cleanup,
- },
-
- {
- .name = "Multi-block write",
- .prepare = mmc_test_prepare_write,
- .run = mmc_test_multi_write,
- .cleanup = mmc_test_cleanup,
- },
-
- {
- .name = "Multi-block read",
- .prepare = mmc_test_prepare_read,
- .run = mmc_test_multi_read,
- .cleanup = mmc_test_cleanup,
- },
-
- {
- .name = "Power of two block writes",
- .prepare = mmc_test_prepare_write,
- .run = mmc_test_pow2_write,
- .cleanup = mmc_test_cleanup,
- },
-
- {
- .name = "Power of two block reads",
- .prepare = mmc_test_prepare_read,
- .run = mmc_test_pow2_read,
- .cleanup = mmc_test_cleanup,
- },
-
- {
- .name = "Weird sized block writes",
- .prepare = mmc_test_prepare_write,
- .run = mmc_test_weird_write,
- .cleanup = mmc_test_cleanup,
- },
-
- {
- .name = "Weird sized block reads",
- .prepare = mmc_test_prepare_read,
- .run = mmc_test_weird_read,
- .cleanup = mmc_test_cleanup,
- },
-
- {
- .name = "Badly aligned write",
- .prepare = mmc_test_prepare_write,
- .run = mmc_test_align_write,
- .cleanup = mmc_test_cleanup,
- },
-
- {
- .name = "Badly aligned read",
- .prepare = mmc_test_prepare_read,
- .run = mmc_test_align_read,
- .cleanup = mmc_test_cleanup,
- },
-
- {
- .name = "Badly aligned multi-block write",
- .prepare = mmc_test_prepare_write,
- .run = mmc_test_align_multi_write,
- .cleanup = mmc_test_cleanup,
- },
-
- {
- .name = "Badly aligned multi-block read",
- .prepare = mmc_test_prepare_read,
- .run = mmc_test_align_multi_read,
- .cleanup = mmc_test_cleanup,
- },
-
- {
- .name = "Correct xfer_size at write (start failure)",
- .run = mmc_test_xfersize_write,
- },
-
- {
- .name = "Correct xfer_size at read (start failure)",
- .run = mmc_test_xfersize_read,
- },
-
- {
- .name = "Correct xfer_size at write (midway failure)",
- .run = mmc_test_multi_xfersize_write,
- },
-
- {
- .name = "Correct xfer_size at read (midway failure)",
- .run = mmc_test_multi_xfersize_read,
- },
-
-#ifdef CONFIG_HIGHMEM
-
- {
- .name = "Highmem write",
- .prepare = mmc_test_prepare_write,
- .run = mmc_test_write_high,
- .cleanup = mmc_test_cleanup,
- },
-
- {
- .name = "Highmem read",
- .prepare = mmc_test_prepare_read,
- .run = mmc_test_read_high,
- .cleanup = mmc_test_cleanup,
- },
-
- {
- .name = "Multi-block highmem write",
- .prepare = mmc_test_prepare_write,
- .run = mmc_test_multi_write_high,
- .cleanup = mmc_test_cleanup,
- },
-
- {
- .name = "Multi-block highmem read",
- .prepare = mmc_test_prepare_read,
- .run = mmc_test_multi_read_high,
- .cleanup = mmc_test_cleanup,
- },
-
-#else
-
- {
- .name = "Highmem write",
- .run = mmc_test_no_highmem,
- },
-
- {
- .name = "Highmem read",
- .run = mmc_test_no_highmem,
- },
-
- {
- .name = "Multi-block highmem write",
- .run = mmc_test_no_highmem,
- },
-
- {
- .name = "Multi-block highmem read",
- .run = mmc_test_no_highmem,
- },
-
-#endif /* CONFIG_HIGHMEM */
-
- {
- .name = "Best-case read performance",
- .prepare = mmc_test_area_prepare_fill,
- .run = mmc_test_best_read_performance,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Best-case write performance",
- .prepare = mmc_test_area_prepare_erase,
- .run = mmc_test_best_write_performance,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Best-case read performance into scattered pages",
- .prepare = mmc_test_area_prepare_fill,
- .run = mmc_test_best_read_perf_max_scatter,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Best-case write performance from scattered pages",
- .prepare = mmc_test_area_prepare_erase,
- .run = mmc_test_best_write_perf_max_scatter,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Single read performance by transfer size",
- .prepare = mmc_test_area_prepare_fill,
- .run = mmc_test_profile_read_perf,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Single write performance by transfer size",
- .prepare = mmc_test_area_prepare,
- .run = mmc_test_profile_write_perf,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Single trim performance by transfer size",
- .prepare = mmc_test_area_prepare_fill,
- .run = mmc_test_profile_trim_perf,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Consecutive read performance by transfer size",
- .prepare = mmc_test_area_prepare_fill,
- .run = mmc_test_profile_seq_read_perf,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Consecutive write performance by transfer size",
- .prepare = mmc_test_area_prepare,
- .run = mmc_test_profile_seq_write_perf,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Consecutive trim performance by transfer size",
- .prepare = mmc_test_area_prepare,
- .run = mmc_test_profile_seq_trim_perf,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Random read performance by transfer size",
- .prepare = mmc_test_area_prepare,
- .run = mmc_test_random_read_perf,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Random write performance by transfer size",
- .prepare = mmc_test_area_prepare,
- .run = mmc_test_random_write_perf,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Large sequential read into scattered pages",
- .prepare = mmc_test_area_prepare,
- .run = mmc_test_large_seq_read_perf,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Large sequential write from scattered pages",
- .prepare = mmc_test_area_prepare,
- .run = mmc_test_large_seq_write_perf,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Write performance with blocking req 4k to 4MB",
- .prepare = mmc_test_area_prepare,
- .run = mmc_test_profile_mult_write_blocking_perf,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Write performance with non-blocking req 4k to 4MB",
- .prepare = mmc_test_area_prepare,
- .run = mmc_test_profile_mult_write_nonblock_perf,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Read performance with blocking req 4k to 4MB",
- .prepare = mmc_test_area_prepare,
- .run = mmc_test_profile_mult_read_blocking_perf,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Read performance with non-blocking req 4k to 4MB",
- .prepare = mmc_test_area_prepare,
- .run = mmc_test_profile_mult_read_nonblock_perf,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Write performance blocking req 1 to 512 sg elems",
- .prepare = mmc_test_area_prepare,
- .run = mmc_test_profile_sglen_wr_blocking_perf,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Write performance non-blocking req 1 to 512 sg elems",
- .prepare = mmc_test_area_prepare,
- .run = mmc_test_profile_sglen_wr_nonblock_perf,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Read performance blocking req 1 to 512 sg elems",
- .prepare = mmc_test_area_prepare,
- .run = mmc_test_profile_sglen_r_blocking_perf,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "Read performance non-blocking req 1 to 512 sg elems",
- .prepare = mmc_test_area_prepare,
- .run = mmc_test_profile_sglen_r_nonblock_perf,
- .cleanup = mmc_test_area_cleanup,
- },
-
- {
- .name = "eMMC hardware reset",
- .run = mmc_test_hw_reset,
- },
-};
-
-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;
-
- pr_info("%s: Starting tests of card %s...\n",
- mmc_hostname(test->card->host), mmc_card_id(test->card));
-
- 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;
-
- pr_info("%s: Test case %d. %s...\n",
- mmc_hostname(test->card->host), i + 1,
- mmc_test_cases[i].name);
-
- if (mmc_test_cases[i].prepare) {
- ret = mmc_test_cases[i].prepare(test);
- if (ret) {
- pr_info("%s: Result: Prepare "
- "stage failed! (%d)\n",
- mmc_hostname(test->card->host),
- ret);
- continue;
- }
- }
-
- 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:
- pr_info("%s: Result: OK\n",
- mmc_hostname(test->card->host));
- break;
- case RESULT_FAIL:
- pr_info("%s: Result: FAILED\n",
- mmc_hostname(test->card->host));
- break;
- case RESULT_UNSUP_HOST:
- pr_info("%s: Result: UNSUPPORTED "
- "(by host)\n",
- mmc_hostname(test->card->host));
- break;
- case RESULT_UNSUP_CARD:
- pr_info("%s: Result: UNSUPPORTED "
- "(by card)\n",
- mmc_hostname(test->card->host));
- break;
- default:
- pr_info("%s: Result: ERROR (%d)\n",
- 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) {
- pr_info("%s: Warning: Cleanup "
- "stage failed! (%d)\n",
- mmc_hostname(test->card->host),
- ret);
- }
- }
- }
-
- mmc_release_host(test->card->host);
-
- pr_info("%s: Tests completed.\n",
- mmc_hostname(test->card->host));
-}
-
-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 %u.%02u\n",
- tr->count, tr->sectors,
- (unsigned long)tr->ts.tv_sec,
- (unsigned long)tr->ts.tv_nsec,
- tr->rate, tr->iops / 100, tr->iops % 100);
- }
- }
-
- mutex_unlock(&mmc_test_lock);
-
- return 0;
-}
-
-static int mtf_test_open(struct inode *inode, struct file *file)
-{
- 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;
- char lbuf[12];
- long testcase;
-
- if (count >= sizeof(lbuf))
- return -EINVAL;
-
- 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);
-#ifdef CONFIG_HIGHMEM
- test->highmem = alloc_pages(GFP_KERNEL | __GFP_HIGHMEM, BUFFER_ORDER);
-#endif
-
-#ifdef CONFIG_HIGHMEM
- if (test->buffer && test->highmem) {
-#else
- if (test->buffer) {
-#endif
- mutex_lock(&mmc_test_lock);
- mmc_test_run(test, testcase);
- mutex_unlock(&mmc_test_lock);
- }
-
-#ifdef CONFIG_HIGHMEM
- __free_pages(test->highmem, BUFFER_ORDER);
-#endif
- kfree(test->buffer);
- kfree(test);
-
- return count;
-}
-
-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 int mtf_testlist_show(struct seq_file *sf, void *data)
-{
- int i;
-
- mutex_lock(&mmc_test_lock);
-
- for (i = 0; i < ARRAY_SIZE(mmc_test_cases); i++)
- seq_printf(sf, "%d:\t%s\n", i+1, mmc_test_cases[i].name);
-
- mutex_unlock(&mmc_test_lock);
-
- return 0;
-}
-
-static int mtf_testlist_open(struct inode *inode, struct file *file)
-{
- return single_open(file, mtf_testlist_show, inode->i_private);
-}
-
-static const struct file_operations mmc_test_fops_testlist = {
- .open = mtf_testlist_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static void mmc_test_free_dbgfs_file(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_dbgfs_file(struct mmc_card *card,
- const char *name, umode_t mode, const struct file_operations *fops)
-{
- struct dentry *file = NULL;
- struct mmc_test_dbgfs_file *df;
-
- if (card->debugfs_root)
- file = debugfs_create_file(name, mode, card->debugfs_root,
- card, fops);
-
- if (IS_ERR_OR_NULL(file)) {
- dev_err(&card->dev,
- "Can't create %s. Perhaps debugfs is disabled.\n",
- name);
- return -ENODEV;
- }
-
- 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");
- return -ENOMEM;
- }
-
- df->card = card;
- df->file = file;
-
- list_add(&df->link, &mmc_test_file_test);
- return 0;
-}
-
-static int mmc_test_register_dbgfs_file(struct mmc_card *card)
-{
- int ret;
-
- mutex_lock(&mmc_test_lock);
-
- ret = __mmc_test_register_dbgfs_file(card, "test", S_IWUSR | S_IRUGO,
- &mmc_test_fops_test);
- if (ret)
- goto err;
-
- ret = __mmc_test_register_dbgfs_file(card, "testlist", S_IRUGO,
- &mmc_test_fops_testlist);
- if (ret)
- goto err;
-
-err:
- mutex_unlock(&mmc_test_lock);
-
- return ret;
-}
-
-static int mmc_test_probe(struct mmc_card *card)
-{
- int ret;
-
- if (!mmc_card_mmc(card) && !mmc_card_sd(card))
- return -ENODEV;
-
- ret = mmc_test_register_dbgfs_file(card);
- if (ret)
- return ret;
-
- dev_info(&card->dev, "Card claimed for testing.\n");
-
- return 0;
-}
-
-static void mmc_test_remove(struct mmc_card *card)
-{
- mmc_test_free_result(card);
- mmc_test_free_dbgfs_file(card);
-}
-
-static struct mmc_driver mmc_driver = {
- .drv = {
- .name = "mmc_test",
- },
- .probe = mmc_test_probe,
- .remove = mmc_test_remove,
-};
-
-static int __init mmc_test_init(void)
-{
- return mmc_register_driver(&mmc_driver);
-}
-
-static void __exit mmc_test_exit(void)
-{
- /* Clear stalled data if card is still plugged */
- mmc_test_free_result(NULL);
- mmc_test_free_dbgfs_file(NULL);
-
- mmc_unregister_driver(&mmc_driver);
-}
-
-module_init(mmc_test_init);
-module_exit(mmc_test_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Multimedia Card (MMC) host test driver");
-MODULE_AUTHOR("Pierre Ossman");
diff --git a/ANDROID_3.4.5/drivers/mmc/card/queue.c b/ANDROID_3.4.5/drivers/mmc/card/queue.c
deleted file mode 100644
index 996f8e36..00000000
--- a/ANDROID_3.4.5/drivers/mmc/card/queue.c
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * linux/drivers/mmc/card/queue.c
- *
- * Copyright (C) 2003 Russell King, All Rights Reserved.
- * Copyright 2006-2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/blkdev.h>
-#include <linux/freezer.h>
-#include <linux/kthread.h>
-#include <linux/scatterlist.h>
-
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-#include "queue.h"
-
-#define MMC_QUEUE_BOUNCESZ 65536
-
-#define MMC_QUEUE_SUSPENDED (1 << 0)
-
-/*
- * Prepare a MMC request. This just filters out odd stuff.
- */
-static int mmc_prep_request(struct request_queue *q, struct request *req)
-{
- struct mmc_queue *mq = q->queuedata;
-
- /*
- * We only like normal block requests and discards.
- */
- if (req->cmd_type != REQ_TYPE_FS && !(req->cmd_flags & REQ_DISCARD)) {
- blk_dump_rq_flags(req, "MMC bad request");
- return BLKPREP_KILL;
- }
-
- if (mq && mmc_card_removed(mq->card))
- return BLKPREP_KILL;
-
- req->cmd_flags |= REQ_DONTPREP;
-
- return BLKPREP_OK;
-}
-
-static int mmc_queue_thread(void *d)
-{
- struct mmc_queue *mq = d;
- struct request_queue *q = mq->queue;
-
- current->flags |= PF_MEMALLOC;
-
- down(&mq->thread_sem);
- do {
- struct request *req = NULL;
- struct mmc_queue_req *tmp;
-
- spin_lock_irq(q->queue_lock);
- set_current_state(TASK_INTERRUPTIBLE);
- req = blk_fetch_request(q);
- mq->mqrq_cur->req = req;
- spin_unlock_irq(q->queue_lock);
-
- if (req || mq->mqrq_prev->req) {
- set_current_state(TASK_RUNNING);
- mq->issue_fn(mq, req);
- } else {
- if (kthread_should_stop()) {
- set_current_state(TASK_RUNNING);
- break;
- }
- up(&mq->thread_sem);
- schedule();
- down(&mq->thread_sem);
- }
-
- /* Current request becomes previous request and vice versa. */
- mq->mqrq_prev->brq.mrq.data = NULL;
- mq->mqrq_prev->req = NULL;
- tmp = mq->mqrq_prev;
- mq->mqrq_prev = mq->mqrq_cur;
- mq->mqrq_cur = tmp;
- } while (1);
- up(&mq->thread_sem);
-
- return 0;
-}
-
-/*
- * Generic MMC request handler. This is called for any queue on a
- * particular host. When the host is not busy, we look for a request
- * on any queue on this host, and attempt to issue it. This may
- * not be the queue we were asked to process.
- */
-static void mmc_request(struct request_queue *q)
-{
- struct mmc_queue *mq = q->queuedata;
- struct request *req;
-
- if (!mq) {
- while ((req = blk_fetch_request(q)) != NULL) {
- req->cmd_flags |= REQ_QUIET;
- __blk_end_request_all(req, -EIO);
- }
- return;
- }
-
- if (!mq->mqrq_cur->req && !mq->mqrq_prev->req)
- wake_up_process(mq->thread);
-}
-
-static struct scatterlist *mmc_alloc_sg(int sg_len, int *err)
-{
- struct scatterlist *sg;
-
- sg = kmalloc(sizeof(struct scatterlist)*sg_len, GFP_KERNEL);
- if (!sg)
- *err = -ENOMEM;
- else {
- *err = 0;
- sg_init_table(sg, sg_len);
- }
-
- return sg;
-}
-
-static void mmc_queue_setup_discard(struct request_queue *q,
- struct mmc_card *card)
-{
- unsigned max_discard;
-
- max_discard = mmc_calc_max_discard(card);
- if (!max_discard)
- return;
-
- queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
- q->limits.max_discard_sectors = max_discard;
- if (card->erased_byte == 0 && !mmc_can_discard(card))
- q->limits.discard_zeroes_data = 1;
- q->limits.discard_granularity = card->pref_erase << 9;
- /* granularity must not be greater than max. discard */
- if (card->pref_erase > max_discard)
- q->limits.discard_granularity = 0;
- if (mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))
- queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q);
-}
-
-/**
- * mmc_init_queue - initialise a queue structure.
- * @mq: mmc queue
- * @card: mmc card to attach this queue
- * @lock: queue lock
- * @subname: partition subname
- *
- * Initialise a MMC card request queue.
- */
-int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
- spinlock_t *lock, const char *subname)
-{
- struct mmc_host *host = card->host;
- u64 limit = BLK_BOUNCE_HIGH;
- int ret;
- struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
- struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
-
- if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
- limit = *mmc_dev(host)->dma_mask;
-
- mq->card = card;
- mq->queue = blk_init_queue(mmc_request, lock);
- if (!mq->queue)
- return -ENOMEM;
-
- memset(&mq->mqrq_cur, 0, sizeof(mq->mqrq_cur));
- memset(&mq->mqrq_prev, 0, sizeof(mq->mqrq_prev));
- mq->mqrq_cur = mqrq_cur;
- mq->mqrq_prev = mqrq_prev;
- mq->queue->queuedata = mq;
-
- blk_queue_prep_rq(mq->queue, mmc_prep_request);
- queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
- if (mmc_can_erase(card))
- mmc_queue_setup_discard(mq->queue, card);
-
-#ifdef CONFIG_MMC_BLOCK_BOUNCE
- if (host->max_segs == 1) {
- unsigned int bouncesz;
-
- bouncesz = MMC_QUEUE_BOUNCESZ;
-
- if (bouncesz > host->max_req_size)
- bouncesz = host->max_req_size;
- if (bouncesz > host->max_seg_size)
- bouncesz = host->max_seg_size;
- if (bouncesz > (host->max_blk_count * 512))
- bouncesz = host->max_blk_count * 512;
-
- if (bouncesz > 512) {
- mqrq_cur->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
- if (!mqrq_cur->bounce_buf) {
- pr_warning("%s: unable to "
- "allocate bounce cur buffer\n",
- mmc_card_name(card));
- }
- mqrq_prev->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
- if (!mqrq_prev->bounce_buf) {
- pr_warning("%s: unable to "
- "allocate bounce prev buffer\n",
- mmc_card_name(card));
- kfree(mqrq_cur->bounce_buf);
- mqrq_cur->bounce_buf = NULL;
- }
- }
-
- if (mqrq_cur->bounce_buf && mqrq_prev->bounce_buf) {
- blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
- blk_queue_max_hw_sectors(mq->queue, bouncesz / 512);
- blk_queue_max_segments(mq->queue, bouncesz / 512);
- blk_queue_max_segment_size(mq->queue, bouncesz);
-
- mqrq_cur->sg = mmc_alloc_sg(1, &ret);
- if (ret)
- goto cleanup_queue;
-
- mqrq_cur->bounce_sg =
- mmc_alloc_sg(bouncesz / 512, &ret);
- if (ret)
- goto cleanup_queue;
-
- mqrq_prev->sg = mmc_alloc_sg(1, &ret);
- if (ret)
- goto cleanup_queue;
-
- mqrq_prev->bounce_sg =
- mmc_alloc_sg(bouncesz / 512, &ret);
- if (ret)
- goto cleanup_queue;
- }
- }
-#endif
-
- if (!mqrq_cur->bounce_buf && !mqrq_prev->bounce_buf) {
- 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_segs);
- blk_queue_max_segment_size(mq->queue, host->max_seg_size);
-
- mqrq_cur->sg = mmc_alloc_sg(host->max_segs, &ret);
- if (ret)
- goto cleanup_queue;
-
-
- mqrq_prev->sg = mmc_alloc_sg(host->max_segs, &ret);
- if (ret)
- goto cleanup_queue;
- }
-
- sema_init(&mq->thread_sem, 1);
-
- mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d%s",
- host->index, subname ? subname : "");
-
- if (IS_ERR(mq->thread)) {
- ret = PTR_ERR(mq->thread);
- goto free_bounce_sg;
- }
-
- return 0;
- free_bounce_sg:
- kfree(mqrq_cur->bounce_sg);
- mqrq_cur->bounce_sg = NULL;
- kfree(mqrq_prev->bounce_sg);
- mqrq_prev->bounce_sg = NULL;
-
- cleanup_queue:
- kfree(mqrq_cur->sg);
- mqrq_cur->sg = NULL;
- kfree(mqrq_cur->bounce_buf);
- mqrq_cur->bounce_buf = NULL;
-
- kfree(mqrq_prev->sg);
- mqrq_prev->sg = NULL;
- kfree(mqrq_prev->bounce_buf);
- mqrq_prev->bounce_buf = NULL;
-
- blk_cleanup_queue(mq->queue);
- return ret;
-}
-
-void mmc_cleanup_queue(struct mmc_queue *mq)
-{
- struct request_queue *q = mq->queue;
- unsigned long flags;
- struct mmc_queue_req *mqrq_cur = mq->mqrq_cur;
- struct mmc_queue_req *mqrq_prev = mq->mqrq_prev;
-
- /* Make sure the queue isn't suspended, as that will deadlock */
- mmc_queue_resume(mq);
-
- /* Then terminate our worker thread */
- kthread_stop(mq->thread);
-
- /* Empty the queue */
- spin_lock_irqsave(q->queue_lock, flags);
- q->queuedata = NULL;
- blk_start_queue(q);
- spin_unlock_irqrestore(q->queue_lock, flags);
-
- kfree(mqrq_cur->bounce_sg);
- mqrq_cur->bounce_sg = NULL;
-
- kfree(mqrq_cur->sg);
- mqrq_cur->sg = NULL;
-
- kfree(mqrq_cur->bounce_buf);
- mqrq_cur->bounce_buf = NULL;
-
- kfree(mqrq_prev->bounce_sg);
- mqrq_prev->bounce_sg = NULL;
-
- kfree(mqrq_prev->sg);
- mqrq_prev->sg = NULL;
-
- kfree(mqrq_prev->bounce_buf);
- mqrq_prev->bounce_buf = NULL;
-
- mq->card = NULL;
-}
-EXPORT_SYMBOL(mmc_cleanup_queue);
-
-/**
- * mmc_queue_suspend - suspend a MMC request queue
- * @mq: MMC queue to suspend
- *
- * Stop the block request queue, and wait for our thread to
- * complete any outstanding requests. This ensures that we
- * won't suspend while a request is being processed.
- */
-void mmc_queue_suspend(struct mmc_queue *mq)
-{
- struct request_queue *q = mq->queue;
- unsigned long flags;
-
- if (!(mq->flags & MMC_QUEUE_SUSPENDED)) {
- mq->flags |= MMC_QUEUE_SUSPENDED;
-
- spin_lock_irqsave(q->queue_lock, flags);
- blk_stop_queue(q);
- spin_unlock_irqrestore(q->queue_lock, flags);
-
- down(&mq->thread_sem);
- }
-}
-
-/**
- * mmc_queue_resume - resume a previously suspended MMC request queue
- * @mq: MMC queue to resume
- */
-void mmc_queue_resume(struct mmc_queue *mq)
-{
- struct request_queue *q = mq->queue;
- unsigned long flags;
-
- if (mq->flags & MMC_QUEUE_SUSPENDED) {
- mq->flags &= ~MMC_QUEUE_SUSPENDED;
-
- up(&mq->thread_sem);
-
- spin_lock_irqsave(q->queue_lock, flags);
- blk_start_queue(q);
- spin_unlock_irqrestore(q->queue_lock, flags);
- }
-}
-
-/*
- * Prepare the sg list(s) to be handed of to the host driver
- */
-unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq)
-{
- unsigned int sg_len;
- size_t buflen;
- struct scatterlist *sg;
- int i;
-
- if (!mqrq->bounce_buf)
- return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
-
- BUG_ON(!mqrq->bounce_sg);
-
- sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
-
- mqrq->bounce_sg_len = sg_len;
-
- buflen = 0;
- for_each_sg(mqrq->bounce_sg, sg, sg_len, i)
- buflen += sg->length;
-
- sg_init_one(mqrq->sg, mqrq->bounce_buf, buflen);
-
- return 1;
-}
-
-/*
- * If writing, bounce the data to the buffer before the request
- * is sent to the host driver
- */
-void mmc_queue_bounce_pre(struct mmc_queue_req *mqrq)
-{
- if (!mqrq->bounce_buf)
- return;
-
- if (rq_data_dir(mqrq->req) != WRITE)
- return;
-
- sg_copy_to_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
- mqrq->bounce_buf, mqrq->sg[0].length);
-}
-
-/*
- * If reading, bounce the data from the buffer after the request
- * has been handled by the host driver
- */
-void mmc_queue_bounce_post(struct mmc_queue_req *mqrq)
-{
- if (!mqrq->bounce_buf)
- return;
-
- if (rq_data_dir(mqrq->req) != READ)
- return;
-
- sg_copy_from_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
- mqrq->bounce_buf, mqrq->sg[0].length);
-}
diff --git a/ANDROID_3.4.5/drivers/mmc/card/queue.h b/ANDROID_3.4.5/drivers/mmc/card/queue.h
deleted file mode 100644
index d2a1eb4b..00000000
--- a/ANDROID_3.4.5/drivers/mmc/card/queue.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef MMC_QUEUE_H
-#define MMC_QUEUE_H
-
-struct request;
-struct task_struct;
-
-struct mmc_blk_request {
- struct mmc_request mrq;
- struct mmc_command sbc;
- struct mmc_command cmd;
- struct mmc_command stop;
- struct mmc_data data;
-};
-
-struct mmc_queue_req {
- struct request *req;
- struct mmc_blk_request brq;
- struct scatterlist *sg;
- char *bounce_buf;
- struct scatterlist *bounce_sg;
- unsigned int bounce_sg_len;
- struct mmc_async_req mmc_active;
-};
-
-struct mmc_queue {
- struct mmc_card *card;
- struct task_struct *thread;
- struct semaphore thread_sem;
- unsigned int flags;
- int (*issue_fn)(struct mmc_queue *, struct request *);
- void *data;
- struct request_queue *queue;
- struct mmc_queue_req mqrq[2];
- struct mmc_queue_req *mqrq_cur;
- struct mmc_queue_req *mqrq_prev;
-};
-
-extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
- const char *);
-extern void mmc_cleanup_queue(struct mmc_queue *);
-extern void mmc_queue_suspend(struct mmc_queue *);
-extern void mmc_queue_resume(struct mmc_queue *);
-
-extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
- struct mmc_queue_req *);
-extern void mmc_queue_bounce_pre(struct mmc_queue_req *);
-extern void mmc_queue_bounce_post(struct mmc_queue_req *);
-
-#endif
diff --git a/ANDROID_3.4.5/drivers/mmc/card/sdio_uart.c b/ANDROID_3.4.5/drivers/mmc/card/sdio_uart.c
deleted file mode 100644
index 5a2cbfac..00000000
--- a/ANDROID_3.4.5/drivers/mmc/card/sdio_uart.c
+++ /dev/null
@@ -1,1219 +0,0 @@
-/*
- * linux/drivers/mmc/card/sdio_uart.c - SDIO UART/GPS driver
- *
- * Based on drivers/serial/8250.c and drivers/serial/serial_core.c
- * by Russell King.
- *
- * Author: Nicolas Pitre
- * Created: June 15, 2007
- * Copyright: MontaVista Software, Inc.
- *
- * 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.
- */
-
-/*
- * Note: Although this driver assumes a 16550A-like UART implementation,
- * it is not possible to leverage the common 8250/16550 driver, nor the
- * core UART infrastructure, as they assumes direct access to the hardware
- * registers, often under a spinlock. This is not possible in the SDIO
- * context as SDIO access functions must be able to sleep.
- *
- * Because we need to lock the SDIO host to ensure an exclusive access to
- * the card, we simply rely on that lock to also prevent and serialize
- * concurrent access to the same port.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mutex.h>
-#include <linux/seq_file.h>
-#include <linux/serial_reg.h>
-#include <linux/circ_buf.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/kfifo.h>
-#include <linux/slab.h>
-
-#include <linux/mmc/core.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/sdio_ids.h>
-
-
-#define UART_NR 8 /* Number of UARTs this driver can handle */
-
-
-#define FIFO_SIZE PAGE_SIZE
-#define WAKEUP_CHARS 256
-
-struct uart_icount {
- __u32 cts;
- __u32 dsr;
- __u32 rng;
- __u32 dcd;
- __u32 rx;
- __u32 tx;
- __u32 frame;
- __u32 overrun;
- __u32 parity;
- __u32 brk;
-};
-
-struct sdio_uart_port {
- struct tty_port port;
- struct kref kref;
- struct tty_struct *tty;
- unsigned int index;
- struct sdio_func *func;
- struct mutex func_lock;
- struct task_struct *in_sdio_uart_irq;
- unsigned int regs_offset;
- struct kfifo xmit_fifo;
- spinlock_t write_lock;
- struct uart_icount icount;
- unsigned int uartclk;
- unsigned int mctrl;
- unsigned int rx_mctrl;
- unsigned int read_status_mask;
- unsigned int ignore_status_mask;
- unsigned char x_char;
- unsigned char ier;
- unsigned char lcr;
-};
-
-static struct sdio_uart_port *sdio_uart_table[UART_NR];
-static DEFINE_SPINLOCK(sdio_uart_table_lock);
-
-static int sdio_uart_add_port(struct sdio_uart_port *port)
-{
- int index, ret = -EBUSY;
-
- kref_init(&port->kref);
- mutex_init(&port->func_lock);
- spin_lock_init(&port->write_lock);
- if (kfifo_alloc(&port->xmit_fifo, FIFO_SIZE, GFP_KERNEL))
- return -ENOMEM;
-
- spin_lock(&sdio_uart_table_lock);
- for (index = 0; index < UART_NR; index++) {
- if (!sdio_uart_table[index]) {
- port->index = index;
- sdio_uart_table[index] = port;
- ret = 0;
- break;
- }
- }
- spin_unlock(&sdio_uart_table_lock);
-
- return ret;
-}
-
-static struct sdio_uart_port *sdio_uart_port_get(unsigned index)
-{
- struct sdio_uart_port *port;
-
- if (index >= UART_NR)
- return NULL;
-
- spin_lock(&sdio_uart_table_lock);
- port = sdio_uart_table[index];
- if (port)
- kref_get(&port->kref);
- spin_unlock(&sdio_uart_table_lock);
-
- return port;
-}
-
-static void sdio_uart_port_destroy(struct kref *kref)
-{
- struct sdio_uart_port *port =
- container_of(kref, struct sdio_uart_port, kref);
- kfifo_free(&port->xmit_fifo);
- kfree(port);
-}
-
-static void sdio_uart_port_put(struct sdio_uart_port *port)
-{
- kref_put(&port->kref, sdio_uart_port_destroy);
-}
-
-static void sdio_uart_port_remove(struct sdio_uart_port *port)
-{
- struct sdio_func *func;
- struct tty_struct *tty;
-
- BUG_ON(sdio_uart_table[port->index] != port);
-
- spin_lock(&sdio_uart_table_lock);
- sdio_uart_table[port->index] = NULL;
- spin_unlock(&sdio_uart_table_lock);
-
- /*
- * We're killing a port that potentially still is in use by
- * the tty layer. Be careful to prevent any further access
- * to the SDIO function and arrange for the tty layer to
- * give up on that port ASAP.
- * Beware: the lock ordering is critical.
- */
- mutex_lock(&port->port.mutex);
- mutex_lock(&port->func_lock);
- func = port->func;
- sdio_claim_host(func);
- port->func = NULL;
- mutex_unlock(&port->func_lock);
- tty = tty_port_tty_get(&port->port);
- /* tty_hangup is async so is this safe as is ?? */
- if (tty) {
- tty_hangup(tty);
- tty_kref_put(tty);
- }
- mutex_unlock(&port->port.mutex);
- sdio_release_irq(func);
- sdio_disable_func(func);
- sdio_release_host(func);
-
- sdio_uart_port_put(port);
-}
-
-static int sdio_uart_claim_func(struct sdio_uart_port *port)
-{
- mutex_lock(&port->func_lock);
- if (unlikely(!port->func)) {
- mutex_unlock(&port->func_lock);
- return -ENODEV;
- }
- if (likely(port->in_sdio_uart_irq != current))
- sdio_claim_host(port->func);
- mutex_unlock(&port->func_lock);
- return 0;
-}
-
-static inline void sdio_uart_release_func(struct sdio_uart_port *port)
-{
- if (likely(port->in_sdio_uart_irq != current))
- sdio_release_host(port->func);
-}
-
-static inline unsigned int sdio_in(struct sdio_uart_port *port, int offset)
-{
- unsigned char c;
- c = sdio_readb(port->func, port->regs_offset + offset, NULL);
- return c;
-}
-
-static inline void sdio_out(struct sdio_uart_port *port, int offset, int value)
-{
- sdio_writeb(port->func, value, port->regs_offset + offset, NULL);
-}
-
-static unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port)
-{
- unsigned char status;
- unsigned int ret;
-
- /* FIXME: What stops this losing the delta bits and breaking
- sdio_uart_check_modem_status ? */
- status = sdio_in(port, UART_MSR);
-
- ret = 0;
- if (status & UART_MSR_DCD)
- ret |= TIOCM_CAR;
- if (status & UART_MSR_RI)
- ret |= TIOCM_RNG;
- if (status & UART_MSR_DSR)
- ret |= TIOCM_DSR;
- if (status & UART_MSR_CTS)
- ret |= TIOCM_CTS;
- return ret;
-}
-
-static void sdio_uart_write_mctrl(struct sdio_uart_port *port,
- unsigned int mctrl)
-{
- unsigned char mcr = 0;
-
- if (mctrl & TIOCM_RTS)
- mcr |= UART_MCR_RTS;
- if (mctrl & TIOCM_DTR)
- mcr |= UART_MCR_DTR;
- if (mctrl & TIOCM_OUT1)
- mcr |= UART_MCR_OUT1;
- if (mctrl & TIOCM_OUT2)
- mcr |= UART_MCR_OUT2;
- if (mctrl & TIOCM_LOOP)
- mcr |= UART_MCR_LOOP;
-
- sdio_out(port, UART_MCR, mcr);
-}
-
-static inline void sdio_uart_update_mctrl(struct sdio_uart_port *port,
- unsigned int set, unsigned int clear)
-{
- unsigned int old;
-
- old = port->mctrl;
- port->mctrl = (old & ~clear) | set;
- if (old != port->mctrl)
- sdio_uart_write_mctrl(port, port->mctrl);
-}
-
-#define sdio_uart_set_mctrl(port, x) sdio_uart_update_mctrl(port, x, 0)
-#define sdio_uart_clear_mctrl(port, x) sdio_uart_update_mctrl(port, 0, x)
-
-static void sdio_uart_change_speed(struct sdio_uart_port *port,
- struct ktermios *termios,
- struct ktermios *old)
-{
- unsigned char cval, fcr = 0;
- unsigned int baud, quot;
-
- switch (termios->c_cflag & CSIZE) {
- case CS5:
- cval = UART_LCR_WLEN5;
- break;
- case CS6:
- cval = UART_LCR_WLEN6;
- break;
- case CS7:
- cval = UART_LCR_WLEN7;
- break;
- default:
- case CS8:
- cval = UART_LCR_WLEN8;
- break;
- }
-
- if (termios->c_cflag & CSTOPB)
- cval |= UART_LCR_STOP;
- if (termios->c_cflag & PARENB)
- cval |= UART_LCR_PARITY;
- if (!(termios->c_cflag & PARODD))
- cval |= UART_LCR_EPAR;
-
- for (;;) {
- baud = tty_termios_baud_rate(termios);
- if (baud == 0)
- baud = 9600; /* Special case: B0 rate. */
- if (baud <= port->uartclk)
- break;
- /*
- * Oops, the quotient was zero. Try again with the old
- * baud rate if possible, otherwise default to 9600.
- */
- termios->c_cflag &= ~CBAUD;
- if (old) {
- termios->c_cflag |= old->c_cflag & CBAUD;
- old = NULL;
- } else
- termios->c_cflag |= B9600;
- }
- quot = (2 * port->uartclk + baud) / (2 * baud);
-
- if (baud < 2400)
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
- else
- fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;
-
- port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
- if (termios->c_iflag & INPCK)
- port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- if (termios->c_iflag & (BRKINT | PARMRK))
- port->read_status_mask |= UART_LSR_BI;
-
- /*
- * Characters to ignore
- */
- port->ignore_status_mask = 0;
- if (termios->c_iflag & IGNPAR)
- port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
- if (termios->c_iflag & IGNBRK) {
- port->ignore_status_mask |= UART_LSR_BI;
- /*
- * If we're ignoring parity and break indicators,
- * ignore overruns too (for real raw support).
- */
- if (termios->c_iflag & IGNPAR)
- port->ignore_status_mask |= UART_LSR_OE;
- }
-
- /*
- * ignore all characters if CREAD is not set
- */
- if ((termios->c_cflag & CREAD) == 0)
- port->ignore_status_mask |= UART_LSR_DR;
-
- /*
- * CTS flow control flag and modem status interrupts
- */
- port->ier &= ~UART_IER_MSI;
- if ((termios->c_cflag & CRTSCTS) || !(termios->c_cflag & CLOCAL))
- port->ier |= UART_IER_MSI;
-
- port->lcr = cval;
-
- sdio_out(port, UART_IER, port->ier);
- sdio_out(port, UART_LCR, cval | UART_LCR_DLAB);
- sdio_out(port, UART_DLL, quot & 0xff);
- sdio_out(port, UART_DLM, quot >> 8);
- sdio_out(port, UART_LCR, cval);
- sdio_out(port, UART_FCR, fcr);
-
- sdio_uart_write_mctrl(port, port->mctrl);
-}
-
-static void sdio_uart_start_tx(struct sdio_uart_port *port)
-{
- if (!(port->ier & UART_IER_THRI)) {
- port->ier |= UART_IER_THRI;
- sdio_out(port, UART_IER, port->ier);
- }
-}
-
-static void sdio_uart_stop_tx(struct sdio_uart_port *port)
-{
- if (port->ier & UART_IER_THRI) {
- port->ier &= ~UART_IER_THRI;
- sdio_out(port, UART_IER, port->ier);
- }
-}
-
-static void sdio_uart_stop_rx(struct sdio_uart_port *port)
-{
- port->ier &= ~UART_IER_RLSI;
- port->read_status_mask &= ~UART_LSR_DR;
- sdio_out(port, UART_IER, port->ier);
-}
-
-static void sdio_uart_receive_chars(struct sdio_uart_port *port,
- unsigned int *status)
-{
- struct tty_struct *tty = tty_port_tty_get(&port->port);
- unsigned int ch, flag;
- int max_count = 256;
-
- do {
- ch = sdio_in(port, UART_RX);
- flag = TTY_NORMAL;
- port->icount.rx++;
-
- if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
- UART_LSR_FE | UART_LSR_OE))) {
- /*
- * For statistics only
- */
- if (*status & UART_LSR_BI) {
- *status &= ~(UART_LSR_FE | UART_LSR_PE);
- port->icount.brk++;
- } else if (*status & UART_LSR_PE)
- port->icount.parity++;
- else if (*status & UART_LSR_FE)
- port->icount.frame++;
- if (*status & UART_LSR_OE)
- port->icount.overrun++;
-
- /*
- * Mask off conditions which should be ignored.
- */
- *status &= port->read_status_mask;
- if (*status & UART_LSR_BI)
- flag = TTY_BREAK;
- else if (*status & UART_LSR_PE)
- flag = TTY_PARITY;
- else if (*status & UART_LSR_FE)
- flag = TTY_FRAME;
- }
-
- if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0)
- if (tty)
- tty_insert_flip_char(tty, ch, flag);
-
- /*
- * Overrun is special. Since it's reported immediately,
- * it doesn't affect the current character.
- */
- if (*status & ~port->ignore_status_mask & UART_LSR_OE)
- if (tty)
- tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-
- *status = sdio_in(port, UART_LSR);
- } while ((*status & UART_LSR_DR) && (max_count-- > 0));
- if (tty) {
- tty_flip_buffer_push(tty);
- tty_kref_put(tty);
- }
-}
-
-static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
-{
- struct kfifo *xmit = &port->xmit_fifo;
- int count;
- struct tty_struct *tty;
- u8 iobuf[16];
- int len;
-
- if (port->x_char) {
- sdio_out(port, UART_TX, port->x_char);
- port->icount.tx++;
- port->x_char = 0;
- return;
- }
-
- tty = tty_port_tty_get(&port->port);
-
- if (tty == NULL || !kfifo_len(xmit) ||
- tty->stopped || tty->hw_stopped) {
- sdio_uart_stop_tx(port);
- tty_kref_put(tty);
- return;
- }
-
- len = kfifo_out_locked(xmit, iobuf, 16, &port->write_lock);
- for (count = 0; count < len; count++) {
- sdio_out(port, UART_TX, iobuf[count]);
- port->icount.tx++;
- }
-
- len = kfifo_len(xmit);
- if (len < WAKEUP_CHARS) {
- tty_wakeup(tty);
- if (len == 0)
- sdio_uart_stop_tx(port);
- }
- tty_kref_put(tty);
-}
-
-static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
-{
- int status;
- struct tty_struct *tty;
-
- status = sdio_in(port, UART_MSR);
-
- if ((status & UART_MSR_ANY_DELTA) == 0)
- return;
-
- if (status & UART_MSR_TERI)
- port->icount.rng++;
- if (status & UART_MSR_DDSR)
- port->icount.dsr++;
- if (status & UART_MSR_DDCD) {
- port->icount.dcd++;
- /* DCD raise - wake for open */
- if (status & UART_MSR_DCD)
- wake_up_interruptible(&port->port.open_wait);
- else {
- /* DCD drop - hang up if tty attached */
- tty = tty_port_tty_get(&port->port);
- if (tty) {
- tty_hangup(tty);
- tty_kref_put(tty);
- }
- }
- }
- if (status & UART_MSR_DCTS) {
- port->icount.cts++;
- tty = tty_port_tty_get(&port->port);
- if (tty && (tty->termios->c_cflag & CRTSCTS)) {
- int cts = (status & UART_MSR_CTS);
- if (tty->hw_stopped) {
- if (cts) {
- tty->hw_stopped = 0;
- sdio_uart_start_tx(port);
- tty_wakeup(tty);
- }
- } else {
- if (!cts) {
- tty->hw_stopped = 1;
- sdio_uart_stop_tx(port);
- }
- }
- }
- tty_kref_put(tty);
- }
-}
-
-/*
- * This handles the interrupt from one port.
- */
-static void sdio_uart_irq(struct sdio_func *func)
-{
- struct sdio_uart_port *port = sdio_get_drvdata(func);
- unsigned int iir, lsr;
-
- /*
- * In a few places sdio_uart_irq() is called directly instead of
- * waiting for the actual interrupt to be raised and the SDIO IRQ
- * thread scheduled in order to reduce latency. However, some
- * interaction with the tty core may end up calling us back
- * (serial echo, flow control, etc.) through those same places
- * causing undesirable effects. Let's stop the recursion here.
- */
- if (unlikely(port->in_sdio_uart_irq == current))
- return;
-
- iir = sdio_in(port, UART_IIR);
- if (iir & UART_IIR_NO_INT)
- return;
-
- port->in_sdio_uart_irq = current;
- lsr = sdio_in(port, UART_LSR);
- if (lsr & UART_LSR_DR)
- sdio_uart_receive_chars(port, &lsr);
- sdio_uart_check_modem_status(port);
- if (lsr & UART_LSR_THRE)
- sdio_uart_transmit_chars(port);
- port->in_sdio_uart_irq = NULL;
-}
-
-static int uart_carrier_raised(struct tty_port *tport)
-{
- struct sdio_uart_port *port =
- container_of(tport, struct sdio_uart_port, port);
- unsigned int ret = sdio_uart_claim_func(port);
- if (ret) /* Missing hardware shouldn't block for carrier */
- return 1;
- ret = sdio_uart_get_mctrl(port);
- sdio_uart_release_func(port);
- if (ret & TIOCM_CAR)
- return 1;
- return 0;
-}
-
-/**
- * uart_dtr_rts - port helper to set uart signals
- * @tport: tty port to be updated
- * @onoff: set to turn on DTR/RTS
- *
- * Called by the tty port helpers when the modem signals need to be
- * adjusted during an open, close and hangup.
- */
-
-static void uart_dtr_rts(struct tty_port *tport, int onoff)
-{
- struct sdio_uart_port *port =
- container_of(tport, struct sdio_uart_port, port);
- int ret = sdio_uart_claim_func(port);
- if (ret)
- return;
- if (onoff == 0)
- sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
- else
- sdio_uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
- sdio_uart_release_func(port);
-}
-
-/**
- * sdio_uart_activate - start up hardware
- * @tport: tty port to activate
- * @tty: tty bound to this port
- *
- * Activate a tty port. The port locking guarantees us this will be
- * run exactly once per set of opens, and if successful will see the
- * shutdown method run exactly once to match. Start up and shutdown are
- * protected from each other by the internal locking and will not run
- * at the same time even during a hangup event.
- *
- * If we successfully start up the port we take an extra kref as we
- * will keep it around until shutdown when the kref is dropped.
- */
-
-static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
-{
- struct sdio_uart_port *port =
- container_of(tport, struct sdio_uart_port, port);
- int ret;
-
- /*
- * Set the TTY IO error marker - we will only clear this
- * once we have successfully opened the port.
- */
- set_bit(TTY_IO_ERROR, &tty->flags);
-
- kfifo_reset(&port->xmit_fifo);
-
- ret = sdio_uart_claim_func(port);
- if (ret)
- return ret;
- ret = sdio_enable_func(port->func);
- if (ret)
- goto err1;
- ret = sdio_claim_irq(port->func, sdio_uart_irq);
- if (ret)
- goto err2;
-
- /*
- * Clear the FIFO buffers and disable them.
- * (they will be reenabled in sdio_change_speed())
- */
- sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO);
- sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO |
- UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
- sdio_out(port, UART_FCR, 0);
-
- /*
- * Clear the interrupt registers.
- */
- (void) sdio_in(port, UART_LSR);
- (void) sdio_in(port, UART_RX);
- (void) sdio_in(port, UART_IIR);
- (void) sdio_in(port, UART_MSR);
-
- /*
- * Now, initialize the UART
- */
- sdio_out(port, UART_LCR, UART_LCR_WLEN8);
-
- port->ier = UART_IER_RLSI|UART_IER_RDI|UART_IER_RTOIE|UART_IER_UUE;
- port->mctrl = TIOCM_OUT2;
-
- sdio_uart_change_speed(port, tty->termios, NULL);
-
- if (tty->termios->c_cflag & CBAUD)
- sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
-
- if (tty->termios->c_cflag & CRTSCTS)
- if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS))
- tty->hw_stopped = 1;
-
- clear_bit(TTY_IO_ERROR, &tty->flags);
-
- /* Kick the IRQ handler once while we're still holding the host lock */
- sdio_uart_irq(port->func);
-
- sdio_uart_release_func(port);
- return 0;
-
-err2:
- sdio_disable_func(port->func);
-err1:
- sdio_uart_release_func(port);
- return ret;
-}
-
-/**
- * sdio_uart_shutdown - stop hardware
- * @tport: tty port to shut down
- *
- * Deactivate a tty port. The port locking guarantees us this will be
- * run only if a successful matching activate already ran. The two are
- * protected from each other by the internal locking and will not run
- * at the same time even during a hangup event.
- */
-
-static void sdio_uart_shutdown(struct tty_port *tport)
-{
- struct sdio_uart_port *port =
- container_of(tport, struct sdio_uart_port, port);
- int ret;
-
- ret = sdio_uart_claim_func(port);
- if (ret)
- return;
-
- sdio_uart_stop_rx(port);
-
- /* Disable interrupts from this port */
- sdio_release_irq(port->func);
- port->ier = 0;
- sdio_out(port, UART_IER, 0);
-
- sdio_uart_clear_mctrl(port, TIOCM_OUT2);
-
- /* Disable break condition and FIFOs. */
- port->lcr &= ~UART_LCR_SBC;
- sdio_out(port, UART_LCR, port->lcr);
- sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO |
- UART_FCR_CLEAR_RCVR |
- UART_FCR_CLEAR_XMIT);
- sdio_out(port, UART_FCR, 0);
-
- sdio_disable_func(port->func);
-
- sdio_uart_release_func(port);
-}
-
-/**
- * sdio_uart_install - install method
- * @driver: the driver in use (sdio_uart in our case)
- * @tty: the tty being bound
- *
- * Look up and bind the tty and the driver together. Initialize
- * any needed private data (in our case the termios)
- */
-
-static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty)
-{
- int idx = tty->index;
- struct sdio_uart_port *port = sdio_uart_port_get(idx);
- int ret = tty_standard_install(driver, tty);
-
- if (ret == 0)
- /* This is the ref sdio_uart_port get provided */
- tty->driver_data = port;
- else
- sdio_uart_port_put(port);
- return ret;
-}
-
-/**
- * sdio_uart_cleanup - called on the last tty kref drop
- * @tty: the tty being destroyed
- *
- * Called asynchronously when the last reference to the tty is dropped.
- * We cannot destroy the tty->driver_data port kref until this point
- */
-
-static void sdio_uart_cleanup(struct tty_struct *tty)
-{
- struct sdio_uart_port *port = tty->driver_data;
- tty->driver_data = NULL; /* Bug trap */
- sdio_uart_port_put(port);
-}
-
-/*
- * Open/close/hangup is now entirely boilerplate
- */
-
-static int sdio_uart_open(struct tty_struct *tty, struct file *filp)
-{
- struct sdio_uart_port *port = tty->driver_data;
- return tty_port_open(&port->port, tty, filp);
-}
-
-static void sdio_uart_close(struct tty_struct *tty, struct file * filp)
-{
- struct sdio_uart_port *port = tty->driver_data;
- tty_port_close(&port->port, tty, filp);
-}
-
-static void sdio_uart_hangup(struct tty_struct *tty)
-{
- struct sdio_uart_port *port = tty->driver_data;
- tty_port_hangup(&port->port);
-}
-
-static int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf,
- int count)
-{
- struct sdio_uart_port *port = tty->driver_data;
- int ret;
-
- if (!port->func)
- return -ENODEV;
-
- ret = kfifo_in_locked(&port->xmit_fifo, buf, count, &port->write_lock);
- if (!(port->ier & UART_IER_THRI)) {
- int err = sdio_uart_claim_func(port);
- if (!err) {
- sdio_uart_start_tx(port);
- sdio_uart_irq(port->func);
- sdio_uart_release_func(port);
- } else
- ret = err;
- }
-
- return ret;
-}
-
-static int sdio_uart_write_room(struct tty_struct *tty)
-{
- struct sdio_uart_port *port = tty->driver_data;
- return FIFO_SIZE - kfifo_len(&port->xmit_fifo);
-}
-
-static int sdio_uart_chars_in_buffer(struct tty_struct *tty)
-{
- struct sdio_uart_port *port = tty->driver_data;
- return kfifo_len(&port->xmit_fifo);
-}
-
-static void sdio_uart_send_xchar(struct tty_struct *tty, char ch)
-{
- struct sdio_uart_port *port = tty->driver_data;
-
- port->x_char = ch;
- if (ch && !(port->ier & UART_IER_THRI)) {
- if (sdio_uart_claim_func(port) != 0)
- return;
- sdio_uart_start_tx(port);
- sdio_uart_irq(port->func);
- sdio_uart_release_func(port);
- }
-}
-
-static void sdio_uart_throttle(struct tty_struct *tty)
-{
- struct sdio_uart_port *port = tty->driver_data;
-
- if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))
- return;
-
- if (sdio_uart_claim_func(port) != 0)
- return;
-
- if (I_IXOFF(tty)) {
- port->x_char = STOP_CHAR(tty);
- sdio_uart_start_tx(port);
- }
-
- if (tty->termios->c_cflag & CRTSCTS)
- sdio_uart_clear_mctrl(port, TIOCM_RTS);
-
- sdio_uart_irq(port->func);
- sdio_uart_release_func(port);
-}
-
-static void sdio_uart_unthrottle(struct tty_struct *tty)
-{
- struct sdio_uart_port *port = tty->driver_data;
-
- if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))
- return;
-
- if (sdio_uart_claim_func(port) != 0)
- return;
-
- if (I_IXOFF(tty)) {
- if (port->x_char) {
- port->x_char = 0;
- } else {
- port->x_char = START_CHAR(tty);
- sdio_uart_start_tx(port);
- }
- }
-
- if (tty->termios->c_cflag & CRTSCTS)
- sdio_uart_set_mctrl(port, TIOCM_RTS);
-
- sdio_uart_irq(port->func);
- sdio_uart_release_func(port);
-}
-
-static void sdio_uart_set_termios(struct tty_struct *tty,
- struct ktermios *old_termios)
-{
- struct sdio_uart_port *port = tty->driver_data;
- unsigned int cflag = tty->termios->c_cflag;
-
- if (sdio_uart_claim_func(port) != 0)
- return;
-
- sdio_uart_change_speed(port, tty->termios, old_termios);
-
- /* Handle transition to B0 status */
- if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
- sdio_uart_clear_mctrl(port, TIOCM_RTS | TIOCM_DTR);
-
- /* Handle transition away from B0 status */
- if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
- unsigned int mask = TIOCM_DTR;
- if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags))
- mask |= TIOCM_RTS;
- sdio_uart_set_mctrl(port, mask);
- }
-
- /* Handle turning off CRTSCTS */
- if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
- sdio_uart_start_tx(port);
- }
-
- /* Handle turning on CRTSCTS */
- if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
- if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) {
- tty->hw_stopped = 1;
- sdio_uart_stop_tx(port);
- }
- }
-
- sdio_uart_release_func(port);
-}
-
-static int sdio_uart_break_ctl(struct tty_struct *tty, int break_state)
-{
- struct sdio_uart_port *port = tty->driver_data;
- int result;
-
- result = sdio_uart_claim_func(port);
- if (result != 0)
- return result;
-
- if (break_state == -1)
- port->lcr |= UART_LCR_SBC;
- else
- port->lcr &= ~UART_LCR_SBC;
- sdio_out(port, UART_LCR, port->lcr);
-
- sdio_uart_release_func(port);
- return 0;
-}
-
-static int sdio_uart_tiocmget(struct tty_struct *tty)
-{
- struct sdio_uart_port *port = tty->driver_data;
- int result;
-
- result = sdio_uart_claim_func(port);
- if (!result) {
- result = port->mctrl | sdio_uart_get_mctrl(port);
- sdio_uart_release_func(port);
- }
-
- return result;
-}
-
-static int sdio_uart_tiocmset(struct tty_struct *tty,
- unsigned int set, unsigned int clear)
-{
- struct sdio_uart_port *port = tty->driver_data;
- int result;
-
- result = sdio_uart_claim_func(port);
- if (!result) {
- sdio_uart_update_mctrl(port, set, clear);
- sdio_uart_release_func(port);
- }
-
- return result;
-}
-
-static int sdio_uart_proc_show(struct seq_file *m, void *v)
-{
- int i;
-
- seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n",
- "", "", "");
- for (i = 0; i < UART_NR; i++) {
- struct sdio_uart_port *port = sdio_uart_port_get(i);
- if (port) {
- seq_printf(m, "%d: uart:SDIO", i);
- if (capable(CAP_SYS_ADMIN)) {
- seq_printf(m, " tx:%d rx:%d",
- port->icount.tx, port->icount.rx);
- if (port->icount.frame)
- seq_printf(m, " fe:%d",
- port->icount.frame);
- if (port->icount.parity)
- seq_printf(m, " pe:%d",
- port->icount.parity);
- if (port->icount.brk)
- seq_printf(m, " brk:%d",
- port->icount.brk);
- if (port->icount.overrun)
- seq_printf(m, " oe:%d",
- port->icount.overrun);
- if (port->icount.cts)
- seq_printf(m, " cts:%d",
- port->icount.cts);
- if (port->icount.dsr)
- seq_printf(m, " dsr:%d",
- port->icount.dsr);
- if (port->icount.rng)
- seq_printf(m, " rng:%d",
- port->icount.rng);
- if (port->icount.dcd)
- seq_printf(m, " dcd:%d",
- port->icount.dcd);
- }
- sdio_uart_port_put(port);
- seq_putc(m, '\n');
- }
- }
- return 0;
-}
-
-static int sdio_uart_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, sdio_uart_proc_show, NULL);
-}
-
-static const struct file_operations sdio_uart_proc_fops = {
- .owner = THIS_MODULE,
- .open = sdio_uart_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct tty_port_operations sdio_uart_port_ops = {
- .dtr_rts = uart_dtr_rts,
- .carrier_raised = uart_carrier_raised,
- .shutdown = sdio_uart_shutdown,
- .activate = sdio_uart_activate,
-};
-
-static const struct tty_operations sdio_uart_ops = {
- .open = sdio_uart_open,
- .close = sdio_uart_close,
- .write = sdio_uart_write,
- .write_room = sdio_uart_write_room,
- .chars_in_buffer = sdio_uart_chars_in_buffer,
- .send_xchar = sdio_uart_send_xchar,
- .throttle = sdio_uart_throttle,
- .unthrottle = sdio_uart_unthrottle,
- .set_termios = sdio_uart_set_termios,
- .hangup = sdio_uart_hangup,
- .break_ctl = sdio_uart_break_ctl,
- .tiocmget = sdio_uart_tiocmget,
- .tiocmset = sdio_uart_tiocmset,
- .install = sdio_uart_install,
- .cleanup = sdio_uart_cleanup,
- .proc_fops = &sdio_uart_proc_fops,
-};
-
-static struct tty_driver *sdio_uart_tty_driver;
-
-static int sdio_uart_probe(struct sdio_func *func,
- const struct sdio_device_id *id)
-{
- struct sdio_uart_port *port;
- int ret;
-
- port = kzalloc(sizeof(struct sdio_uart_port), GFP_KERNEL);
- if (!port)
- return -ENOMEM;
-
- if (func->class == SDIO_CLASS_UART) {
- pr_warning("%s: need info on UART class basic setup\n",
- sdio_func_id(func));
- kfree(port);
- return -ENOSYS;
- } else if (func->class == SDIO_CLASS_GPS) {
- /*
- * We need tuple 0x91. It contains SUBTPL_SIOREG
- * and SUBTPL_RCVCAPS.
- */
- struct sdio_func_tuple *tpl;
- for (tpl = func->tuples; tpl; tpl = tpl->next) {
- if (tpl->code != 0x91)
- continue;
- if (tpl->size < 10)
- continue;
- if (tpl->data[1] == 0) /* SUBTPL_SIOREG */
- break;
- }
- if (!tpl) {
- pr_warning(
- "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n",
- sdio_func_id(func));
- kfree(port);
- return -EINVAL;
- }
- pr_debug("%s: Register ID = 0x%02x, Exp ID = 0x%02x\n",
- sdio_func_id(func), tpl->data[2], tpl->data[3]);
- port->regs_offset = (tpl->data[4] << 0) |
- (tpl->data[5] << 8) |
- (tpl->data[6] << 16);
- pr_debug("%s: regs offset = 0x%x\n",
- sdio_func_id(func), port->regs_offset);
- port->uartclk = tpl->data[7] * 115200;
- if (port->uartclk == 0)
- port->uartclk = 115200;
- pr_debug("%s: clk %d baudcode %u 4800-div %u\n",
- sdio_func_id(func), port->uartclk,
- tpl->data[7], tpl->data[8] | (tpl->data[9] << 8));
- } else {
- kfree(port);
- return -EINVAL;
- }
-
- port->func = func;
- sdio_set_drvdata(func, port);
- tty_port_init(&port->port);
- port->port.ops = &sdio_uart_port_ops;
-
- ret = sdio_uart_add_port(port);
- if (ret) {
- kfree(port);
- } else {
- struct device *dev;
- dev = tty_register_device(sdio_uart_tty_driver,
- port->index, &func->dev);
- if (IS_ERR(dev)) {
- sdio_uart_port_remove(port);
- ret = PTR_ERR(dev);
- }
- }
-
- return ret;
-}
-
-static void sdio_uart_remove(struct sdio_func *func)
-{
- struct sdio_uart_port *port = sdio_get_drvdata(func);
-
- tty_unregister_device(sdio_uart_tty_driver, port->index);
- sdio_uart_port_remove(port);
-}
-
-static const struct sdio_device_id sdio_uart_ids[] = {
- { SDIO_DEVICE_CLASS(SDIO_CLASS_UART) },
- { SDIO_DEVICE_CLASS(SDIO_CLASS_GPS) },
- { /* end: all zeroes */ },
-};
-
-MODULE_DEVICE_TABLE(sdio, sdio_uart_ids);
-
-static struct sdio_driver sdio_uart_driver = {
- .probe = sdio_uart_probe,
- .remove = sdio_uart_remove,
- .name = "sdio_uart",
- .id_table = sdio_uart_ids,
-};
-
-static int __init sdio_uart_init(void)
-{
- int ret;
- struct tty_driver *tty_drv;
-
- sdio_uart_tty_driver = tty_drv = alloc_tty_driver(UART_NR);
- if (!tty_drv)
- return -ENOMEM;
-
- tty_drv->driver_name = "sdio_uart";
- tty_drv->name = "ttySDIO";
- tty_drv->major = 0; /* dynamically allocated */
- tty_drv->minor_start = 0;
- tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
- tty_drv->subtype = SERIAL_TYPE_NORMAL;
- tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
- tty_drv->init_termios = tty_std_termios;
- tty_drv->init_termios.c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL;
- tty_drv->init_termios.c_ispeed = 4800;
- tty_drv->init_termios.c_ospeed = 4800;
- tty_set_operations(tty_drv, &sdio_uart_ops);
-
- ret = tty_register_driver(tty_drv);
- if (ret)
- goto err1;
-
- ret = sdio_register_driver(&sdio_uart_driver);
- if (ret)
- goto err2;
-
- return 0;
-
-err2:
- tty_unregister_driver(tty_drv);
-err1:
- put_tty_driver(tty_drv);
- return ret;
-}
-
-static void __exit sdio_uart_exit(void)
-{
- sdio_unregister_driver(&sdio_uart_driver);
- tty_unregister_driver(sdio_uart_tty_driver);
- put_tty_driver(sdio_uart_tty_driver);
-}
-
-module_init(sdio_uart_init);
-module_exit(sdio_uart_exit);
-
-MODULE_AUTHOR("Nicolas Pitre");
-MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/mmc/core/Kconfig b/ANDROID_3.4.5/drivers/mmc/core/Kconfig
deleted file mode 100644
index 85c2e1ac..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/Kconfig
+++ /dev/null
@@ -1,46 +0,0 @@
-#
-# MMC core configuration
-#
-
-config MMC_UNSAFE_RESUME
- bool "Assume MMC/SD cards are non-removable (DANGEROUS)"
- help
- If you say Y here, the MMC layer will assume that all cards
- stayed in their respective slots during the suspend. The
- normal behaviour is to remove them at suspend and
- redetecting them at resume. Breaking this assumption will
- in most cases result in data corruption.
-
- This option is usually just for embedded systems which use
- a MMC/SD card for rootfs. Most people should say N here.
-
- This option sets a default which can be overridden by the
- module parameter "removable=0" or "removable=1".
-
-config MMC_CLKGATE
- bool "MMC host clock gating (EXPERIMENTAL)"
- depends on EXPERIMENTAL
- help
- This will attempt to aggressively gate the clock to the MMC card.
- This is done to save power due to gating off the logic and bus
- noise when the MMC card is not in use. Your host driver has to
- support handling this in order for it to be of any use.
-
- If unsure, say N.
-
-config MMC_EMBEDDED_SDIO
- boolean "MMC embedded SDIO device support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
- help
- If you say Y here, support will be added for embedded SDIO
- devices which do not contain the necessary enumeration
- support in hardware to be properly detected.
-
-config MMC_PARANOID_SD_INIT
- bool "Enable paranoid SD card initialization (EXPERIMENTAL)"
- depends on EXPERIMENTAL
- help
- If you say Y here, the MMC layer will be extra paranoid
- about re-trying SD init requests. This can be a useful
- work-around for buggy controllers and hardware. Enable
- if you are experiencing issues with SD detection.
diff --git a/ANDROID_3.4.5/drivers/mmc/core/Makefile b/ANDROID_3.4.5/drivers/mmc/core/Makefile
deleted file mode 100644
index dca44283..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# Makefile for the kernel mmc core.
-#
-
-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 \
- sdio.o sdio_ops.o sdio_bus.o \
- sdio_cis.o sdio_io.o sdio_irq.o \
- quirks.o cd-gpio.o
-
-mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o
diff --git a/ANDROID_3.4.5/drivers/mmc/core/bus.c b/ANDROID_3.4.5/drivers/mmc/core/bus.c
deleted file mode 100644
index e2cbbc3c..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/bus.c
+++ /dev/null
@@ -1,454 +0,0 @@
-/*
- * linux/drivers/mmc/core/bus.c
- *
- * Copyright (C) 2003 Russell King, All Rights Reserved.
- * Copyright (C) 2007 Pierre Ossman
- *
- * 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.
- *
- * MMC card bus driver model
- */
-
-#include <linux/export.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/pm_runtime.h>
-
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-
-#include "core.h"
-#include "sdio_cis.h"
-#include "bus.h"
-
-#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
-
-#if 0
-#define DBG(x...) printk(KERN_ALERT x)
-#else
-#define DBG(x...) do { } while (0)
-#endif
-
-static ssize_t mmc_type_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mmc_card *card = mmc_dev_to_card(dev);
-
- DBG("[%s] s\n",__func__);
-
- switch (card->type) {
- case MMC_TYPE_MMC:
- DBG("[%s] e1\n",__func__);
- return sprintf(buf, "MMC\n");
- case MMC_TYPE_SD:
- DBG("[%s] e2\n",__func__);
- return sprintf(buf, "SD\n");
- case MMC_TYPE_SDIO:
- DBG("[%s] e3\n",__func__);
- return sprintf(buf, "SDIO\n");
- case MMC_TYPE_SD_COMBO:
- DBG("[%s] e4\n",__func__);
- return sprintf(buf, "SDcombo\n");
- default:
- DBG("[%s] e5\n",__func__);
- return -EFAULT;
- }
-}
-
-static struct device_attribute mmc_dev_attrs[] = {
- __ATTR(type, S_IRUGO, mmc_type_show, NULL),
- __ATTR_NULL,
-};
-
-/*
- * This currently matches any MMC driver to any MMC card - drivers
- * themselves make the decision whether to drive this card in their
- * probe method.
- */
-static int mmc_bus_match(struct device *dev, struct device_driver *drv)
-{
- DBG("[%s]\n",__func__);
- return 1;
-}
-
-static int
-mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- struct mmc_card *card = mmc_dev_to_card(dev);
- const char *type;
- int retval = 0;
-
- DBG("[%s] s\n",__func__);
-
- switch (card->type) {
- case MMC_TYPE_MMC:
- type = "MMC";
- break;
- case MMC_TYPE_SD:
- type = "SD";
- break;
- case MMC_TYPE_SDIO:
- type = "SDIO";
- break;
- case MMC_TYPE_SD_COMBO:
- type = "SDcombo";
- break;
- default:
- type = NULL;
- }
-
- if (type) {
- retval = add_uevent_var(env, "MMC_TYPE=%s", type);
- if (retval) {
- DBG("[%s] e1\n",__func__);
- return retval;
- }
- }
-
- retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card));
- if (retval) {
- DBG("[%s] e2\n",__func__);
- return retval;
- }
-
- /*
- * Request the mmc_block device. Note: that this is a direct request
- * for the module it carries no information as to what is inserted.
- */
- retval = add_uevent_var(env, "MODALIAS=mmc:block");
-
- DBG("[%s] e3\n",__func__);
- return retval;
-}
-
-static int mmc_bus_probe(struct device *dev)
-{
- struct mmc_driver *drv = to_mmc_driver(dev->driver);
- struct mmc_card *card = mmc_dev_to_card(dev);
-
- DBG("[%s]\n",__func__);
- return drv->probe(card);
-}
-
-static int mmc_bus_remove(struct device *dev)
-{
- struct mmc_driver *drv = to_mmc_driver(dev->driver);
- struct mmc_card *card = mmc_dev_to_card(dev);
-
- DBG("[%s] s\n",__func__);
-
- drv->remove(card);
-
- DBG("[%s] e\n",__func__);
- return 0;
-}
-
-static int mmc_bus_suspend(struct device *dev)
-{
- struct mmc_driver *drv = to_mmc_driver(dev->driver);
- struct mmc_card *card = mmc_dev_to_card(dev);
- pm_message_t state = { PM_EVENT_SUSPEND };
- int ret = 0;
-
- DBG("[%s] s\n",__func__);
-
- if (dev->driver && drv->suspend)
- ret = drv->suspend(card);
-
- DBG("[%s] e\n",__func__);
- return ret;
-}
-
-static int mmc_bus_resume(struct device *dev)
-{
- struct mmc_driver *drv = to_mmc_driver(dev->driver);
- struct mmc_card *card = mmc_dev_to_card(dev);
- int ret = 0;
-
- DBG("[%s] s\n",__func__);
-
- if (dev->driver && drv->resume)
- ret = drv->resume(card);
-
- DBG("[%s] e\n",__func__);
- return ret;
-}
-
-#ifdef CONFIG_PM_RUNTIME
-
-static int mmc_runtime_suspend(struct device *dev)
-{
- struct mmc_card *card = mmc_dev_to_card(dev);
- int ret;
-
- DBG("[%s] s\n",__func__);
-
- ret = mmc_power_save_host(card->host);
-
- DBG("[%s] e\n",__func__);
- /*return mmc_power_save_host(card->host);*/
- return ret;
-
-}
-
-static int mmc_runtime_resume(struct device *dev)
-{
- struct mmc_card *card = mmc_dev_to_card(dev);
- int ret;
-
- DBG("[%s] s\n",__func__);
-
- ret = mmc_power_restore_host(card->host);
-
- DBG("[%s] e\n",__func__);
- /*return mmc_power_restore_host(card->host);*/
- return ret;
-
-}
-
-static int mmc_runtime_idle(struct device *dev)
-{
- int ret;
-
- DBG("[%s] s\n",__func__);
-
- ret = pm_runtime_suspend(dev);
-
- DBG("[%s] e\n",__func__);
- /*return pm_runtime_suspend(dev);*/
- return ret;
-}
-
-#endif /* !CONFIG_PM_RUNTIME */
-
-static const struct dev_pm_ops mmc_bus_pm_ops = {
- SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume,
- mmc_runtime_idle)
- SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_suspend, mmc_bus_resume)
-};
-
-static struct bus_type mmc_bus_type = {
- .name = "mmc",
- .dev_attrs = mmc_dev_attrs,
- .match = mmc_bus_match,
- .uevent = mmc_bus_uevent,
- .probe = mmc_bus_probe,
- .remove = mmc_bus_remove,
- .pm = &mmc_bus_pm_ops,
-};
-
-int mmc_register_bus(void)
-{
- int ret;
-
- DBG("[%s] s\n",__func__);
-
- ret = bus_register(&mmc_bus_type);
-
- DBG("[%s] e\n",__func__);
- return ret;
- /*return bus_register(&mmc_bus_type);*/
-}
-
-void mmc_unregister_bus(void)
-{
- DBG("[%s] s\n",__func__);
-
- bus_unregister(&mmc_bus_type);
-
- DBG("[%s] e\n",__func__);
-}
-
-/**
- * mmc_register_driver - register a media driver
- * @drv: MMC media driver
- */
-int mmc_register_driver(struct mmc_driver *drv)
-{
- int ret;
-
- DBG("[%s] s\n",__func__);
-
- drv->drv.bus = &mmc_bus_type;
- ret = driver_register(&drv->drv);
-
- DBG("[%s] e\n",__func__);
- /*return driver_register(&drv->drv);*/
- return ret;
-
-}
-
-EXPORT_SYMBOL(mmc_register_driver);
-
-/**
- * mmc_unregister_driver - unregister a media driver
- * @drv: MMC media driver
- */
-void mmc_unregister_driver(struct mmc_driver *drv)
-{
- DBG("[%s] s\n",__func__);
-
- drv->drv.bus = &mmc_bus_type;
- driver_unregister(&drv->drv);
-
- DBG("[%s] e\n",__func__);
-}
-
-EXPORT_SYMBOL(mmc_unregister_driver);
-
-static void mmc_release_card(struct device *dev)
-{
- struct mmc_card *card = mmc_dev_to_card(dev);
-
- DBG("[%s] s\n",__func__);
-
- sdio_free_common_cis(card);
-
- if (card->info)
- kfree(card->info);
-
- kfree(card);
-
- DBG("[%s] e\n",__func__);
-}
-
-/*
- * Allocate and initialise a new MMC card structure.
- */
-struct mmc_card *mmc_alloc_card(struct mmc_host *host, struct device_type *type)
-{
- struct mmc_card *card;
- DBG("[%s] s\n",__func__);
-
- card = kzalloc(sizeof(struct mmc_card), GFP_KERNEL);
- if (!card) {
- DBG("[%s] e1\n",__func__);
- return ERR_PTR(-ENOMEM);
- }
-
- card->host = host;
-
- device_initialize(&card->dev);
-
- card->dev.parent = mmc_classdev(host);
- card->dev.bus = &mmc_bus_type;
- card->dev.release = mmc_release_card;
- card->dev.type = type;
-
- DBG("[%s] e2\n",__func__);
- return card;
-}
-
-/*
- * Register a new MMC card with the driver model.
- */
-int mmc_add_card(struct mmc_card *card)
-{
- int ret;
- const char *type;
- const char *uhs_bus_speed_mode = "";
- static const char *const uhs_speeds[] = {
- [UHS_SDR12_BUS_SPEED] = "SDR12 ",
- [UHS_SDR25_BUS_SPEED] = "SDR25 ",
- [UHS_SDR50_BUS_SPEED] = "SDR50 ",
- [UHS_SDR104_BUS_SPEED] = "SDR104 ",
- [UHS_DDR50_BUS_SPEED] = "DDR50 ",
- };
- DBG("[%s] s\n",__func__);
-
- dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca);
-
- switch (card->type) {
- case MMC_TYPE_MMC:
- type = "MMC";
- break;
- case MMC_TYPE_SD:
- type = "SD";
- if (mmc_card_blockaddr(card)) {
- if (mmc_card_ext_capacity(card))
- type = "SDXC";
- else
- type = "SDHC";
- }
- break;
- case MMC_TYPE_SDIO:
- type = "SDIO";
- break;
- case MMC_TYPE_SD_COMBO:
- type = "SD-combo";
- if (mmc_card_blockaddr(card))
- type = "SDHC-combo";
- break;
- default:
- type = "?";
- break;
- }
-
- if (mmc_sd_card_uhs(card) &&
- (card->sd_bus_speed < ARRAY_SIZE(uhs_speeds)))
- uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed];
-
- if (mmc_host_is_spi(card->host)) {
- pr_info("%s: new %s%s%s card on SPI\n",
- mmc_hostname(card->host),
- mmc_card_highspeed(card) ? "high speed " : "",
- mmc_card_ddr_mode(card) ? "DDR " : "",
- type);
- } else {
- pr_info("%s: new %s%s%s%s%s card at address %04x\n",
- mmc_hostname(card->host),
- mmc_card_uhs(card) ? "ultra high speed " :
- (mmc_card_highspeed(card) ? "high speed " : ""),
- (mmc_card_hs200(card) ? "HS200 " : ""),
- mmc_card_ddr_mode(card) ? "DDR " : "",
- uhs_bus_speed_mode, type, card->rca);
- }
-
-#ifdef CONFIG_DEBUG_FS
- mmc_add_card_debugfs(card);
-#endif
-
- ret = device_add(&card->dev);
- if (ret) {
- DBG("[%s] e1\n",__func__);
- return ret;
- }
-
- mmc_card_set_present(card);
-
- DBG("[%s] e2\n",__func__);
- return 0;
-}
-
-/*
- * Unregister a new MMC card with the driver model, and
- * (eventually) free it.
- */
-void mmc_remove_card(struct mmc_card *card)
-{
- DBG("[%s] s\n",__func__);
-
-#ifdef CONFIG_DEBUG_FS
- mmc_remove_card_debugfs(card);
-#endif
-
- if (mmc_card_present(card)) {
- if (mmc_host_is_spi(card->host)) {
- pr_info("%s: SPI card removed\n",
- mmc_hostname(card->host));
- } else {
- pr_info("%s: card %04x removed\n",
- mmc_hostname(card->host), card->rca);
- }
- device_del(&card->dev);
- }
-
- put_device(&card->dev);
-
- DBG("[%s] e\n",__func__);
-}
-
diff --git a/ANDROID_3.4.5/drivers/mmc/core/bus.h b/ANDROID_3.4.5/drivers/mmc/core/bus.h
deleted file mode 100644
index 00a19710..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/bus.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * linux/drivers/mmc/core/bus.h
- *
- * Copyright (C) 2003 Russell King, All Rights Reserved.
- * Copyright 2007 Pierre Ossman
- *
- * 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 _MMC_CORE_BUS_H
-#define _MMC_CORE_BUS_H
-
-#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 = mmc_dev_to_card(dev); \
- return sprintf(buf, fmt, args); \
-} \
-static DEVICE_ATTR(name, S_IRUGO, mmc_##name##_show, NULL)
-
-struct mmc_card *mmc_alloc_card(struct mmc_host *host,
- struct device_type *type);
-int mmc_add_card(struct mmc_card *card);
-void mmc_remove_card(struct mmc_card *card);
-
-int mmc_register_bus(void);
-void mmc_unregister_bus(void);
-
-#endif
-
diff --git a/ANDROID_3.4.5/drivers/mmc/core/cd-gpio.c b/ANDROID_3.4.5/drivers/mmc/core/cd-gpio.c
deleted file mode 100644
index f13e38de..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/cd-gpio.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Generic GPIO card-detect helper
- *
- * Copyright (C) 2011, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/err.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/jiffies.h>
-#include <linux/mmc/cd-gpio.h>
-#include <linux/mmc/host.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-struct mmc_cd_gpio {
- unsigned int gpio;
- char label[0];
-};
-
-static irqreturn_t mmc_cd_gpio_irqt(int irq, void *dev_id)
-{
- /* Schedule a card detection after a debounce timeout */
- mmc_detect_change(dev_id, msecs_to_jiffies(100));
- return IRQ_HANDLED;
-}
-
-int mmc_cd_gpio_request(struct mmc_host *host, unsigned int gpio)
-{
- size_t len = strlen(dev_name(host->parent)) + 4;
- struct mmc_cd_gpio *cd;
- int irq = gpio_to_irq(gpio);
- int ret;
-
- if (irq < 0)
- return irq;
-
- cd = kmalloc(sizeof(*cd) + len, GFP_KERNEL);
- if (!cd)
- return -ENOMEM;
-
- snprintf(cd->label, len, "%s cd", dev_name(host->parent));
-
- ret = gpio_request_one(gpio, GPIOF_DIR_IN, cd->label);
- if (ret < 0)
- goto egpioreq;
-
- ret = request_threaded_irq(irq, NULL, mmc_cd_gpio_irqt,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- cd->label, host);
- if (ret < 0)
- goto eirqreq;
-
- cd->gpio = gpio;
- host->hotplug.irq = irq;
- host->hotplug.handler_priv = cd;
-
- return 0;
-
-eirqreq:
- gpio_free(gpio);
-egpioreq:
- kfree(cd);
- return ret;
-}
-EXPORT_SYMBOL(mmc_cd_gpio_request);
-
-void mmc_cd_gpio_free(struct mmc_host *host)
-{
- struct mmc_cd_gpio *cd = host->hotplug.handler_priv;
-
- if (!cd)
- return;
-
- free_irq(host->hotplug.irq, host);
- gpio_free(cd->gpio);
- kfree(cd);
-}
-EXPORT_SYMBOL(mmc_cd_gpio_free);
diff --git a/ANDROID_3.4.5/drivers/mmc/core/core.c b/ANDROID_3.4.5/drivers/mmc/core/core.c
deleted file mode 100644
index 7dc7edd5..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/core.c
+++ /dev/null
@@ -1,2958 +0,0 @@
-/*
- * linux/drivers/mmc/core/core.c
- *
- * Copyright (C) 2003-2004 Russell King, All Rights Reserved.
- * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
- * Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
- * MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/completion.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/pagemap.h>
-#include <linux/err.h>
-#include <linux/leds.h>
-#include <linux/scatterlist.h>
-#include <linux/log2.h>
-#include <linux/regulator/consumer.h>
-#include <linux/pm_runtime.h>
-#include <linux/suspend.h>
-#include <linux/fault-inject.h>
-#include <linux/random.h>
-#include <linux/wakelock.h>
-
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/sd.h>
-
-#include "core.h"
-#include "bus.h"
-#include "host.h"
-#include "sdio_bus.h"
-
-#include "mmc_ops.h"
-#include "sd_ops.h"
-#include "sdio_ops.h"
-#include "../host/mmc_atsmb.h"
-#include <mach/hardware.h>
-
-
-static struct workqueue_struct *workqueue;
-
-#if 0
-#define DBG(x...) printk(KERN_ALERT x)
-#else
-#define DBG(x...) do { } while (0)
-#endif
-
-/*
- * Enabling software CRCs on the data blocks can be a significant (30%)
- * performance cost, and for other reasons may not always be desired.
- * So we allow it it to be disabled.
- */
-bool use_spi_crc = 1;
-module_param(use_spi_crc, bool, 0);
-
-/*
- * We normally treat cards as removed during suspend if they are not
- * known to be on a non-removable bus, to avoid the risk of writing
- * back data to a different card after resume. Allow this to be
- * overridden if necessary.
- */
-#ifdef CONFIG_MMC_UNSAFE_RESUME
-bool mmc_assume_removable;
-#else
-bool mmc_assume_removable = 1;
-#endif
-EXPORT_SYMBOL(mmc_assume_removable);
-module_param_named(removable, mmc_assume_removable, bool, 0644);
-MODULE_PARM_DESC(
- removable,
- "MMC/SD cards are removable and may be removed during suspend");
-
-/*
- * Internal function. Schedule delayed work in the MMC work queue.
- */
-static int mmc_schedule_delayed_work(struct delayed_work *work,
- unsigned long delay)
-{
- int ret;
- DBG("[%s] s\n",__func__);
-
- ret = queue_delayed_work(workqueue, work, delay);
-
- DBG("[%s] e\n",__func__);
- return ret;
- /*return queue_delayed_work(workqueue, work, delay);*/
-}
-
-/*
- * Internal function. Flush all scheduled work from the MMC work queue.
- */
-static void mmc_flush_scheduled_work(void)
-{
- DBG("[%s] s\n",__func__);
-
- flush_workqueue(workqueue);
-
- DBG("[%s] e\n",__func__);
-}
-
-#ifdef CONFIG_FAIL_MMC_REQUEST
-
-/*
- * Internal function. Inject random data errors.
- * If mmc_data is NULL no errors are injected.
- */
-static void mmc_should_fail_request(struct mmc_host *host,
- struct mmc_request *mrq)
-{
- struct mmc_command *cmd = mrq->cmd;
- struct mmc_data *data = mrq->data;
- static const int data_errors[] = {
- -ETIMEDOUT,
- -EILSEQ,
- -EIO,
- };
-
- if (!data)
- return;
-
- if (cmd->error || data->error ||
- !should_fail(&host->fail_mmc_request, data->blksz * data->blocks))
- return;
-
- data->error = data_errors[random32() % ARRAY_SIZE(data_errors)];
- data->bytes_xfered = (random32() % (data->bytes_xfered >> 9)) << 9;
-}
-
-#else /* CONFIG_FAIL_MMC_REQUEST */
-
-static inline void mmc_should_fail_request(struct mmc_host *host,
- struct mmc_request *mrq)
-{
-}
-
-#endif /* CONFIG_FAIL_MMC_REQUEST */
-
-/**
- * mmc_request_done - finish processing an MMC request
- * @host: MMC host which completed request
- * @mrq: MMC request which request
- *
- * MMC drivers should call this function when they have completed
- * their processing of a request.
- */
-void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
-{
- struct mmc_command *cmd = mrq->cmd;
- int err = cmd->error;
- DBG("[%s] s\n",__func__);
-
- if (err && cmd->retries && mmc_host_is_spi(host)) {
- if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
- cmd->retries = 0;
- }
-
- if (err && cmd->retries && !mmc_card_removed(host->card)) {
- /*
- * Request starter must handle retries - see
- * mmc_wait_for_req_done().
- */
- if (mrq->done)
- mrq->done(mrq);
- } else {
- mmc_should_fail_request(host, mrq);
-
- led_trigger_event(host->led, LED_OFF);
-
- pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n",
- mmc_hostname(host), cmd->opcode, err,
- cmd->resp[0], cmd->resp[1],
- cmd->resp[2], cmd->resp[3]);
-
- if (mrq->data) {
- pr_debug("%s: %d bytes transferred: %d\n",
- mmc_hostname(host),
- mrq->data->bytes_xfered, mrq->data->error);
- }
-
- if (mrq->stop) {
- pr_debug("%s: (CMD%u): %d: %08x %08x %08x %08x\n",
- mmc_hostname(host), mrq->stop->opcode,
- mrq->stop->error,
- mrq->stop->resp[0], mrq->stop->resp[1],
- mrq->stop->resp[2], mrq->stop->resp[3]);
- }
-
- if (mrq->done)
- mrq->done(mrq);
-
- mmc_host_clk_release(host);
- }
- DBG("[%s] e\n",__func__);
-}
-
-EXPORT_SYMBOL(mmc_request_done);
-
-static void
-mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
-{
-#ifdef CONFIG_MMC_DEBUG
- unsigned int i, sz;
- struct scatterlist *sg;
-#endif
- DBG("[%s] s\n",__func__);
-
- if (mrq->sbc) {
- pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n",
- mmc_hostname(host), mrq->sbc->opcode,
- mrq->sbc->arg, mrq->sbc->flags);
- }
-
- pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
- mmc_hostname(host), mrq->cmd->opcode,
- mrq->cmd->arg, mrq->cmd->flags);
-
- if (mrq->data) {
- pr_debug("%s: blksz %d blocks %d flags %08x "
- "tsac %d ms nsac %d\n",
- mmc_hostname(host), mrq->data->blksz,
- mrq->data->blocks, mrq->data->flags,
- mrq->data->timeout_ns / 1000000,
- mrq->data->timeout_clks);
- }
-
- if (mrq->stop) {
- pr_debug("%s: CMD%u arg %08x flags %08x\n",
- mmc_hostname(host), mrq->stop->opcode,
- mrq->stop->arg, mrq->stop->flags);
- }
-
- WARN_ON(!host->claimed);
-
- mrq->cmd->error = 0;
- mrq->cmd->mrq = mrq;
- if (mrq->data) {
- BUG_ON(mrq->data->blksz > host->max_blk_size);
- BUG_ON(mrq->data->blocks > host->max_blk_count);
- BUG_ON(mrq->data->blocks * mrq->data->blksz >
- host->max_req_size);
-
-#ifdef CONFIG_MMC_DEBUG
- sz = 0;
- for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i)
- sz += sg->length;
- BUG_ON(sz != mrq->data->blocks * mrq->data->blksz);
-#endif
-
- mrq->cmd->data = mrq->data;
- mrq->data->error = 0;
- mrq->data->mrq = mrq;
- if (mrq->stop) {
- mrq->data->stop = mrq->stop;
- mrq->stop->error = 0;
- mrq->stop->mrq = mrq;
- }
- }
- mmc_host_clk_hold(host);
- led_trigger_event(host->led, LED_FULL);
- host->ops->request(host, mrq);
-
- DBG("[%s] e\n",__func__);
-}
-
-static void mmc_wait_done(struct mmc_request *mrq)
-{
- DBG("[%s] s\n",__func__);
-
- complete(&mrq->completion);
-
- DBG("[%s] e\n",__func__);
-}
-
-static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
-{
- DBG("[%s] s\n",__func__);
- init_completion(&mrq->completion);
- mrq->done = mmc_wait_done;
- if (mmc_card_removed(host->card)) {
- mrq->cmd->error = -ENOMEDIUM;
- complete(&mrq->completion);
- DBG("[%s] e1\n",__func__);
- return -ENOMEDIUM;
- }
- mmc_start_request(host, mrq);
- DBG("[%s] e2\n",__func__);
- return 0;
-}
-
-static void mmc_wait_for_req_done(struct mmc_host *host,
- struct mmc_request *mrq)
-{
- struct mmc_command *cmd;
- DBG("[%s] s\n",__func__);
- while (1) {
- wait_for_completion(&mrq->completion);
-
- cmd = mrq->cmd;
- if (!cmd->error || !cmd->retries ||
- mmc_card_removed(host->card))
- break;
-
- pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
- mmc_hostname(host), cmd->opcode, cmd->error);
- cmd->retries--;
- cmd->error = 0;
- host->ops->request(host, mrq);
- }
- DBG("[%s] e\n",__func__);
-}
-
-/**
- * mmc_pre_req - Prepare for a new request
- * @host: MMC host to prepare command
- * @mrq: MMC request to prepare for
- * @is_first_req: true if there is no previous started request
- * that may run in parellel to this call, otherwise false
- *
- * mmc_pre_req() is called in prior to mmc_start_req() to let
- * host prepare for the new request. Preparation of a request may be
- * performed while another request is running on the host.
- */
-static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
- bool is_first_req)
-{
- DBG("[%s] s\n",__func__);
- if (host->ops->pre_req) {
- mmc_host_clk_hold(host);
- host->ops->pre_req(host, mrq, is_first_req);
- mmc_host_clk_release(host);
- }
- DBG("[%s] e\n",__func__);
-}
-
-/**
- * mmc_post_req - Post process a completed request
- * @host: MMC host to post process command
- * @mrq: MMC request to post process for
- * @err: Error, if non zero, clean up any resources made in pre_req
- *
- * Let the host post process a completed request. Post processing of
- * a request may be performed while another reuqest is running.
- */
-static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
- int err)
-{
- DBG("[%s] s\n",__func__);
- if (host->ops->post_req) {
- mmc_host_clk_hold(host);
- host->ops->post_req(host, mrq, err);
- mmc_host_clk_release(host);
- }
- DBG("[%s] e\n",__func__);
-}
-
-/**
- * mmc_start_req - start a non-blocking request
- * @host: MMC host to start command
- * @areq: async request to start
- * @error: out parameter returns 0 for success, otherwise non zero
- *
- * Start a new MMC custom command request for a host.
- * If there is on ongoing async request wait for completion
- * of that request and start the new one and return.
- * Does not wait for the new request to complete.
- *
- * Returns the completed request, NULL in case of none completed.
- * Wait for the an ongoing request (previoulsy started) to complete and
- * return the completed request. If there is no ongoing request, NULL
- * is returned without waiting. NULL is not an error condition.
- */
-struct mmc_async_req *mmc_start_req(struct mmc_host *host,
- struct mmc_async_req *areq, int *error)
-{
- int err = 0;
- int start_err = 0;
- struct mmc_async_req *data = host->areq;
- DBG("[%s] s\n",__func__);
- /* Prepare a new request */
- if (areq)
- mmc_pre_req(host, areq->mrq, !host->areq);
-
- if (host->areq) {
- mmc_wait_for_req_done(host, host->areq->mrq);
- err = host->areq->err_check(host->card, host->areq);
- }
-
- if (!err && areq)
- start_err = __mmc_start_req(host, areq->mrq);
-
- if (host->areq)
- mmc_post_req(host, host->areq->mrq, 0);
-
- /* Cancel a prepared request if it was not started. */
- if ((err || start_err) && areq)
- mmc_post_req(host, areq->mrq, -EINVAL);
-
- if (err)
- host->areq = NULL;
- else
- host->areq = areq;
-
- if (error)
- *error = err;
- DBG("[%s] e\n",__func__);
- return data;
-}
-EXPORT_SYMBOL(mmc_start_req);
-
-/**
- * mmc_wait_for_req - start a request and wait for completion
- * @host: MMC host to start command
- * @mrq: MMC request to start
- *
- * Start a new MMC custom command request for a host, and wait
- * for the command to complete. Does not attempt to parse the
- * response.
- */
-void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
-{
- DBG("[%s] s\n",__func__);
- __mmc_start_req(host, mrq);
- mmc_wait_for_req_done(host, mrq);
- DBG("[%s] e\n",__func__);
-}
-EXPORT_SYMBOL(mmc_wait_for_req);
-
-/**
- * mmc_interrupt_hpi - Issue for High priority Interrupt
- * @card: the MMC card associated with the HPI transfer
- *
- * Issued High Priority Interrupt, and check for card status
- * util out-of prg-state.
- */
-int mmc_interrupt_hpi(struct mmc_card *card)
-{
- int err;
- u32 status;
- DBG("[%s] s\n",__func__);
- BUG_ON(!card);
-
- if (!card->ext_csd.hpi_en) {
- pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host));
- return 1;
- }
-
- mmc_claim_host(card->host);
- err = mmc_send_status(card, &status);
- if (err) {
- pr_err("%s: Get card status fail\n", mmc_hostname(card->host));
- goto out;
- }
-
- /*
- * If the card status is in PRG-state, we can send the HPI command.
- */
- if (R1_CURRENT_STATE(status) == R1_STATE_PRG) {
- do {
- /*
- * We don't know when the HPI command will finish
- * processing, so we need to resend HPI until out
- * of prg-state, and keep checking the card status
- * with SEND_STATUS. If a timeout error occurs when
- * sending the HPI command, we are already out of
- * prg-state.
- */
- err = mmc_send_hpi_cmd(card, &status);
- if (err)
- pr_debug("%s: abort HPI (%d error)\n",
- mmc_hostname(card->host), err);
-
- err = mmc_send_status(card, &status);
- if (err)
- break;
- } while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
- } else
- pr_debug("%s: Left prg-state\n", mmc_hostname(card->host));
-
-out:
- mmc_release_host(card->host);
- DBG("[%s] e\n",__func__);
- return err;
-}
-EXPORT_SYMBOL(mmc_interrupt_hpi);
-
-/**
- * mmc_wait_for_cmd - start a command and wait for completion
- * @host: MMC host to start command
- * @cmd: MMC command to start
- * @retries: maximum number of retries
- *
- * Start a new MMC command for a host, and wait for the command
- * to complete. Return any error that occurred while the command
- * was executing. Do not attempt to parse the response.
- */
-int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
-{
- struct mmc_request mrq = {NULL};
-
- DBG("[%s] s\n",__func__);
-
- WARN_ON(!host->claimed);
-
- memset(cmd->resp, 0, sizeof(cmd->resp));
- cmd->retries = retries;
-
- mrq.cmd = cmd;
- cmd->data = NULL;
-
- mmc_wait_for_req(host, &mrq);
-
- DBG("[%s] e\n",__func__);
- return cmd->error;
-}
-
-EXPORT_SYMBOL(mmc_wait_for_cmd);
-
-/**
- * mmc_set_data_timeout - set the timeout for a data command
- * @data: data phase for command
- * @card: the MMC card associated with the data transfer
- *
- * Computes the data timeout parameters according to the
- * correct algorithm given the card type.
- */
-void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
-{
- unsigned int mult;
- DBG("[%s] s\n",__func__);
- /*
- * SDIO cards only define an upper 1 s limit on access.
- */
- if (mmc_card_sdio(card)) {
- data->timeout_ns = 1000000000;
- data->timeout_clks = 0;
- DBG("[%s] e1\n",__func__);
- return;
- }
-
- /*
- * SD cards use a 100 multiplier rather than 10
- */
- mult = mmc_card_sd(card) ? 100 : 10;
-
- /*
- * Scale up the multiplier (and therefore the timeout) by
- * the r2w factor for writes.
- */
- if (data->flags & MMC_DATA_WRITE)
- mult <<= card->csd.r2w_factor;
-
- data->timeout_ns = card->csd.tacc_ns * mult;
- data->timeout_clks = card->csd.tacc_clks * mult;
-
- /*
- * SD cards also have an upper limit on the timeout.
- */
- if (mmc_card_sd(card)) {
- unsigned int timeout_us, limit_us;
-
- timeout_us = data->timeout_ns / 1000;
- if (mmc_host_clk_rate(card->host))
- timeout_us += data->timeout_clks * 1000 /
- (mmc_host_clk_rate(card->host) / 1000);
-
- if (data->flags & MMC_DATA_WRITE)
- /*
- * The MMC spec "It is strongly recommended
- * for hosts to implement more than 500ms
- * timeout value even if the card indicates
- * the 250ms maximum busy length." Even the
- * previous value of 300ms is known to be
- * insufficient for some cards.
- */
- limit_us = 3000000;
- else
- limit_us = 100000;
-
- /*
- * SDHC cards always use these fixed values.
- */
- if (timeout_us > limit_us || mmc_card_blockaddr(card)) {
- data->timeout_ns = limit_us * 1000;
- data->timeout_clks = 0;
- }
- }
-
- /*
- * Some cards require longer data read timeout than indicated in CSD.
- * Address this by setting the read timeout to a "reasonably high"
- * value. For the cards tested, 300ms has proven enough. If necessary,
- * this value can be increased if other problematic cards require this.
- */
- if (mmc_card_long_read_time(card) && data->flags & MMC_DATA_READ) {
- data->timeout_ns = 300000000;
- data->timeout_clks = 0;
- }
-
- /*
- * Some cards need very high timeouts if driven in SPI mode.
- * The worst observed timeout was 900ms after writing a
- * continuous stream of data until the internal logic
- * overflowed.
- */
- if (mmc_host_is_spi(card->host)) {
- if (data->flags & MMC_DATA_WRITE) {
- if (data->timeout_ns < 1000000000)
- data->timeout_ns = 1000000000; /* 1s */
- } else {
- if (data->timeout_ns < 100000000)
- data->timeout_ns = 100000000; /* 100ms */
- }
- }
-
- DBG("[%s] e2\n",__func__);
-}
-EXPORT_SYMBOL(mmc_set_data_timeout);
-
-/**
- * mmc_align_data_size - pads a transfer size to a more optimal value
- * @card: the MMC card associated with the data transfer
- * @sz: original transfer size
- *
- * Pads the original data size with a number of extra bytes in
- * order to avoid controller bugs and/or performance hits
- * (e.g. some controllers revert to PIO for certain sizes).
- *
- * Returns the improved size, which might be unmodified.
- *
- * Note that this function is only relevant when issuing a
- * single scatter gather entry.
- */
-unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz)
-{
- /*
- * FIXME: We don't have a system for the controller to tell
- * the core about its problems yet, so for now we just 32-bit
- * align the size.
- */
- sz = ((sz + 3) / 4) * 4;
-
- return sz;
-}
-EXPORT_SYMBOL(mmc_align_data_size);
-
-/**
- * __mmc_claim_host - exclusively claim a host
- * @host: mmc host to claim
- * @abort: whether or not the operation should be aborted
- *
- * Claim a host for a set of operations. If @abort is non null and
- * dereference a non-zero value then this will return prematurely with
- * that non-zero value without acquiring the lock. Returns zero
- * with the lock held otherwise.
- */
-int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int stop;
-
- DBG("[%s] s\n",__func__);
-
- might_sleep();
-
- add_wait_queue(&host->wq, &wait);
- spin_lock_irqsave(&host->lock, flags);
- while (1) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- stop = abort ? atomic_read(abort) : 0;
- if (stop || !host->claimed || host->claimer == current)
- break;
- spin_unlock_irqrestore(&host->lock, flags);
- schedule();
- spin_lock_irqsave(&host->lock, flags);
- }
- set_current_state(TASK_RUNNING);
- if (!stop) {
- host->claimed = 1;
- host->claimer = current;
- host->claim_cnt += 1;
- } else
- wake_up(&host->wq);
- spin_unlock_irqrestore(&host->lock, flags);
- remove_wait_queue(&host->wq, &wait);
- if (host->ops->enable && !stop && host->claim_cnt == 1)
- host->ops->enable(host);
-
- DBG("[%s] e\n",__func__);
- return stop;
-}
-
-EXPORT_SYMBOL(__mmc_claim_host);
-
-/**
- * mmc_try_claim_host - try exclusively to claim a host
- * @host: mmc host to claim
- *
- * Returns %1 if the host is claimed, %0 otherwise.
- */
-int mmc_try_claim_host(struct mmc_host *host)
-{
- int claimed_host = 0;
- unsigned long flags;
- DBG("[%s] s\n",__func__);
-
- spin_lock_irqsave(&host->lock, flags);
- if (!host->claimed || host->claimer == current) {
- host->claimed = 1;
- host->claimer = current;
- host->claim_cnt += 1;
- claimed_host = 1;
- }
- spin_unlock_irqrestore(&host->lock, flags);
- if (host->ops->enable && claimed_host && host->claim_cnt == 1)
- host->ops->enable(host);
-
- DBG("[%s] e\n",__func__);
- return claimed_host;
-}
-EXPORT_SYMBOL(mmc_try_claim_host);
-
-/**
- * mmc_release_host - release a host
- * @host: mmc host to release
- *
- * Release a MMC host, allowing others to claim the host
- * for their operations.
- */
-void mmc_release_host(struct mmc_host *host)
-{
- unsigned long flags;
- DBG("[%s] s\n",__func__);
-
- WARN_ON(!host->claimed);
-
- if (host->ops->disable && host->claim_cnt == 1)
- host->ops->disable(host);
-
- spin_lock_irqsave(&host->lock, flags);
- if (--host->claim_cnt) {
- /* Release for nested claim */
- spin_unlock_irqrestore(&host->lock, flags);
- } else {
- host->claimed = 0;
- host->claimer = NULL;
- spin_unlock_irqrestore(&host->lock, flags);
- wake_up(&host->wq);
- }
- DBG("[%s] e\n",__func__);
-}
-EXPORT_SYMBOL(mmc_release_host);
-
-/*
- * Internal function that does the actual ios call to the host driver,
- * optionally printing some debug output.
- */
-static inline void mmc_set_ios(struct mmc_host *host)
-{
- struct mmc_ios *ios = &host->ios;
-
- DBG("[%s] s\n",__func__);
-
- pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u "
- "width %u timing %u\n",
- mmc_hostname(host), ios->clock, ios->bus_mode,
- ios->power_mode, ios->chip_select, ios->vdd,
- ios->bus_width, ios->timing);
-
- if (ios->clock > 0)
- mmc_set_ungated(host);
- host->ops->set_ios(host, ios);
-
- DBG("[%s] e\n",__func__);
-}
-
-/*
- * Control chip select pin on a host.
- */
-void mmc_set_chip_select(struct mmc_host *host, int mode)
-{
- DBG("[%s] s\n",__func__);
-
- mmc_host_clk_hold(host);
- host->ios.chip_select = mode;
- mmc_set_ios(host);
- mmc_host_clk_release(host);
-
- DBG("[%s] e\n",__func__);
-}
-
-/*
- * Sets the host clock to the highest possible frequency that
- * is below "hz".
- */
-static void __mmc_set_clock(struct mmc_host *host, unsigned int hz)
-{
- DBG("[%s] s\n",__func__);
-
- WARN_ON(hz < host->f_min);
-
- if (hz > host->f_max)
- hz = host->f_max;
-
- host->ios.clock = hz;
- mmc_set_ios(host);
-
- DBG("[%s] e\n",__func__);
-}
-
-void mmc_set_clock(struct mmc_host *host, unsigned int hz)
-{
- DBG("[%s] s\n",__func__);
- mmc_host_clk_hold(host);
- __mmc_set_clock(host, hz);
- mmc_host_clk_release(host);
-
- DBG("[%s] e\n",__func__);
-}
-
-#ifdef CONFIG_MMC_CLKGATE
-/*
- * This gates the clock by setting it to 0 Hz.
- */
-void mmc_gate_clock(struct mmc_host *host)
-{
- unsigned long flags;
- DBG("[%s] s\n",__func__);
-
- spin_lock_irqsave(&host->clk_lock, flags);
- host->clk_old = host->ios.clock;
- host->ios.clock = 0;
- host->clk_gated = true;
- spin_unlock_irqrestore(&host->clk_lock, flags);
- mmc_set_ios(host);
-
- DBG("[%s] e\n",__func__);
-}
-
-/*
- * This restores the clock from gating by using the cached
- * clock value.
- */
-void mmc_ungate_clock(struct mmc_host *host)
-{
- DBG("[%s] s\n",__func__);
- /*
- * We should previously have gated the clock, so the clock shall
- * be 0 here! The clock may however be 0 during initialization,
- * when some request operations are performed before setting
- * the frequency. When ungate is requested in that situation
- * we just ignore the call.
- */
- if (host->clk_old) {
- BUG_ON(host->ios.clock);
- /* This call will also set host->clk_gated to false */
- __mmc_set_clock(host, host->clk_old);
- }
-
- DBG("[%s] e\n",__func__);
-}
-
-void mmc_set_ungated(struct mmc_host *host)
-{
- unsigned long flags;
- DBG("[%s] s\n",__func__);
- /*
- * We've been given a new frequency while the clock is gated,
- * so make sure we regard this as ungating it.
- */
- spin_lock_irqsave(&host->clk_lock, flags);
- host->clk_gated = false;
- spin_unlock_irqrestore(&host->clk_lock, flags);
-
- DBG("[%s] e\n",__func__);
-}
-
-#else
-void mmc_set_ungated(struct mmc_host *host)
-{
-}
-#endif
-
-/*
- * Change the bus mode (open drain/push-pull) of a host.
- */
-void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
-{
- DBG("[%s] s\n",__func__);
-
- mmc_host_clk_hold(host);
- host->ios.bus_mode = mode;
- mmc_set_ios(host);
- mmc_host_clk_release(host);
-
- DBG("[%s] e\n",__func__);
-}
-
-/*
- * Change data bus width of a host.
- */
-void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
-{
- DBG("[%s] s\n",__func__);
-
- mmc_host_clk_hold(host);
- host->ios.bus_width = width;
- mmc_set_ios(host);
- mmc_host_clk_release(host);
-
- DBG("[%s] e\n",__func__);
-}
-
-/**
- * mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number
- * @vdd: voltage (mV)
- * @low_bits: prefer low bits in boundary cases
- *
- * This function returns the OCR bit number according to the provided @vdd
- * value. If conversion is not possible a negative errno value returned.
- *
- * Depending on the @low_bits flag the function prefers low or high OCR bits
- * on boundary voltages. For example,
- * with @low_bits = true, 3300 mV translates to ilog2(MMC_VDD_32_33);
- * with @low_bits = false, 3300 mV translates to ilog2(MMC_VDD_33_34);
- *
- * Any value in the [1951:1999] range translates to the ilog2(MMC_VDD_20_21).
- */
-static int mmc_vdd_to_ocrbitnum(int vdd, bool low_bits)
-{
- const int max_bit = ilog2(MMC_VDD_35_36);
- int bit;
-
- DBG("[%s] s\n",__func__);
-
- if (vdd < 1650 || vdd > 3600) {
- DBG("[%s] e1\n",__func__);
- return -EINVAL;
- }
-
- if (vdd >= 1650 && vdd <= 1950) {
- DBG("[%s] e2\n",__func__);
- return ilog2(MMC_VDD_165_195);
- }
-
- if (low_bits)
- vdd -= 1;
-
- /* Base 2000 mV, step 100 mV, bit's base 8. */
- bit = (vdd - 2000) / 100 + 8;
- if (bit > max_bit) {
- DBG("[%s] e3\n",__func__);
- return max_bit;
- }
- DBG("[%s] e4\n",__func__);
- return bit;
-}
-
-/**
- * mmc_vddrange_to_ocrmask - Convert a voltage range to the OCR mask
- * @vdd_min: minimum voltage value (mV)
- * @vdd_max: maximum voltage value (mV)
- *
- * This function returns the OCR mask bits according to the provided @vdd_min
- * and @vdd_max values. If conversion is not possible the function returns 0.
- *
- * Notes wrt boundary cases:
- * This function sets the OCR bits for all boundary voltages, for example
- * [3300:3400] range is translated to MMC_VDD_32_33 | MMC_VDD_33_34 |
- * MMC_VDD_34_35 mask.
- */
-u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max)
-{
- u32 mask = 0;
-
- DBG("[%s] s\n",__func__);
-
- if (vdd_max < vdd_min) {
- DBG("[%s] e1\n",__func__);
- return 0;
- }
-
- /* Prefer high bits for the boundary vdd_max values. */
- vdd_max = mmc_vdd_to_ocrbitnum(vdd_max, false);
- if (vdd_max < 0) {
- DBG("[%s] e2\n",__func__);
- return 0;
- }
-
- /* Prefer low bits for the boundary vdd_min values. */
- vdd_min = mmc_vdd_to_ocrbitnum(vdd_min, true);
- if (vdd_min < 0) {
- DBG("[%s] e3\n",__func__);
- return 0;
- }
-
- /* Fill the mask, from max bit to min bit. */
- while (vdd_max >= vdd_min)
- mask |= 1 << vdd_max--;
-
- DBG("[%s] e4\n",__func__);
- return mask;
-}
-EXPORT_SYMBOL(mmc_vddrange_to_ocrmask);
-
-#ifdef CONFIG_REGULATOR
-
-/**
- * mmc_regulator_get_ocrmask - return mask of supported voltages
- * @supply: regulator to use
- *
- * This returns either a negative errno, or a mask of voltages that
- * can be provided to MMC/SD/SDIO devices using the specified voltage
- * regulator. This would normally be called before registering the
- * MMC host adapter.
- */
-int mmc_regulator_get_ocrmask(struct regulator *supply)
-{
- int result = 0;
- int count;
- int i;
-
- DBG("[%s] s\n",__func__);
-
- count = regulator_count_voltages(supply);
- if (count < 0) {
- DBG("[%s] e1\n",__func__);
- return count;
- }
-
- for (i = 0; i < count; i++) {
- int vdd_uV;
- int vdd_mV;
-
- vdd_uV = regulator_list_voltage(supply, i);
- if (vdd_uV <= 0)
- continue;
-
- vdd_mV = vdd_uV / 1000;
- result |= mmc_vddrange_to_ocrmask(vdd_mV, vdd_mV);
- }
-
- DBG("[%s] e2\n",__func__);
- return result;
-}
-EXPORT_SYMBOL(mmc_regulator_get_ocrmask);
-
-/**
- * mmc_regulator_set_ocr - set regulator to match host->ios voltage
- * @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.
- *
- * MMC host drivers may use this to enable or disable a regulator using
- * a particular supply voltage. This would normally be called from the
- * set_ios() method.
- */
-int mmc_regulator_set_ocr(struct mmc_host *mmc,
- struct regulator *supply,
- unsigned short vdd_bit)
-{
- int result = 0;
- int min_uV, max_uV;
-
- DBG("[%s] s\n",__func__);
-
- if (vdd_bit) {
- int tmp;
- int voltage;
-
- /* REVISIT mmc_vddrange_to_ocrmask() may have set some
- * bits this regulator doesn't quite support ... don't
- * be too picky, most cards and regulators are OK with
- * a 0.1V range goof (it's a small error percentage).
- */
- tmp = vdd_bit - ilog2(MMC_VDD_165_195);
- if (tmp == 0) {
- min_uV = 1650 * 1000;
- max_uV = 1950 * 1000;
- } else {
- min_uV = 1900 * 1000 + tmp * 100 * 1000;
- max_uV = min_uV + 100 * 1000;
- }
-
- /* avoid needless changes to this voltage; the regulator
- * might not allow this operation
- */
- voltage = regulator_get_voltage(supply);
-
- if (mmc->caps2 & MMC_CAP2_BROKEN_VOLTAGE)
- min_uV = max_uV = voltage;
-
- if (voltage < 0)
- result = voltage;
- else if (voltage < min_uV || voltage > max_uV)
- result = regulator_set_voltage(supply, min_uV, max_uV);
- else
- result = 0;
-
- if (result == 0 && !mmc->regulator_enabled) {
- result = regulator_enable(supply);
- 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);
-
- DBG("[%s] e\n",__func__);
- return result;
-}
-EXPORT_SYMBOL(mmc_regulator_set_ocr);
-
-#endif /* CONFIG_REGULATOR */
-
-/*
- * Mask off any voltages we don't support and select
- * the lowest voltage
- */
-u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
-{
- int bit;
-
- DBG("[%s] s\n",__func__);
-
- ocr &= host->ocr_avail;
-
- bit = ffs(ocr);
- if (bit) {
- bit -= 1;
-
- ocr &= 3 << bit;
-
- mmc_host_clk_hold(host);
- host->ios.vdd = bit;
- mmc_set_ios(host);
- mmc_host_clk_release(host);
- } else {
- pr_warning("%s: host doesn't support card's voltages\n",
- mmc_hostname(host));
- ocr = 0;
- }
-
- DBG("[%s] e\n",__func__);
- return ocr;
-}
-
-int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11)
-{
- struct mmc_command cmd = {0};
- int err = 0;
-
- DBG("[%s] s\n",__func__);
-
- BUG_ON(!host);
-
- /*
- * Send CMD11 only if the request is to switch the card to
- * 1.8V signalling.
- */
- if ((signal_voltage != MMC_SIGNAL_VOLTAGE_330) && cmd11) {
- cmd.opcode = SD_SWITCH_VOLTAGE;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err) {
- DBG("[%s] e1\n",__func__);
- return err;
- }
-
- if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) {
- DBG("[%s] e2\n",__func__);
- return -EIO;
- }
- }
-
- host->ios.signal_voltage = signal_voltage;
-
- if (host->ops->start_signal_voltage_switch) {
- mmc_host_clk_hold(host);
- err = host->ops->start_signal_voltage_switch(host, &host->ios);
- mmc_host_clk_release(host);
- }
- DBG("[%s] e3\n",__func__);
- return err;
-}
-
-/*
- * Select timing parameters for host.
- */
-void mmc_set_timing(struct mmc_host *host, unsigned int timing)
-{
- DBG("[%s] s\n",__func__);
-
- mmc_host_clk_hold(host);
- host->ios.timing = timing;
- mmc_set_ios(host);
- mmc_host_clk_release(host);
-
- DBG("[%s] e\n",__func__);
-}
-
-/*
- * Select appropriate driver type for host.
- */
-void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
-{
- DBG("[%s] s\n",__func__);
-
- mmc_host_clk_hold(host);
- host->ios.drv_type = drv_type;
- mmc_set_ios(host);
- mmc_host_clk_release(host);
-
- DBG("[%s] e\n",__func__);
-}
-
-static void mmc_poweroff_notify(struct mmc_host *host)
-{
- struct mmc_card *card;
- unsigned int timeout;
- unsigned int notify_type = EXT_CSD_NO_POWER_NOTIFICATION;
- int err = 0;
-
- DBG("[%s] s\n",__func__);
-
- card = host->card;
- mmc_claim_host(host);
-
- /*
- * Send power notify command only if card
- * is mmc and notify state is powered ON
- */
- if (card && mmc_card_mmc(card) &&
- (card->poweroff_notify_state == MMC_POWERED_ON)) {
-
- if (host->power_notify_type == MMC_HOST_PW_NOTIFY_SHORT) {
- notify_type = EXT_CSD_POWER_OFF_SHORT;
- timeout = card->ext_csd.generic_cmd6_time;
- card->poweroff_notify_state = MMC_POWEROFF_SHORT;
- } else {
- notify_type = EXT_CSD_POWER_OFF_LONG;
- timeout = card->ext_csd.power_off_longtime;
- card->poweroff_notify_state = MMC_POWEROFF_LONG;
- }
-
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_POWER_OFF_NOTIFICATION,
- notify_type, timeout);
-
- if (err && err != -EBADMSG)
- pr_err("Device failed to respond within %d poweroff "
- "time. Forcefully powering down the device\n",
- timeout);
-
- /* Set the card state to no notification after the poweroff */
- card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION;
- }
- mmc_release_host(host);
-
- DBG("[%s] e\n",__func__);
-}
-
-/*
- * Apply power to the MMC stack. This is a two-stage process.
- * First, we enable power to the card without the clock running.
- * We then wait a bit for the power to stabilise. Finally,
- * enable the bus drivers and clock to the card.
- *
- * We must _NOT_ enable the clock prior to power stablising.
- *
- * If a host does all the power sequencing itself, ignore the
- * initial MMC_POWER_UP stage.
- */
-static void mmc_power_up(struct mmc_host *host)
-{
- int bit;
-
- DBG("[%s] s\n",__func__);
-
- mmc_host_clk_hold(host);
-
- /* If ocr is set, we use it */
- if (host->ocr)
- bit = ffs(host->ocr) - 1;
- else
- bit = fls(host->ocr_avail) - 1;
-
- host->ios.vdd = bit;
- if (mmc_host_is_spi(host))
- host->ios.chip_select = MMC_CS_HIGH;
- else
- host->ios.chip_select = MMC_CS_DONTCARE;
- host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
- host->ios.power_mode = MMC_POWER_UP;
- host->ios.bus_width = MMC_BUS_WIDTH_1;
- host->ios.timing = MMC_TIMING_LEGACY;
- mmc_set_ios(host);
-
- /*
- * This delay should be sufficient to allow the power supply
- * to reach the minimum voltage.
- */
- mmc_delay(10);
-
- host->ios.clock = host->f_init;
-
- host->ios.power_mode = MMC_POWER_ON;
- mmc_set_ios(host);
-
- /*
- * This delay must be at least 74 clock sizes, or 1 ms, or the
- * time required to reach a stable voltage.
- */
- mmc_delay(10);
-
- mmc_host_clk_release(host);
-
- DBG("[%s] e\n",__func__);
-}
-
-void mmc_power_off(struct mmc_host *host)
-{
- int err = 0;
- DBG("[%s] s\n",__func__);
- mmc_host_clk_hold(host);
-
- host->ios.clock = 0;
- host->ios.vdd = 0;
-
- /*
- * For eMMC 4.5 device send AWAKE command before
- * POWER_OFF_NOTIFY command, because in sleep state
- * eMMC 4.5 devices respond to only RESET and AWAKE cmd
- */
- if (host->card && mmc_card_is_sleep(host->card) &&
- host->bus_ops->resume) {
- err = host->bus_ops->resume(host);
-
- if (!err)
- mmc_poweroff_notify(host);
- else
- pr_warning("%s: error %d during resume "
- "(continue with poweroff sequence)\n",
- mmc_hostname(host), err);
- }
-
- /*
- * Reset ocr mask to be the highest possible voltage supported for
- * this mmc host. This value will be used at next power up.
- */
- host->ocr = 1 << (fls(host->ocr_avail) - 1);
-
- if (!mmc_host_is_spi(host)) {
- host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
- host->ios.chip_select = MMC_CS_DONTCARE;
- }
- host->ios.power_mode = MMC_POWER_OFF;
- host->ios.bus_width = MMC_BUS_WIDTH_1;
- host->ios.timing = MMC_TIMING_LEGACY;
- mmc_set_ios(host);
-
- /*
- * Some configurations, such as the 802.11 SDIO card in the OLPC
- * XO-1.5, require a short delay after poweroff before the card
- * can be successfully turned on again.
- */
- mmc_delay(1);
-
- mmc_host_clk_release(host);
-
- DBG("[%s] e\n",__func__);
-}
-
-/*
- * Cleanup when the last reference to the bus operator is dropped.
- */
-static void __mmc_release_bus(struct mmc_host *host)
-{
- DBG("[%s] s\n",__func__);
- BUG_ON(!host);
- BUG_ON(host->bus_refs);
- BUG_ON(!host->bus_dead);
-
- host->bus_ops = NULL;
-
- DBG("[%s] e\n",__func__);
-}
-
-/*
- * Increase reference count of bus operator
- */
-static inline void mmc_bus_get(struct mmc_host *host)
-{
- unsigned long flags;
- DBG("[%s] s\n",__func__);
-
- spin_lock_irqsave(&host->lock, flags);
- host->bus_refs++;
- spin_unlock_irqrestore(&host->lock, flags);
-
- DBG("[%s] e\n",__func__);
-}
-
-/*
- * Decrease reference count of bus operator and free it if
- * it is the last reference.
- */
-static inline void mmc_bus_put(struct mmc_host *host)
-{
- unsigned long flags;
- DBG("[%s] s\n",__func__);
-
- spin_lock_irqsave(&host->lock, flags);
- host->bus_refs--;
- if ((host->bus_refs == 0) && host->bus_ops)
- __mmc_release_bus(host);
- spin_unlock_irqrestore(&host->lock, flags);
-
- DBG("[%s] e\n",__func__);
-}
-
-int mmc_resume_bus(struct mmc_host *host)
-{
- unsigned long flags;
- DBG("[%s] s\n",__func__);
-
- if (!mmc_bus_needs_resume(host)) {
- DBG("[%s] e1\n",__func__);
- return -EINVAL;
- }
-
- printk("%s: Starting deferred resume\n", mmc_hostname(host));
- spin_lock_irqsave(&host->lock, flags);
- host->bus_resume_flags &= ~MMC_BUSRESUME_NEEDS_RESUME;
- host->rescan_disable = 0;
- spin_unlock_irqrestore(&host->lock, flags);
-
- mmc_bus_get(host);
- if (host->bus_ops && !host->bus_dead) {
- mmc_power_up(host);
- BUG_ON(!host->bus_ops->resume);
- host->bus_ops->resume(host);
- }
-
- if (host->bus_ops->detect && !host->bus_dead)
- host->bus_ops->detect(host);
-
- mmc_bus_put(host);
- printk("%s: Deferred resume completed\n", mmc_hostname(host));
- DBG("[%s] e2\n",__func__);
- return 0;
-}
-
-EXPORT_SYMBOL(mmc_resume_bus);
-
-/*
- * Assign a mmc bus handler to a host. Only one bus handler may control a
- * host at any given time.
- */
-void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
-{
- unsigned long flags;
-
- DBG("[%s] s\n",__func__);
-
- BUG_ON(!host);
- BUG_ON(!ops);
-
- WARN_ON(!host->claimed);
-
- spin_lock_irqsave(&host->lock, flags);
-
- BUG_ON(host->bus_ops);
- BUG_ON(host->bus_refs);
-
- host->bus_ops = ops;
- host->bus_refs = 1;
- host->bus_dead = 0;
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- DBG("[%s] e\n",__func__);
-}
-
-/*
- * Remove the current bus handler from a host.
- */
-void mmc_detach_bus(struct mmc_host *host)
-{
- unsigned long flags;
-
- DBG("[%s] s\n",__func__);
-
- BUG_ON(!host);
-
- WARN_ON(!host->claimed);
- WARN_ON(!host->bus_ops);
-
- spin_lock_irqsave(&host->lock, flags);
-
- host->bus_dead = 1;
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- mmc_bus_put(host);
-
- DBG("[%s] e\n",__func__);
-}
-
-/**
- * mmc_detect_change - process change of state on a MMC socket
- * @host: host which changed state.
- * @delay: optional delay to wait before detection (jiffies)
- *
- * MMC drivers should call this when they detect a card has been
- * inserted or removed. The MMC layer will confirm that any
- * present card is still functional, and initialize any newly
- * inserted.
- */
-void mmc_detect_change(struct mmc_host *host, unsigned long delay)
-{
- DBG("[%s] s\n",__func__);
-
-#ifdef CONFIG_MMC_DEBUG
- unsigned long flags;
- spin_lock_irqsave(&host->lock, flags);
- WARN_ON(host->removed);
- spin_unlock_irqrestore(&host->lock, flags);
-#endif
- host->detect_change = 1;
-
- wake_lock(&host->detect_wake_lock);
- mmc_schedule_delayed_work(&host->detect, delay);
-
- DBG("[%s] e\n",__func__);
-}
-
-EXPORT_SYMBOL(mmc_detect_change);
-
-void mmc_init_erase(struct mmc_card *card)
-{
- unsigned int sz;
-
- DBG("[%s] s\n",__func__);
-
- if (is_power_of_2(card->erase_size))
- card->erase_shift = ffs(card->erase_size) - 1;
- else
- card->erase_shift = 0;
-
- /*
- * It is possible to erase an arbitrarily large area of an SD or MMC
- * card. That is not desirable because it can take a long time
- * (minutes) potentially delaying more important I/O, and also the
- * timeout calculations become increasingly hugely over-estimated.
- * Consequently, 'pref_erase' is defined as a guide to limit erases
- * to that size and alignment.
- *
- * For SD cards that define Allocation Unit size, limit erases to one
- * Allocation Unit at a time. For MMC cards that define High Capacity
- * Erase Size, whether it is switched on or not, limit to that size.
- * Otherwise just have a stab at a good value. For modern cards it
- * will end up being 4MiB. Note that if the value is too small, it
- * can end up taking longer to erase.
- */
- if (mmc_card_sd(card) && card->ssr.au) {
- card->pref_erase = card->ssr.au;
- card->erase_shift = ffs(card->ssr.au) - 1;
- } else if (card->ext_csd.hc_erase_size) {
- card->pref_erase = card->ext_csd.hc_erase_size;
- } else {
- sz = (card->csd.capacity << (card->csd.read_blkbits - 9)) >> 11;
- if (sz < 128)
- card->pref_erase = 512 * 1024 / 512;
- else if (sz < 512)
- card->pref_erase = 1024 * 1024 / 512;
- else if (sz < 1024)
- card->pref_erase = 2 * 1024 * 1024 / 512;
- else
- card->pref_erase = 4 * 1024 * 1024 / 512;
- if (card->pref_erase < card->erase_size)
- card->pref_erase = card->erase_size;
- else {
- sz = card->pref_erase % card->erase_size;
- if (sz)
- card->pref_erase += card->erase_size - sz;
- }
- }
-
- DBG("[%s] e\n",__func__);
-}
-
-static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
- unsigned int arg, unsigned int qty)
-{
- unsigned int erase_timeout;
-
- DBG("[%s] s\n",__func__);
-
- if (arg == MMC_DISCARD_ARG ||
- (arg == MMC_TRIM_ARG && card->ext_csd.rev >= 6)) {
- erase_timeout = card->ext_csd.trim_timeout;
- } else if (card->ext_csd.erase_group_def & 1) {
- /* High Capacity Erase Group Size uses HC timeouts */
- if (arg == MMC_TRIM_ARG)
- erase_timeout = card->ext_csd.trim_timeout;
- else
- erase_timeout = card->ext_csd.hc_erase_timeout;
- } else {
- /* CSD Erase Group Size uses write timeout */
- unsigned int mult = (10 << card->csd.r2w_factor);
- unsigned int timeout_clks = card->csd.tacc_clks * mult;
- unsigned int timeout_us;
-
- /* Avoid overflow: e.g. tacc_ns=80000000 mult=1280 */
- if (card->csd.tacc_ns < 1000000)
- timeout_us = (card->csd.tacc_ns * mult) / 1000;
- else
- timeout_us = (card->csd.tacc_ns / 1000) * mult;
-
- /*
- * ios.clock is only a target. The real clock rate might be
- * less but not that much less, so fudge it by multiplying by 2.
- */
- timeout_clks <<= 1;
- timeout_us += (timeout_clks * 1000) /
- (mmc_host_clk_rate(card->host) / 1000);
-
- erase_timeout = timeout_us / 1000;
-
- /*
- * Theoretically, the calculation could underflow so round up
- * to 1ms in that case.
- */
- if (!erase_timeout)
- erase_timeout = 1;
- }
-
- /* Multiplier for secure operations */
- if (arg & MMC_SECURE_ARGS) {
- if (arg == MMC_SECURE_ERASE_ARG)
- erase_timeout *= card->ext_csd.sec_erase_mult;
- else
- erase_timeout *= card->ext_csd.sec_trim_mult;
- }
-
- erase_timeout *= qty;
-
- /*
- * Ensure at least a 1 second timeout for SPI as per
- * 'mmc_set_data_timeout()'
- */
- if (mmc_host_is_spi(card->host) && erase_timeout < 1000)
- erase_timeout = 1000;
-
- DBG("[%s] e\n",__func__);
- return erase_timeout;
-}
-
-static unsigned int mmc_sd_erase_timeout(struct mmc_card *card,
- unsigned int arg,
- unsigned int qty)
-{
- unsigned int erase_timeout;
-
- DBG("[%s] s\n",__func__);
-
- if (card->ssr.erase_timeout) {
- /* Erase timeout specified in SD Status Register (SSR) */
- erase_timeout = card->ssr.erase_timeout * qty +
- card->ssr.erase_offset;
- } else {
- /*
- * Erase timeout not specified in SD Status Register (SSR) so
- * use 250ms per write block.
- */
- erase_timeout = 250 * qty;
- }
-
- /* Must not be less than 1 second */
- if (erase_timeout < 1000)
- erase_timeout = 1000;
-
- DBG("[%s] e\n",__func__);
- return erase_timeout;
-}
-
-static unsigned int mmc_erase_timeout(struct mmc_card *card,
- unsigned int arg,
- unsigned int qty)
-{
- unsigned int ret;
-
- DBG("[%s] s\n",__func__);
-
- if (mmc_card_sd(card)) {
- ret = mmc_sd_erase_timeout(card, arg, qty);
- /*return mmc_sd_erase_timeout(card, arg, qty);*/
- DBG("[%s] e1\n",__func__);
- return ret;
- } else {
- ret = mmc_mmc_erase_timeout(card, arg, qty);
- /*return mmc_mmc_erase_timeout(card, arg, qty);*/
- DBG("[%s] e2\n",__func__);
- return ret;
- }
-
-}
-
-static int mmc_do_erase(struct mmc_card *card, unsigned int from,
- unsigned int to, unsigned int arg)
-{
- struct mmc_command cmd = {0};
- unsigned int qty = 0;
- int err;
-
- DBG("[%s] s\n",__func__);
- /*
- * qty is used to calculate the erase timeout which depends on how many
- * erase groups (or allocation units in SD terminology) are affected.
- * We count erasing part of an erase group as one erase group.
- * For SD, the allocation units are always a power of 2. For MMC, the
- * erase group size is almost certainly also power of 2, but it does not
- * seem to insist on that in the JEDEC standard, so we fall back to
- * division in that case. SD may not specify an allocation unit size,
- * in which case the timeout is based on the number of write blocks.
- *
- * Note that the timeout for secure trim 2 will only be correct if the
- * number of erase groups specified is the same as the total of all
- * preceding secure trim 1 commands. Since the power may have been
- * lost since the secure trim 1 commands occurred, it is generally
- * impossible to calculate the secure trim 2 timeout correctly.
- */
- if (card->erase_shift)
- qty += ((to >> card->erase_shift) -
- (from >> card->erase_shift)) + 1;
- else if (mmc_card_sd(card))
- qty += to - from + 1;
- else
- qty += ((to / card->erase_size) -
- (from / card->erase_size)) + 1;
-
- if (!mmc_card_blockaddr(card)) {
- from <<= 9;
- to <<= 9;
- }
-
- if (mmc_card_sd(card))
- cmd.opcode = SD_ERASE_WR_BLK_START;
- else
- cmd.opcode = MMC_ERASE_GROUP_START;
- cmd.arg = from;
- //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
- if (err) {
- pr_err("mmc_erase: group start error %d, "
- "status %#x\n", err, cmd.resp[0]);
- err = -EIO;
- goto out;
- }
-
- memset(&cmd, 0, sizeof(struct mmc_command));
- if (mmc_card_sd(card))
- cmd.opcode = SD_ERASE_WR_BLK_END;
- else
- cmd.opcode = MMC_ERASE_GROUP_END;
- cmd.arg = to;
- //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
- if (err) {
- pr_err("mmc_erase: group end error %d, status %#x\n",
- err, cmd.resp[0]);
- err = -EIO;
- goto out;
- }
-
- memset(&cmd, 0, sizeof(struct mmc_command));
- cmd.opcode = MMC_ERASE;
- cmd.arg = arg;
- //cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
- cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
- cmd.cmd_timeout_ms = mmc_erase_timeout(card, arg, qty);
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
- if (err) {
- pr_err("mmc_erase: erase error %d, status %#x\n",
- err, cmd.resp[0]);
- err = -EIO;
- goto out;
- }
-
- if (mmc_host_is_spi(card->host))
- goto out;
-
- do {
- memset(&cmd, 0, sizeof(struct mmc_command));
- cmd.opcode = MMC_SEND_STATUS;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- /* Do not retry else we can't see errors */
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
- if (err || (cmd.resp[0] & 0xFDF92000)) {
- pr_err("error %d requesting status %#x\n",
- err, cmd.resp[0]);
- err = -EIO;
- goto out;
- }
- } while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
- R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG);
-out:
- return err;
-}
-
-/**
- * mmc_erase - erase sectors.
- * @card: card to erase
- * @from: first sector to erase
- * @nr: number of sectors to erase
- * @arg: erase command argument (SD supports only %MMC_ERASE_ARG)
- *
- * Caller must claim host before calling this function.
- */
-int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
- unsigned int arg)
-{
- unsigned int rem, to = from + nr;
- int ret;
-
- DBG("[%s] s\n",__func__);
-
- if (!(card->host->caps & MMC_CAP_ERASE) ||
- !(card->csd.cmdclass & CCC_ERASE)) {
- DBG("[%s] e1\n",__func__);
- return -EOPNOTSUPP;
- }
-
- if (!card->erase_size) {
- DBG("[%s] e2\n",__func__);
- return -EOPNOTSUPP;
- }
-
- if (mmc_card_sd(card) && arg != MMC_ERASE_ARG) {
- DBG("[%s] e3\n",__func__);
- return -EOPNOTSUPP;
- }
-
- if ((arg & MMC_SECURE_ARGS) &&
- !(card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN)) {
- DBG("[%s] e4\n",__func__);
- return -EOPNOTSUPP;
- }
-
- if ((arg & MMC_TRIM_ARGS) &&
- !(card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN)) {
- DBG("[%s] e5\n",__func__);
- return -EOPNOTSUPP;
- }
-
- if (arg == MMC_SECURE_ERASE_ARG) {
- if (from % card->erase_size || nr % card->erase_size) {
- DBG("[%s] e6\n",__func__);
- return -EINVAL;
- }
- }
-
- if (arg == MMC_ERASE_ARG) {
- rem = from % card->erase_size;
- if (rem) {
- rem = card->erase_size - rem;
- from += rem;
- if (nr > rem)
- nr -= rem;
- else {
- DBG("[%s] e7\n",__func__);
- return 0;
- }
- }
- rem = nr % card->erase_size;
- if (rem)
- nr -= rem;
- }
-
- if (nr == 0) {
- DBG("[%s] e8\n",__func__);
- return 0;
- }
-
- to = from + nr;
-
- if (to <= from) {
- DBG("[%s] e9\n",__func__);
- return -EINVAL;
- }
-
- /* 'from' and 'to' are inclusive */
- to -= 1;
-
- ret = mmc_do_erase(card, from, to, arg);
- DBG("[%s] e10\n",__func__);
- /*return mmc_do_erase(card, from, to, arg);*/
- return ret;
-}
-EXPORT_SYMBOL(mmc_erase);
-
-int mmc_can_erase(struct mmc_card *card)
-{
- DBG("[%s] s\n",__func__);
-
- if ((card->host->caps & MMC_CAP_ERASE) &&
- (card->csd.cmdclass & CCC_ERASE) && card->erase_size) {
- DBG("[%s] e1\n",__func__);
- return 1;
- }
- DBG("[%s] e2\n",__func__);
- return 0;
-}
-EXPORT_SYMBOL(mmc_can_erase);
-
-int mmc_can_trim(struct mmc_card *card)
-{
- DBG("[%s] s\n",__func__);
-
- if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN) {
- DBG("[%s] e1\n",__func__);
- return 1;
- }
-
- DBG("[%s] e2\n",__func__);
- return 0;
-}
-EXPORT_SYMBOL(mmc_can_trim);
-
-int mmc_can_discard(struct mmc_card *card)
-{
- DBG("[%s] s\n",__func__);
- /*
- * As there's no way to detect the discard support bit at v4.5
- * use the s/w feature support filed.
- */
- if (card->ext_csd.feature_support & MMC_DISCARD_FEATURE) {
- DBG("[%s] e1\n",__func__);
- return 1;
- }
- DBG("[%s] e2\n",__func__);
- return 0;
-}
-EXPORT_SYMBOL(mmc_can_discard);
-
-int mmc_can_sanitize(struct mmc_card *card)
-{
- DBG("[%s] s\n",__func__);
- if (!mmc_can_trim(card) && !mmc_can_erase(card)) {
- DBG("[%s] e1\n",__func__);
- return 0;
- }
- if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_SANITIZE) {
- DBG("[%s] e2\n",__func__);
- return 1;
- }
- DBG("[%s] e3\n",__func__);
- return 0;
-}
-EXPORT_SYMBOL(mmc_can_sanitize);
-
-int mmc_can_secure_erase_trim(struct mmc_card *card)
-{
- DBG("[%s] s\n",__func__);
-
- if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN) {
- DBG("[%s] e1\n",__func__);
- return 1;
- }
- DBG("[%s] e2\n",__func__);
- return 0;
-}
-EXPORT_SYMBOL(mmc_can_secure_erase_trim);
-
-int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
- unsigned int nr)
-{
- DBG("[%s] s\n",__func__);
- if (!card->erase_size) {
- DBG("[%s] e1\n",__func__);
- return 0;
- }
- if (from % card->erase_size || nr % card->erase_size) {
- DBG("[%s] e2\n",__func__);
- return 0;
- }
- DBG("[%s] e3\n",__func__);
- return 1;
-}
-EXPORT_SYMBOL(mmc_erase_group_aligned);
-
-static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
- unsigned int arg)
-{
- struct mmc_host *host = card->host;
- unsigned int max_discard, x, y, qty = 0, max_qty, timeout;
- unsigned int last_timeout = 0;
-
- DBG("[%s] s\n",__func__);
-
- if (card->erase_shift)
- max_qty = UINT_MAX >> card->erase_shift;
- else if (mmc_card_sd(card))
- max_qty = UINT_MAX;
- else
- max_qty = UINT_MAX / card->erase_size;
-
- /* Find the largest qty with an OK timeout */
- do {
- y = 0;
- for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) {
- timeout = mmc_erase_timeout(card, arg, qty + x);
- if (timeout > host->max_discard_to)
- break;
- if (timeout < last_timeout)
- break;
- last_timeout = timeout;
- y = x;
- }
- qty += y;
- } while (y);
-
- if (!qty) {
- DBG("[%s] e1\n",__func__);
- return 0;
- }
-
- if (qty == 1) {
- DBG("[%s] e2\n",__func__);
- return 1;
- }
-
- /* Convert qty to sectors */
- if (card->erase_shift)
- max_discard = --qty << card->erase_shift;
- else if (mmc_card_sd(card))
- max_discard = qty;
- else
- max_discard = --qty * card->erase_size;
-
- DBG("[%s] e3\n",__func__);
- return max_discard;
-}
-
-unsigned int mmc_calc_max_discard(struct mmc_card *card)
-{
- struct mmc_host *host = card->host;
- unsigned int max_discard, max_trim;
- DBG("[%s] s\n",__func__);
- if (!host->max_discard_to) {
- DBG("[%s] e1\n",__func__);
- return UINT_MAX;
- }
-
- /*
- * Without erase_group_def set, MMC erase timeout depends on clock
- * frequence which can change. In that case, the best choice is
- * just the preferred erase size.
- */
- if (mmc_card_mmc(card) && !(card->ext_csd.erase_group_def & 1)) {
- DBG("[%s] e2\n",__func__);
- return card->pref_erase;
- }
-
- max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG);
- if (mmc_can_trim(card)) {
- max_trim = mmc_do_calc_max_discard(card, MMC_TRIM_ARG);
- if (max_trim < max_discard)
- max_discard = max_trim;
- } else if (max_discard < card->erase_size) {
- max_discard = 0;
- }
- pr_debug("%s: calculated max. discard sectors %u for timeout %u ms\n",
- mmc_hostname(host), max_discard, host->max_discard_to);
- DBG("[%s] e3\n",__func__);
- return max_discard;
-}
-EXPORT_SYMBOL(mmc_calc_max_discard);
-
-int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
-{
- struct mmc_command cmd = {0};
- int ret;
-
- DBG("[%s] s\n",__func__);
-
- if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card)) {
- DBG("[%s] e1\n",__func__);
- return 0;
- }
-
- cmd.opcode = MMC_SET_BLOCKLEN;
- cmd.arg = blocklen;
- //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- ret = mmc_wait_for_cmd(card->host, &cmd, 5);
-
- /*return mmc_wait_for_cmd(card->host, &cmd, 5);*/
- DBG("[%s] e1\n",__func__);
- return ret;
-}
-EXPORT_SYMBOL(mmc_set_blocklen);
-
-static void mmc_hw_reset_for_init(struct mmc_host *host)
-{
- DBG("[%s] s\n",__func__);
-
- if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) {
- DBG("[%s] e1\n",__func__);
- return;
- }
- mmc_host_clk_hold(host);
- host->ops->hw_reset(host);
- mmc_host_clk_release(host);
- DBG("[%s] e2\n",__func__);
-}
-
-int mmc_can_reset(struct mmc_card *card)
-{
- u8 rst_n_function;
-
- DBG("[%s] s\n",__func__);
-
- if (!mmc_card_mmc(card)) {
- DBG("[%s] e1\n",__func__);
- return 0;
- }
- rst_n_function = card->ext_csd.rst_n_function;
- if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED) {
- DBG("[%s] e2\n",__func__);
- return 0;
- }
- DBG("[%s] e3\n",__func__);
- return 1;
-}
-EXPORT_SYMBOL(mmc_can_reset);
-
-static int mmc_do_hw_reset(struct mmc_host *host, int check)
-{
- struct mmc_card *card = host->card;
- DBG("[%s] s\n",__func__);
- if (!host->bus_ops->power_restore) {
- DBG("[%s] e1\n",__func__);
- return -EOPNOTSUPP;
- }
-
- if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) {
- DBG("[%s] e2\n",__func__);
- return -EOPNOTSUPP;
- }
-
- if (!card) {
- DBG("[%s] e3\n",__func__);
- return -EINVAL;
- }
-
- if (!mmc_can_reset(card)) {
- DBG("[%s] e4\n",__func__);
- return -EOPNOTSUPP;
- }
-
- mmc_host_clk_hold(host);
- mmc_set_clock(host, host->f_init);
-
- host->ops->hw_reset(host);
-
- /* If the reset has happened, then a status command will fail */
- if (check) {
- struct mmc_command cmd = {0};
- int err;
-
- cmd.opcode = MMC_SEND_STATUS;
- if (!mmc_host_is_spi(card->host))
- cmd.arg = card->rca << 16;
- //cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
- if (!err) {
- mmc_host_clk_release(host);
- DBG("[%s] e5\n",__func__);
- return -ENOSYS;
- }
- }
-
- host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
- if (mmc_host_is_spi(host)) {
- host->ios.chip_select = MMC_CS_HIGH;
- host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
- } else {
- host->ios.chip_select = MMC_CS_DONTCARE;
- host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
- }
- host->ios.bus_width = MMC_BUS_WIDTH_1;
- host->ios.timing = MMC_TIMING_LEGACY;
- mmc_set_ios(host);
-
- mmc_host_clk_release(host);
- DBG("[%s] e6\n",__func__);
- return host->bus_ops->power_restore(host);
-}
-
-int mmc_hw_reset(struct mmc_host *host)
-{
- DBG("[%s] s\n",__func__);
- return mmc_do_hw_reset(host, 0);
-}
-EXPORT_SYMBOL(mmc_hw_reset);
-
-int mmc_hw_reset_check(struct mmc_host *host)
-{
- DBG("[%s] s\n",__func__);
- return mmc_do_hw_reset(host, 1);
-}
-EXPORT_SYMBOL(mmc_hw_reset_check);
-
-static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
-{
- DBG("[%s] s\n",__func__);
-
- host->f_init = freq;
-
-#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);
-
- /*
- * Some eMMCs (with VCCQ always on) may not be reset after power up, so
- * do a hardware reset if possible.
- */
- mmc_hw_reset_for_init(host);
-
- /* Initialization should be done at 3.3 V I/O voltage. */
- mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
-
- /*
- * sdio_reset sends CMD52 to reset card. Since we do not know
- * if the card is being re-initialized, just send it. CMD52
- * should be ignored by SD/eMMC cards.
- */
- sdio_reset(host);
- mmc_go_idle(host);
-
- mmc_send_if_cond(host, host->ocr_avail);
-
- /* Order's important: probe SDIO, then SD, then MMC */
- if (!mmc_attach_sdio(host)) {
- DBG("[%s] e1\n",__func__);
- return 0;
- }
- if (!mmc_attach_sd(host)) {
- DBG("[%s] e2\n",__func__);
- return 0;
- }
- if (!mmc_attach_mmc(host)) {
- DBG("[%s] e3\n",__func__);
- return 0;
- }
-
- mmc_power_off(host);
- DBG("[%s] e4\n",__func__);
- return -EIO;
-}
-
-int _mmc_detect_card_removed(struct mmc_host *host)
-{
- int ret;
-
- DBG("[%s] s\n",__func__);
- if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive) {
- DBG("[%s] e1\n",__func__);
- return 0;
- }
-
- if (!host->card || mmc_card_removed(host->card)) {
- DBG("[%s] e2\n",__func__);
- return 1;
- }
-
- ret = host->bus_ops->alive(host);
- if (ret) {
- mmc_card_set_removed(host->card);
- pr_debug("%s: card remove detected\n", mmc_hostname(host));
- }
- DBG("[%s] e3\n",__func__);
- return ret;
-}
-
-int mmc_detect_card_removed(struct mmc_host *host)
-{
- struct mmc_card *card = host->card;
- int ret;
-
- DBG("[%s] s\n",__func__);
-
- WARN_ON(!host->claimed);
-
- if (!card) {
- DBG("[%s] e1\n",__func__);
- return 1;
- }
- ret = mmc_card_removed(card);
- /*
- * The card will be considered unchanged unless we have been asked to
- * detect a change or host requires polling to provide card detection.
- */
- if (!host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL) &&
- !(host->caps2 & MMC_CAP2_DETECT_ON_ERR)) {
- DBG("[%s] e2\n",__func__);
- return ret;
- }
-
- host->detect_change = 0;
- if (!ret) {
- ret = _mmc_detect_card_removed(host);
- if (ret && (host->caps2 & MMC_CAP2_DETECT_ON_ERR)) {
- /*
- * Schedule a detect work as soon as possible to let a
- * rescan handle the card removal.
- */
- cancel_delayed_work(&host->detect);
- mmc_detect_change(host, 0);
- }
- }
- DBG("[%s] e3\n",__func__);
- return ret;
-}
-EXPORT_SYMBOL(mmc_detect_card_removed);
-
-void mmc_rescan(struct work_struct *work)
-{
- static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
- struct mmc_host *host =
- container_of(work, struct mmc_host, detect.work);
- int i;
- bool extend_wakelock = false;
- struct atsmb_host *atsmb_host = mmc_priv(host);
- int retry = 5;
-
- DBG("[%s] s\n",__func__);
- host->card_scan_status = false;
-
- if (host->rescan_disable)
- return;
-
- while(retry > 0) {
- retry--;
- mmc_bus_get(host);
-
- /*
- * if there is a _removable_ card registered, check whether it is
- * still present
- */
- if (host->bus_ops && host->bus_ops->detect && !host->bus_dead
- && !(host->caps & MMC_CAP_NONREMOVABLE))
- host->bus_ops->detect(host);
-
- host->detect_change = 0;
-
- /* If the card was removed the bus will be marked
- * as dead - extend the wakelock so userspace
- * can respond */
- if (host->bus_dead)
- extend_wakelock = 1;
-
- /*
- * Let mmc_bus_put() free the bus/bus_ops if we've found that
- * the card is no longer present.
- */
- mmc_bus_put(host);
- mmc_bus_get(host);
-
- /* if there still is a card present, stop here */
- if (host->bus_ops != NULL) {
- mmc_bus_put(host);
- goto out;
- }
-
- /*
- * Only we can add a new handler, so it's safe to
- * release the lock here.
- */
- mmc_bus_put(host);
-
- 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++) {
- if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) {
- extend_wakelock = true;
- break;
- }
- if (freqs[i] <= host->f_min)
- break;
- }
- mmc_release_host(host);
-
- out:
- if (extend_wakelock)
- wake_lock_timeout(&host->detect_wake_lock, HZ / 2);
- else
- wake_unlock(&host->detect_wake_lock);
- if (host->caps & MMC_CAP_NEEDS_POLL) {
- wake_lock(&host->detect_wake_lock);
- mmc_schedule_delayed_work(&host->detect, HZ);
- }
-
- DBG("[%s]retry = %d slot = %x power = %x\n",
- __func__,retry,host->ops->get_slot_status(host),
- host->ios.power_mode);
-
- if((host->ops->get_slot_status(host) == 0) ||
- (host->ios.power_mode != MMC_POWER_OFF))
- break;
-
- msleep(1000);
-
- }
- if (host->ios.power_mode != MMC_POWER_OFF)
- host->card_scan_status = true;
- printk("SD%d Host Clock %dHz\n",host->wmt_host_index, atsmb_host->current_clock);
-
- DBG("[%s] e\n",__func__);
-}
-
-void mmc_start_host(struct mmc_host *host,bool detect)
-{
- DBG("[%s] s\n",__func__);
-
- mmc_power_off(host);
- if (detect == true)
- mmc_detect_change(host, 0);
-
- DBG("[%s] e\n",__func__);
-}
-
-void mmc_stop_host(struct mmc_host *host)
-{
- DBG("[%s] s\n",__func__);
-#ifdef CONFIG_MMC_DEBUG
- unsigned long flags;
- spin_lock_irqsave(&host->lock, flags);
- host->removed = 1;
- spin_unlock_irqrestore(&host->lock, flags);
-#endif
-
- if (cancel_delayed_work_sync(&host->detect))
- wake_unlock(&host->detect_wake_lock);
- mmc_flush_scheduled_work();
-
- /* clear pm flags now and let card drivers set them as needed */
- host->pm_flags = 0;
-
- mmc_bus_get(host);
- if (host->bus_ops && !host->bus_dead) {
- /* Calling bus_ops->remove() with a claimed host can deadlock */
- if (host->bus_ops->remove)
- host->bus_ops->remove(host);
-
- mmc_claim_host(host);
- mmc_detach_bus(host);
- mmc_power_off(host);
- mmc_release_host(host);
- mmc_bus_put(host);
- DBG("[%s] e1\n",__func__);
- return;
- }
- mmc_bus_put(host);
-
- BUG_ON(host->card);
-
- mmc_power_off(host);
-
- DBG("[%s] e2\n",__func__);
-}
-
-int mmc_power_save_host(struct mmc_host *host)
-{
- int ret = 0;
-
- DBG("[%s] s\n",__func__);
-
-#ifdef CONFIG_MMC_DEBUG
- pr_info("%s: %s: powering down\n", mmc_hostname(host), __func__);
-#endif
-
- mmc_bus_get(host);
-
- if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
- mmc_bus_put(host);
- DBG("[%s] e1\n",__func__);
- return -EINVAL;
- }
-
- if (host->bus_ops->power_save)
- ret = host->bus_ops->power_save(host);
-
- mmc_bus_put(host);
-
- mmc_power_off(host);
-
- DBG("[%s] e2\n",__func__);
- return ret;
-}
-EXPORT_SYMBOL(mmc_power_save_host);
-
-int mmc_power_restore_host(struct mmc_host *host)
-{
- int ret;
-
- DBG("[%s] s\n",__func__);
-
-#ifdef CONFIG_MMC_DEBUG
- pr_info("%s: %s: powering up\n", mmc_hostname(host), __func__);
-#endif
-
- mmc_bus_get(host);
-
- if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
- mmc_bus_put(host);
- DBG("[%s] e1\n",__func__);
- return -EINVAL;
- }
-
- mmc_power_up(host);
- ret = host->bus_ops->power_restore(host);
-
- mmc_bus_put(host);
- DBG("[%s] e2\n",__func__);
- return ret;
-}
-EXPORT_SYMBOL(mmc_power_restore_host);
-
-int mmc_card_awake(struct mmc_host *host)
-{
- int err = -ENOSYS;
-
- DBG("[%s] s\n",__func__);
-
- if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD) {
- DBG("[%s] e1\n",__func__);
- return 0;
- }
-
- mmc_bus_get(host);
-
- if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
- err = host->bus_ops->awake(host);
-
- mmc_bus_put(host);
-
- DBG("[%s] e2\n",__func__);
- return err;
-}
-EXPORT_SYMBOL(mmc_card_awake);
-
-int mmc_card_sleep(struct mmc_host *host)
-{
- int err = -ENOSYS;
-
- DBG("[%s] s\n",__func__);
-
- if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD) {
- DBG("[%s] e1\n",__func__);
- return 0;
- }
-
- mmc_bus_get(host);
-
- if (host->bus_ops && !host->bus_dead && host->bus_ops->sleep)
- err = host->bus_ops->sleep(host);
-
- mmc_bus_put(host);
-
- DBG("[%s] e2\n",__func__);
- return err;
-}
-EXPORT_SYMBOL(mmc_card_sleep);
-
-int mmc_card_can_sleep(struct mmc_host *host)
-{
- struct mmc_card *card = host->card;
-
- DBG("[%s] s\n",__func__);
- if (card && mmc_card_mmc(card) && card->ext_csd.rev >= 3) {
- DBG("[%s] e1\n",__func__);
- return 1;
- }
-
- DBG("[%s] e2\n",__func__);
- return 0;
-}
-EXPORT_SYMBOL(mmc_card_can_sleep);
-
-/*
- * Flush the cache to the non-volatile storage.
- */
-int mmc_flush_cache(struct mmc_card *card)
-{
- struct mmc_host *host = card->host;
- int err = 0;
- DBG("[%s] s\n",__func__);
-
- if (!(host->caps2 & MMC_CAP2_CACHE_CTRL)) {
- DBG("[%s] e1\n",__func__);
- return err;
- }
-
- if (mmc_card_mmc(card) &&
- (card->ext_csd.cache_size > 0) &&
- (card->ext_csd.cache_ctrl & 1)) {
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_FLUSH_CACHE, 1, 0);
- if (err)
- pr_err("%s: cache flush error %d\n",
- mmc_hostname(card->host), err);
- }
- DBG("[%s] e2\n",__func__);
- return err;
-}
-EXPORT_SYMBOL(mmc_flush_cache);
-
-/*
- * Turn the cache ON/OFF.
- * Turning the cache OFF shall trigger flushing of the data
- * to the non-volatile storage.
- */
-int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
-{
- struct mmc_card *card = host->card;
- unsigned int timeout;
- int err = 0;
-
- DBG("[%s] s\n",__func__);
-
- if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) ||
- mmc_card_is_removable(host)) {
- DBG("[%s] e1\n",__func__);
- return err;
- }
-
- mmc_claim_host(host);
- if (card && mmc_card_mmc(card) &&
- (card->ext_csd.cache_size > 0)) {
- enable = !!enable;
-
- if (card->ext_csd.cache_ctrl ^ enable) {
- timeout = enable ? card->ext_csd.generic_cmd6_time : 0;
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_CACHE_CTRL, enable, timeout);
- if (err)
- pr_err("%s: cache %s error %d\n",
- mmc_hostname(card->host),
- enable ? "on" : "off",
- err);
- else
- card->ext_csd.cache_ctrl = enable;
- }
- }
- mmc_release_host(host);
- DBG("[%s] e2\n",__func__);
- return err;
-}
-EXPORT_SYMBOL(mmc_cache_ctrl);
-
-#ifdef CONFIG_PM
-
-/**
- * mmc_suspend_host - suspend a host
- * @host: mmc host
- */
-int mmc_suspend_host(struct mmc_host *host)
-{
- int err = 0;
-
- DBG("[%s] s\n",__func__);
-
- if (mmc_bus_needs_resume(host)) {
- DBG("[%s] e1\n",__func__);
- return 0;
- }
-
- if (cancel_delayed_work(&host->detect))
- wake_unlock(&host->detect_wake_lock);
- mmc_flush_scheduled_work();
-
- err = mmc_cache_ctrl(host, 0);
- if (err)
- goto out;
-
- mmc_bus_get(host);
- if (host->bus_ops && !host->bus_dead) {
-
- if (host->bus_ops->suspend)
- err = host->bus_ops->suspend(host);
-
- if (err == -ENOSYS || !host->bus_ops->resume) {
- /*
- * We simply "remove" the card in this case.
- * It will be redetected on resume. (Calling
- * bus_ops->remove() with a claimed host can
- * deadlock.)
- */
- if (host->bus_ops->remove)
- host->bus_ops->remove(host);
- mmc_claim_host(host);
- mmc_detach_bus(host);
- mmc_power_off(host);
- mmc_release_host(host);
- host->pm_flags = 0;
- err = 0;
- }
- }
- mmc_bus_put(host);
-
- if (!err && !mmc_card_keep_power(host))
- mmc_power_off(host);
-
-out:
- DBG("[%s] e2\n",__func__);
- return err;
-}
-
-EXPORT_SYMBOL(mmc_suspend_host);
-
-/**
- * mmc_resume_host - resume a previously suspended host
- * @host: mmc host
- */
-int mmc_resume_host(struct mmc_host *host)
-{
- int err = 0;
-
- DBG("[%s] s\n",__func__);
-
- mmc_bus_get(host);
- if (mmc_bus_manual_resume(host)) {
- host->bus_resume_flags |= MMC_BUSRESUME_NEEDS_RESUME;
- mmc_bus_put(host);
- DBG("[%s] e1\n",__func__);
- return 0;
- }
-
- if (host->bus_ops && !host->bus_dead) {
- if (!mmc_card_keep_power(host)) {
- mmc_power_up(host);
- mmc_select_voltage(host, host->ocr);
- /*
- * Tell runtime PM core we just powered up the card,
- * since it still believes the card is powered off.
- * Note that currently runtime PM is only enabled
- * for SDIO cards that are MMC_CAP_POWER_OFF_CARD
- */
- if (mmc_card_sdio(host->card) &&
- (host->caps & MMC_CAP_POWER_OFF_CARD)) {
- pm_runtime_disable(&host->card->dev);
- pm_runtime_set_active(&host->card->dev);
- pm_runtime_enable(&host->card->dev);
- }
- }
- //kevin add for suspend&resume
- mmc_set_ios(host);
-
- BUG_ON(!host->bus_ops->resume);
- err = host->bus_ops->resume(host);
- if (err) {
- pr_warning("%s: error %d during resume "
- "(card was removed?)\n",
- mmc_hostname(host), err);
- err = 0;
- }
- }
- host->pm_flags &= ~MMC_PM_KEEP_POWER;
- mmc_bus_put(host);
- DBG("[%s] e2\n",__func__);
- return err;
-}
-EXPORT_SYMBOL(mmc_resume_host);
-
-/* Do the card removal on suspend if card is assumed removeable
- * Do that in pm notifier while userspace isn't yet frozen, so we will be able
- to sync the card.
-*/
-int mmc_pm_notify(struct notifier_block *notify_block,
- unsigned long mode, void *unused)
-{
- struct mmc_host *host = container_of(
- notify_block, struct mmc_host, pm_notify);
- unsigned long flags;
-
- DBG("[%s] s\n",__func__);
-
- switch (mode) {
- case PM_HIBERNATION_PREPARE:
- case PM_SUSPEND_PREPARE:
-
- spin_lock_irqsave(&host->lock, flags);
- if (mmc_bus_needs_resume(host)) {
- spin_unlock_irqrestore(&host->lock, flags);
- break;
- }
- host->rescan_disable = 1;
- host->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
- spin_unlock_irqrestore(&host->lock, flags);
- if (cancel_delayed_work_sync(&host->detect))
- wake_unlock(&host->detect_wake_lock);
-
- if (!host->bus_ops || host->bus_ops->suspend)
- break;
-
- /* Calling bus_ops->remove() with a claimed host can deadlock */
- if (host->bus_ops->remove)
- host->bus_ops->remove(host);
-
- mmc_claim_host(host);
- mmc_detach_bus(host);
- mmc_power_off(host);
- mmc_release_host(host);
- host->pm_flags = 0;
- break;
-
- case PM_POST_SUSPEND:
- case PM_POST_HIBERNATION:
- case PM_POST_RESTORE:
-
- spin_lock_irqsave(&host->lock, flags);
- if (mmc_bus_manual_resume(host)) {
- spin_unlock_irqrestore(&host->lock, flags);
- break;
- }
- host->rescan_disable = 0;
- host->power_notify_type = MMC_HOST_PW_NOTIFY_LONG;
- spin_unlock_irqrestore(&host->lock, flags);
- if(!(host->bus_dead))
- mmc_detect_change(host, 0);
-
- }
- DBG("[%s] e\n",__func__);
- return 0;
-}
-#endif
-
-void mmc_force_remove_card(struct mmc_host *host)
-{
- DBG("[%s] s\n",__func__);
- mmc_bus_get(host);
-
- if (host->bus_ops && !host->bus_dead) {
-
- if (host->bus_ops->remove)
- host->bus_ops->remove(host);
- mmc_claim_host(host);
- mmc_detach_bus(host);
- mmc_release_host(host);
-
- }
- mmc_bus_put(host);
- mmc_power_off(host);
- DBG("[%s] e\n",__func__);
- return ;
-}
-EXPORT_SYMBOL(mmc_force_remove_card);
-
-
-#ifdef CONFIG_MMC_EMBEDDED_SDIO
-void mmc_set_embedded_sdio_data(struct mmc_host *host,
- struct sdio_cis *cis,
- struct sdio_cccr *cccr,
- struct sdio_embedded_func *funcs,
- int num_funcs)
-{
- DBG("[%s] s\n",__func__);
- host->embedded_sdio_data.cis = cis;
- host->embedded_sdio_data.cccr = cccr;
- host->embedded_sdio_data.funcs = funcs;
- host->embedded_sdio_data.num_funcs = num_funcs;
- DBG("[%s] e\n",__func__);
-}
-
-EXPORT_SYMBOL(mmc_set_embedded_sdio_data);
-#endif
-
-static int __init mmc_init(void)
-{
- int ret;
-
- DBG("[%s] s\n",__func__);
-
- workqueue = alloc_ordered_workqueue("kmmcd", 0);
- if (!workqueue) {
- DBG("[%s] e1\n",__func__);
- return -ENOMEM;
- }
-
- ret = mmc_register_bus();
- if (ret)
- goto destroy_workqueue;
-
- ret = mmc_register_host_class();
- if (ret)
- goto unregister_bus;
-
- ret = sdio_register_bus();
- if (ret)
- goto unregister_host_class;
-
- DBG("[%s] e2\n",__func__);
- return 0;
-
-unregister_host_class:
- mmc_unregister_host_class();
-unregister_bus:
- mmc_unregister_bus();
-destroy_workqueue:
- destroy_workqueue(workqueue);
-
- DBG("[%s] e3\n",__func__);
- return ret;
-}
-
-static void __exit mmc_exit(void)
-{
- DBG("[%s] s\n",__func__);
- sdio_unregister_bus();
- mmc_unregister_host_class();
- mmc_unregister_bus();
- destroy_workqueue(workqueue);
- DBG("[%s] e\n",__func__);
-}
-
-subsys_initcall(mmc_init);
-module_exit(mmc_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/mmc/core/core.h b/ANDROID_3.4.5/drivers/mmc/core/core.h
deleted file mode 100644
index 1e26016a..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/core.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * linux/drivers/mmc/core/core.h
- *
- * Copyright (C) 2003 Russell King, All Rights Reserved.
- * Copyright 2007 Pierre Ossman
- *
- * 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 _MMC_CORE_CORE_H
-#define _MMC_CORE_CORE_H
-
-#include <linux/delay.h>
-
-#define MMC_CMD_RETRIES 3
-
-struct mmc_bus_ops {
- int (*awake)(struct mmc_host *);
- int (*sleep)(struct mmc_host *);
- void (*remove)(struct mmc_host *);
- void (*detect)(struct mmc_host *);
- int (*suspend)(struct mmc_host *);
- int (*resume)(struct mmc_host *);
- int (*power_save)(struct mmc_host *);
- int (*power_restore)(struct mmc_host *);
- int (*alive)(struct mmc_host *);
-};
-
-void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
-void mmc_detach_bus(struct mmc_host *host);
-
-void mmc_init_erase(struct mmc_card *card);
-
-void mmc_set_chip_select(struct mmc_host *host, int mode);
-void mmc_set_clock(struct mmc_host *host, unsigned int hz);
-void mmc_gate_clock(struct mmc_host *host);
-void mmc_ungate_clock(struct mmc_host *host);
-void mmc_set_ungated(struct mmc_host *host);
-void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
-void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
-u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
-int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage,
- bool cmd11);
-void mmc_set_timing(struct mmc_host *host, unsigned int timing);
-void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
-void mmc_power_off(struct mmc_host *host);
-
-static inline void mmc_delay(unsigned int ms)
-{
- if (ms < 1000 / HZ) {
- cond_resched();
- mdelay(ms);
- } else {
- msleep(ms);
- }
-}
-
-void mmc_rescan(struct work_struct *work);
-void mmc_start_host(struct mmc_host *host, bool detect);
-void mmc_stop_host(struct mmc_host *host);
-
-int _mmc_detect_card_removed(struct mmc_host *host);
-
-int mmc_attach_mmc(struct mmc_host *host);
-int mmc_attach_sd(struct mmc_host *host);
-int mmc_attach_sdio(struct mmc_host *host);
-
-/* Module parameters */
-extern bool use_spi_crc;
-
-/* Debugfs information for hosts and cards */
-void mmc_add_host_debugfs(struct mmc_host *host);
-void mmc_remove_host_debugfs(struct mmc_host *host);
-
-void mmc_add_card_debugfs(struct mmc_card *card);
-void mmc_remove_card_debugfs(struct mmc_card *card);
-
-#endif
-
diff --git a/ANDROID_3.4.5/drivers/mmc/core/debugfs.c b/ANDROID_3.4.5/drivers/mmc/core/debugfs.c
deleted file mode 100644
index 9ab5b17d..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/debugfs.c
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Debugfs support for hosts and cards
- *
- * Copyright (C) 2008 Atmel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/moduleparam.h>
-#include <linux/export.h>
-#include <linux/debugfs.h>
-#include <linux/fs.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/fault-inject.h>
-
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-
-#include "core.h"
-#include "mmc_ops.h"
-
-#ifdef CONFIG_FAIL_MMC_REQUEST
-
-static DECLARE_FAULT_ATTR(fail_default_attr);
-static char *fail_request;
-module_param(fail_request, charp, 0);
-
-#endif /* CONFIG_FAIL_MMC_REQUEST */
-
-/* The debugfs functions are optimized away when CONFIG_DEBUG_FS isn't set. */
-static int mmc_ios_show(struct seq_file *s, void *data)
-{
- static const char *vdd_str[] = {
- [8] = "2.0",
- [9] = "2.1",
- [10] = "2.2",
- [11] = "2.3",
- [12] = "2.4",
- [13] = "2.5",
- [14] = "2.6",
- [15] = "2.7",
- [16] = "2.8",
- [17] = "2.9",
- [18] = "3.0",
- [19] = "3.1",
- [20] = "3.2",
- [21] = "3.3",
- [22] = "3.4",
- [23] = "3.5",
- [24] = "3.6",
- };
- struct mmc_host *host = s->private;
- struct mmc_ios *ios = &host->ios;
- const char *str;
-
- seq_printf(s, "clock:\t\t%u Hz\n", ios->clock);
- if (host->actual_clock)
- seq_printf(s, "actual clock:\t%u Hz\n", host->actual_clock);
- seq_printf(s, "vdd:\t\t%u ", ios->vdd);
- if ((1 << ios->vdd) & MMC_VDD_165_195)
- seq_printf(s, "(1.65 - 1.95 V)\n");
- else if (ios->vdd < (ARRAY_SIZE(vdd_str) - 1)
- && vdd_str[ios->vdd] && vdd_str[ios->vdd + 1])
- seq_printf(s, "(%s ~ %s V)\n", vdd_str[ios->vdd],
- vdd_str[ios->vdd + 1]);
- else
- seq_printf(s, "(invalid)\n");
-
- switch (ios->bus_mode) {
- case MMC_BUSMODE_OPENDRAIN:
- str = "open drain";
- break;
- case MMC_BUSMODE_PUSHPULL:
- str = "push-pull";
- break;
- default:
- str = "invalid";
- break;
- }
- seq_printf(s, "bus mode:\t%u (%s)\n", ios->bus_mode, str);
-
- switch (ios->chip_select) {
- case MMC_CS_DONTCARE:
- str = "don't care";
- break;
- case MMC_CS_HIGH:
- str = "active high";
- break;
- case MMC_CS_LOW:
- str = "active low";
- break;
- default:
- str = "invalid";
- break;
- }
- seq_printf(s, "chip select:\t%u (%s)\n", ios->chip_select, str);
-
- switch (ios->power_mode) {
- case MMC_POWER_OFF:
- str = "off";
- break;
- case MMC_POWER_UP:
- str = "up";
- break;
- case MMC_POWER_ON:
- str = "on";
- break;
- default:
- str = "invalid";
- break;
- }
- seq_printf(s, "power mode:\t%u (%s)\n", ios->power_mode, str);
- seq_printf(s, "bus width:\t%u (%u bits)\n",
- ios->bus_width, 1 << ios->bus_width);
-
- switch (ios->timing) {
- case MMC_TIMING_LEGACY:
- str = "legacy";
- break;
- case MMC_TIMING_MMC_HS:
- str = "mmc high-speed";
- break;
- case MMC_TIMING_SD_HS:
- str = "sd high-speed";
- break;
- case MMC_TIMING_UHS_SDR50:
- str = "sd uhs SDR50";
- break;
- case MMC_TIMING_UHS_SDR104:
- str = "sd uhs SDR104";
- break;
- case MMC_TIMING_UHS_DDR50:
- str = "sd uhs DDR50";
- break;
- case MMC_TIMING_MMC_HS200:
- str = "mmc high-speed SDR200";
- break;
- default:
- str = "invalid";
- break;
- }
- seq_printf(s, "timing spec:\t%u (%s)\n", ios->timing, str);
-
- return 0;
-}
-
-static int mmc_ios_open(struct inode *inode, struct file *file)
-{
- return single_open(file, mmc_ios_show, inode->i_private);
-}
-
-static const struct file_operations mmc_ios_fops = {
- .open = mmc_ios_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .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;
-
- root = debugfs_create_dir(mmc_hostname(host), NULL);
- if (IS_ERR(root))
- /* Don't complain -- debugfs just isn't enabled */
- return;
- if (!root)
- /* Complain -- debugfs is enabled, but it failed to
- * create the directory. */
- goto err_root;
-
- host->debugfs_root = root;
-
- if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
- goto err_node;
-
- if (!debugfs_create_file("clock", S_IRUSR | S_IWUSR, root, host,
- &mmc_clock_fops))
- goto err_node;
-
-#ifdef CONFIG_MMC_CLKGATE
- if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR),
- root, &host->clk_delay))
- goto err_node;
-#endif
-#ifdef CONFIG_FAIL_MMC_REQUEST
- if (fail_request)
- setup_fault_attr(&fail_default_attr, fail_request);
- host->fail_mmc_request = fail_default_attr;
- if (IS_ERR(fault_create_debugfs_attr("fail_mmc_request",
- root,
- &host->fail_mmc_request)))
- goto err_node;
-#endif
- return;
-
-err_node:
- debugfs_remove_recursive(root);
- host->debugfs_root = NULL;
-err_root:
- dev_err(&host->class_dev, "failed to initialize debugfs\n");
-}
-
-void mmc_remove_host_debugfs(struct mmc_host *host)
-{
- debugfs_remove_recursive(host->debugfs_root);
-}
-
-static int mmc_dbg_card_status_get(void *data, u64 *val)
-{
- struct mmc_card *card = data;
- u32 status;
- int ret;
-
- mmc_claim_host(card->host);
-
- ret = mmc_send_status(data, &status);
- if (!ret)
- *val = status;
-
- mmc_release_host(card->host);
-
- return ret;
-}
-DEFINE_SIMPLE_ATTRIBUTE(mmc_dbg_card_status_fops, mmc_dbg_card_status_get,
- NULL, "%08llx\n");
-
-#define EXT_CSD_STR_LEN 1025
-
-static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
-{
- struct mmc_card *card = inode->i_private;
- char *buf;
- ssize_t n = 0;
- u8 *ext_csd;
- int err, i;
-
- buf = kmalloc(EXT_CSD_STR_LEN + 1, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- ext_csd = kmalloc(512, GFP_KERNEL);
- if (!ext_csd) {
- err = -ENOMEM;
- goto out_free;
- }
-
- mmc_claim_host(card->host);
- err = mmc_send_ext_csd(card, ext_csd);
- mmc_release_host(card->host);
- if (err)
- goto out_free;
-
- for (i = 511; i >= 0; i--)
- n += sprintf(buf + n, "%02x", ext_csd[i]);
- n += sprintf(buf + n, "\n");
- BUG_ON(n != EXT_CSD_STR_LEN);
-
- filp->private_data = buf;
- kfree(ext_csd);
- return 0;
-
-out_free:
- kfree(buf);
- kfree(ext_csd);
- return err;
-}
-
-static ssize_t mmc_ext_csd_read(struct file *filp, char __user *ubuf,
- size_t cnt, loff_t *ppos)
-{
- char *buf = filp->private_data;
-
- return simple_read_from_buffer(ubuf, cnt, ppos,
- buf, EXT_CSD_STR_LEN);
-}
-
-static int mmc_ext_csd_release(struct inode *inode, struct file *file)
-{
- kfree(file->private_data);
- return 0;
-}
-
-static const struct file_operations mmc_dbg_ext_csd_fops = {
- .open = mmc_ext_csd_open,
- .read = mmc_ext_csd_read,
- .release = mmc_ext_csd_release,
- .llseek = default_llseek,
-};
-
-void mmc_add_card_debugfs(struct mmc_card *card)
-{
- struct mmc_host *host = card->host;
- struct dentry *root;
-
- if (!host->debugfs_root)
- return;
-
- root = debugfs_create_dir(mmc_card_id(card), host->debugfs_root);
- if (IS_ERR(root))
- /* Don't complain -- debugfs just isn't enabled */
- return;
- if (!root)
- /* Complain -- debugfs is enabled, but it failed to
- * create the directory. */
- goto err;
-
- card->debugfs_root = root;
-
- if (!debugfs_create_x32("state", S_IRUSR, root, &card->state))
- goto err;
-
- if (mmc_card_mmc(card) || mmc_card_sd(card))
- if (!debugfs_create_file("status", S_IRUSR, root, card,
- &mmc_dbg_card_status_fops))
- goto err;
-
- if (mmc_card_mmc(card))
- if (!debugfs_create_file("ext_csd", S_IRUSR, root, card,
- &mmc_dbg_ext_csd_fops))
- goto err;
-
- return;
-
-err:
- debugfs_remove_recursive(root);
- card->debugfs_root = NULL;
- dev_err(&card->dev, "failed to initialize debugfs\n");
-}
-
-void mmc_remove_card_debugfs(struct mmc_card *card)
-{
- debugfs_remove_recursive(card->debugfs_root);
-}
diff --git a/ANDROID_3.4.5/drivers/mmc/core/host.c b/ANDROID_3.4.5/drivers/mmc/core/host.c
deleted file mode 100644
index 37384d1c..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/host.c
+++ /dev/null
@@ -1,498 +0,0 @@
-/*
- * linux/drivers/mmc/core/host.c
- *
- * Copyright (C) 2003 Russell King, All Rights Reserved.
- * Copyright (C) 2007-2008 Pierre Ossman
- * Copyright (C) 2010 Linus Walleij
- *
- * 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.
- *
- * MMC host class device management
- */
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/idr.h>
-#include <linux/pagemap.h>
-#include <linux/export.h>
-#include <linux/leds.h>
-#include <linux/slab.h>
-#include <linux/suspend.h>
-
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-
-#include "core.h"
-#include "host.h"
-
-#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
-
-
-#if 0
-#define DBG(x...) printk(KERN_ALERT x)
-#else
-#define DBG(x...) do { } while (0)
-#endif
-
-static void mmc_host_classdev_release(struct device *dev)
-{
- struct mmc_host *host = cls_dev_to_mmc_host(dev);
- DBG("[%s] s\n",__func__);
- kfree(host);
- DBG("[%s] e\n",__func__);
-}
-
-static struct class mmc_host_class = {
- .name = "mmc_host",
- .dev_release = mmc_host_classdev_release,
-};
-
-int mmc_register_host_class(void)
-{
- int ret;
-
- DBG("[%s] s\n",__func__);
- ret = class_register(&mmc_host_class);
- DBG("[%s] e\n",__func__);
- //return class_register(&mmc_host_class);
- return ret;
-}
-
-void mmc_unregister_host_class(void)
-{
- DBG("[%s] s\n",__func__);
- class_unregister(&mmc_host_class);
- DBG("[%s] e\n",__func__);
-}
-
-static DEFINE_IDR(mmc_host_idr);
-static DEFINE_SPINLOCK(mmc_host_lock);
-
-#ifdef CONFIG_MMC_CLKGATE
-static ssize_t clkgate_delay_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct mmc_host *host = cls_dev_to_mmc_host(dev);
- DBG("[%s] s\n",__func__);
- return snprintf(buf, PAGE_SIZE, "%lu\n", host->clkgate_delay);
-}
-
-static ssize_t clkgate_delay_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct mmc_host *host = cls_dev_to_mmc_host(dev);
- unsigned long flags, value;
-
- DBG("[%s] s\n",__func__);
-
- if (kstrtoul(buf, 0, &value)) {
- DBG("[%s] e1\n",__func__);
- return -EINVAL;
- }
-
- spin_lock_irqsave(&host->clk_lock, flags);
- host->clkgate_delay = value;
- spin_unlock_irqrestore(&host->clk_lock, flags);
- DBG("[%s] e2\n",__func__);
- return count;
-}
-
-/*
- * Enabling clock gating will make the core call out to the host
- * once up and once down when it performs a request or card operation
- * intermingled in any fashion. The driver will see this through
- * set_ios() operations with ios.clock field set to 0 to gate (disable)
- * the block clock, and to the old frequency to enable it again.
- */
-static void mmc_host_clk_gate_delayed(struct mmc_host *host)
-{
- unsigned long tick_ns;
- unsigned long freq = host->ios.clock;
- unsigned long flags;
-
- DBG("[%s] s\n",__func__);
-
- if (!freq) {
- pr_debug("%s: frequency set to 0 in disable function, "
- "this means the clock is already disabled.\n",
- mmc_hostname(host));
- DBG("[%s] e1\n",__func__);
- return;
- }
- /*
- * New requests may have appeared while we were scheduling,
- * then there is no reason to delay the check before
- * clk_disable().
- */
- spin_lock_irqsave(&host->clk_lock, flags);
-
- /*
- * Delay n bus cycles (at least 8 from MMC spec) before attempting
- * to disable the MCI block clock. The reference count may have
- * gone up again after this delay due to rescheduling!
- */
- if (!host->clk_requests) {
- spin_unlock_irqrestore(&host->clk_lock, flags);
- tick_ns = DIV_ROUND_UP(1000000000, freq);
- ndelay(host->clk_delay * tick_ns);
- } else {
- /* New users appeared while waiting for this work */
- spin_unlock_irqrestore(&host->clk_lock, flags);
- DBG("[%s] e2\n",__func__);
- return;
- }
- mutex_lock(&host->clk_gate_mutex);
- spin_lock_irqsave(&host->clk_lock, flags);
- if (!host->clk_requests) {
- spin_unlock_irqrestore(&host->clk_lock, flags);
- /* This will set host->ios.clock to 0 */
- mmc_gate_clock(host);
- spin_lock_irqsave(&host->clk_lock, flags);
- pr_debug("%s: gated MCI clock\n", mmc_hostname(host));
- }
- spin_unlock_irqrestore(&host->clk_lock, flags);
- mutex_unlock(&host->clk_gate_mutex);
-
- DBG("[%s] e3\n",__func__);
-}
-
-/*
- * Internal work. Work to disable the clock at some later point.
- */
-static void mmc_host_clk_gate_work(struct work_struct *work)
-{
- struct mmc_host *host = container_of(work, struct mmc_host,
- clk_gate_work.work);
- DBG("[%s] s\n",__func__);
- mmc_host_clk_gate_delayed(host);
- DBG("[%s] e\n",__func__);
-}
-
-/**
- * mmc_host_clk_hold - ungate hardware MCI clocks
- * @host: host to ungate.
- *
- * Makes sure the host ios.clock is restored to a non-zero value
- * past this call. Increase clock reference count and ungate clock
- * if we're the first user.
- */
-void mmc_host_clk_hold(struct mmc_host *host)
-{
- unsigned long flags;
- DBG("[%s] s\n",__func__);
-
- /* cancel any clock gating work scheduled by mmc_host_clk_release() */
- cancel_delayed_work_sync(&host->clk_gate_work);
- mutex_lock(&host->clk_gate_mutex);
- spin_lock_irqsave(&host->clk_lock, flags);
- if (host->clk_gated) {
- spin_unlock_irqrestore(&host->clk_lock, flags);
- mmc_ungate_clock(host);
- spin_lock_irqsave(&host->clk_lock, flags);
- pr_debug("%s: ungated MCI clock\n", mmc_hostname(host));
- }
- host->clk_requests++;
- spin_unlock_irqrestore(&host->clk_lock, flags);
- mutex_unlock(&host->clk_gate_mutex);
- DBG("[%s] e\n",__func__);
-}
-
-/**
- * mmc_host_may_gate_card - check if this card may be gated
- * @card: card to check.
- */
-static bool mmc_host_may_gate_card(struct mmc_card *card)
-{
- DBG("[%s] s\n",__func__);
- /* If there is no card we may gate it */
- if (!card) {
- DBG("[%s] e1\n",__func__);
- return true;
- }
- /*
- * Don't gate SDIO cards! These need to be clocked at all times
- * since they may be independent systems generating interrupts
- * and other events. The clock requests counter from the core will
- * go down to zero since the core does not need it, but we will not
- * gate the clock, because there is somebody out there that may still
- * be using it.
- */
- DBG("[%s] e2\n",__func__);
- return !(card->quirks & MMC_QUIRK_BROKEN_CLK_GATING);
-}
-
-/**
- * mmc_host_clk_release - gate off hardware MCI clocks
- * @host: host to gate.
- *
- * Calls the host driver with ios.clock set to zero as often as possible
- * in order to gate off hardware MCI clocks. Decrease clock reference
- * count and schedule disabling of clock.
- */
-void mmc_host_clk_release(struct mmc_host *host)
-{
- unsigned long flags;
- DBG("[%s] s\n",__func__);
-
- spin_lock_irqsave(&host->clk_lock, flags);
- host->clk_requests--;
- if (mmc_host_may_gate_card(host->card) &&
- !host->clk_requests)
- queue_delayed_work(system_nrt_wq, &host->clk_gate_work,
- msecs_to_jiffies(host->clkgate_delay));
- spin_unlock_irqrestore(&host->clk_lock, flags);
-
- DBG("[%s] e\n",__func__);
-}
-
-/**
- * mmc_host_clk_rate - get current clock frequency setting
- * @host: host to get the clock frequency for.
- *
- * Returns current clock frequency regardless of gating.
- */
-unsigned int mmc_host_clk_rate(struct mmc_host *host)
-{
- unsigned long freq;
- unsigned long flags;
- DBG("[%s] s\n",__func__);
-
- spin_lock_irqsave(&host->clk_lock, flags);
- if (host->clk_gated)
- freq = host->clk_old;
- else
- freq = host->ios.clock;
- spin_unlock_irqrestore(&host->clk_lock, flags);
-
- DBG("[%s] e\n",__func__);
- return freq;
-}
-
-/**
- * mmc_host_clk_init - set up clock gating code
- * @host: host with potential clock to control
- */
-static inline void mmc_host_clk_init(struct mmc_host *host)
-{
- DBG("[%s] s\n",__func__);
- host->clk_requests = 0;
- /* Hold MCI clock for 8 cycles by default */
- host->clk_delay = 8;
- /*
- * Default clock gating delay is 0ms to avoid wasting power.
- * This value can be tuned by writing into sysfs entry.
- */
- host->clkgate_delay = 0;
- host->clk_gated = false;
- INIT_DELAYED_WORK(&host->clk_gate_work, mmc_host_clk_gate_work);
- spin_lock_init(&host->clk_lock);
- mutex_init(&host->clk_gate_mutex);
- DBG("[%s] e\n",__func__);
-}
-
-/**
- * mmc_host_clk_exit - shut down clock gating code
- * @host: host with potential clock to control
- */
-static inline void mmc_host_clk_exit(struct mmc_host *host)
-{
- DBG("[%s] s\n",__func__);
- /*
- * Wait for any outstanding gate and then make sure we're
- * ungated before exiting.
- */
- if (cancel_delayed_work_sync(&host->clk_gate_work))
- mmc_host_clk_gate_delayed(host);
- if (host->clk_gated)
- mmc_host_clk_hold(host);
- /* There should be only one user now */
- WARN_ON(host->clk_requests > 1);
- DBG("[%s] e\n",__func__);
-}
-
-static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
-{
- host->clkgate_delay_attr.show = clkgate_delay_show;
- host->clkgate_delay_attr.store = clkgate_delay_store;
- sysfs_attr_init(&host->clkgate_delay_attr.attr);
- host->clkgate_delay_attr.attr.name = "clkgate_delay";
- host->clkgate_delay_attr.attr.mode = S_IRUGO | S_IWUSR;
- if (device_create_file(&host->class_dev, &host->clkgate_delay_attr))
- pr_err("%s: Failed to create clkgate_delay sysfs entry\n",
- mmc_hostname(host));
-}
-#else
-
-static inline void mmc_host_clk_init(struct mmc_host *host)
-{
-}
-
-static inline void mmc_host_clk_exit(struct mmc_host *host)
-{
-}
-
-static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
-{
-}
-
-#endif
-
-/**
- * mmc_alloc_host - initialise the per-host structure.
- * @extra: sizeof private data structure
- * @dev: pointer to host device model structure
- *
- * Initialise the per-host structure.
- */
-struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
-{
- int err;
- struct mmc_host *host;
- DBG("[%s] s\n",__func__);
-
- if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL)) {
- DBG("[%s] e1\n",__func__);
- return NULL;
- }
-
- host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
- if (!host) {
- DBG("[%s] e2\n",__func__);
- return NULL;
- }
-
- spin_lock(&mmc_host_lock);
- err = idr_get_new(&mmc_host_idr, host, &host->index);
- spin_unlock(&mmc_host_lock);
- if (err)
- goto free;
-
- dev_set_name(&host->class_dev, "mmc%d", host->index);
-
- host->parent = dev;
- host->class_dev.parent = dev;
- host->class_dev.class = &mmc_host_class;
- device_initialize(&host->class_dev);
-
- mmc_host_clk_init(host);
-
- spin_lock_init(&host->lock);
- init_waitqueue_head(&host->wq);
- wake_lock_init(&host->detect_wake_lock, WAKE_LOCK_SUSPEND,
- kasprintf(GFP_KERNEL, "%s_detect", mmc_hostname(host)));
- INIT_DELAYED_WORK(&host->detect, mmc_rescan);
-#ifdef CONFIG_PM
- host->pm_notify.notifier_call = mmc_pm_notify;
-#endif
-
- /*
- * By default, hosts do not support SGIO or large requests.
- * They have to set these according to their abilities.
- */
- host->max_segs = 1;
- host->max_seg_size = PAGE_CACHE_SIZE;
-
- host->max_req_size = PAGE_CACHE_SIZE;
- host->max_blk_size = 512;
- host->max_blk_count = PAGE_CACHE_SIZE / 512;
-
- DBG("[%s] e3\n",__func__);
- return host;
-
-free:
- kfree(host);
- DBG("[%s] e4\n",__func__);
- return NULL;
-}
-
-EXPORT_SYMBOL(mmc_alloc_host);
-
-/**
- * mmc_add_host - initialise host hardware
- * @host: mmc host
- *
- * Register the host with the driver model. The host must be
- * prepared to start servicing requests before this function
- * completes.
- */
-int mmc_add_host(struct mmc_host *host, bool detect)
-{
- int err;
- DBG("[%s] s\n",__func__);
- WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
- !host->ops->enable_sdio_irq);
-
- err = device_add(&host->class_dev);
- if (err) {
- DBG("[%s] e1\n",__func__);
- return err;
- }
-
- led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
-
-#ifdef CONFIG_DEBUG_FS
- mmc_add_host_debugfs(host);
-#endif
- mmc_host_clk_sysfs_init(host);
-
- mmc_start_host(host, detect);
- if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY))
- register_pm_notifier(&host->pm_notify);
-
- DBG("[%s] e2\n",__func__);
- return 0;
-}
-
-EXPORT_SYMBOL(mmc_add_host);
-
-/**
- * mmc_remove_host - remove host hardware
- * @host: mmc host
- *
- * Unregister and remove all cards associated with this host,
- * and power down the MMC bus. No new requests will be issued
- * after this function has returned.
- */
-void mmc_remove_host(struct mmc_host *host)
-{
- DBG("[%s] s\n",__func__);
- if (!(host->pm_flags & MMC_PM_IGNORE_PM_NOTIFY))
- unregister_pm_notifier(&host->pm_notify);
-
- mmc_stop_host(host);
-
-#ifdef CONFIG_DEBUG_FS
- mmc_remove_host_debugfs(host);
-#endif
-
- device_del(&host->class_dev);
-
- led_trigger_unregister_simple(host->led);
-
- mmc_host_clk_exit(host);
- DBG("[%s] e\n",__func__);
-}
-
-EXPORT_SYMBOL(mmc_remove_host);
-
-/**
- * mmc_free_host - free the host structure
- * @host: mmc host
- *
- * Free the host once all references to it have been dropped.
- */
-void mmc_free_host(struct mmc_host *host)
-{
- DBG("[%s] s\n",__func__);
- spin_lock(&mmc_host_lock);
- idr_remove(&mmc_host_idr, host->index);
- spin_unlock(&mmc_host_lock);
- wake_lock_destroy(&host->detect_wake_lock);
-
- put_device(&host->class_dev);
- DBG("[%s] e\n",__func__);
-}
-
-EXPORT_SYMBOL(mmc_free_host);
diff --git a/ANDROID_3.4.5/drivers/mmc/core/host.h b/ANDROID_3.4.5/drivers/mmc/core/host.h
deleted file mode 100644
index f2ab9e57..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/host.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * linux/drivers/mmc/core/host.h
- *
- * Copyright (C) 2003 Russell King, All Rights Reserved.
- * Copyright 2007 Pierre Ossman
- *
- * 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 _MMC_CORE_HOST_H
-#define _MMC_CORE_HOST_H
-#include <linux/mmc/host.h>
-
-int mmc_register_host_class(void);
-void mmc_unregister_host_class(void);
-
-#endif
-
diff --git a/ANDROID_3.4.5/drivers/mmc/core/mmc.c b/ANDROID_3.4.5/drivers/mmc/core/mmc.c
deleted file mode 100644
index 0eb26c64..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/mmc.c
+++ /dev/null
@@ -1,1553 +0,0 @@
-/*
- * linux/drivers/mmc/core/mmc.c
- *
- * Copyright (C) 2003-2004 Russell King, All Rights Reserved.
- * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
- * MMCv4 support Copyright (C) 2006 Philip Langdale, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/mmc.h>
-
-#include "core.h"
-#include "bus.h"
-#include "mmc_ops.h"
-#include "sd_ops.h"
-
-static const unsigned int tran_exp[] = {
- 10000, 100000, 1000000, 10000000,
- 0, 0, 0, 0
-};
-
-static const unsigned char tran_mant[] = {
- 0, 10, 12, 13, 15, 20, 25, 30,
- 35, 40, 45, 50, 55, 60, 70, 80,
-};
-
-static const unsigned int tacc_exp[] = {
- 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
-};
-
-static const unsigned int tacc_mant[] = {
- 0, 10, 12, 13, 15, 20, 25, 30,
- 35, 40, 45, 50, 55, 60, 70, 80,
-};
-
-#define UNSTUFF_BITS(resp,start,size) \
- ({ \
- const int __size = size; \
- const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \
- const int __off = 3 - ((start) / 32); \
- const int __shft = (start) & 31; \
- u32 __res; \
- \
- __res = resp[__off] >> __shft; \
- if (__size + __shft > 32) \
- __res |= resp[__off-1] << ((32 - __shft) % 32); \
- __res & __mask; \
- })
-
-/*
- * Given the decoded CSD structure, decode the raw CID to our CID structure.
- */
-static int mmc_decode_cid(struct mmc_card *card)
-{
- u32 *resp = card->raw_cid;
-
- /*
- * The selection of the format here is based upon published
- * specs from sandisk and from what people have reported.
- */
- switch (card->csd.mmca_vsn) {
- case 0: /* MMC v1.0 - v1.2 */
- case 1: /* MMC v1.4 */
- card->cid.manfid = UNSTUFF_BITS(resp, 104, 24);
- card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
- card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
- card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
- card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
- card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
- card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
- card->cid.prod_name[6] = UNSTUFF_BITS(resp, 48, 8);
- card->cid.hwrev = UNSTUFF_BITS(resp, 44, 4);
- card->cid.fwrev = UNSTUFF_BITS(resp, 40, 4);
- card->cid.serial = UNSTUFF_BITS(resp, 16, 24);
- card->cid.month = UNSTUFF_BITS(resp, 12, 4);
- card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
- break;
-
- case 2: /* MMC v2.0 - v2.2 */
- case 3: /* MMC v3.1 - v3.3 */
- case 4: /* MMC v4 */
- card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
- card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
- card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
- card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
- card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
- card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
- card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
- card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
- card->cid.serial = UNSTUFF_BITS(resp, 16, 32);
- card->cid.month = UNSTUFF_BITS(resp, 12, 4);
- card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
- break;
-
- default:
- pr_err("%s: card has unknown MMCA version %d\n",
- mmc_hostname(card->host), card->csd.mmca_vsn);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static void mmc_set_erase_size(struct mmc_card *card)
-{
- if (card->ext_csd.erase_group_def & 1)
- card->erase_size = card->ext_csd.hc_erase_size;
- else
- card->erase_size = card->csd.erase_size;
-
- mmc_init_erase(card);
-}
-
-/*
- * Given a 128-bit response, decode to our card CSD structure.
- */
-static int mmc_decode_csd(struct mmc_card *card)
-{
- struct mmc_csd *csd = &card->csd;
- unsigned int e, m, a, b;
- u32 *resp = card->raw_csd;
-
- /*
- * We only understand CSD structure v1.1 and v1.2.
- * v1.2 has extra information in bits 15, 11 and 10.
- * We also support eMMC v4.4 & v4.41.
- */
- csd->structure = UNSTUFF_BITS(resp, 126, 2);
- if (csd->structure == 0) {
- pr_err("%s: unrecognised CSD structure version %d\n",
- mmc_hostname(card->host), csd->structure);
- return -EINVAL;
- }
-
- csd->mmca_vsn = UNSTUFF_BITS(resp, 122, 4);
- m = UNSTUFF_BITS(resp, 115, 4);
- e = UNSTUFF_BITS(resp, 112, 3);
- csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
- csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
-
- m = UNSTUFF_BITS(resp, 99, 4);
- e = UNSTUFF_BITS(resp, 96, 3);
- csd->max_dtr = tran_exp[e] * tran_mant[m];
- csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
-
- e = UNSTUFF_BITS(resp, 47, 3);
- m = UNSTUFF_BITS(resp, 62, 12);
- csd->capacity = (1 + m) << (e + 2);
-
- csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
- csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
- csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
- csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
- csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
- csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
- csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
-
- if (csd->write_blkbits >= 9) {
- a = UNSTUFF_BITS(resp, 42, 5);
- b = UNSTUFF_BITS(resp, 37, 5);
- csd->erase_size = (a + 1) * (b + 1);
- csd->erase_size <<= csd->write_blkbits - 9;
- }
-
- return 0;
-}
-
-/*
- * Read extended CSD.
- */
-static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
-{
- int err;
- u8 *ext_csd;
-
- BUG_ON(!card);
- BUG_ON(!new_ext_csd);
-
- *new_ext_csd = NULL;
-
- if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
- return 0;
-
- /*
- * As the ext_csd is so large and mostly unused, we don't store the
- * raw block in mmc_card.
- */
- ext_csd = kmalloc(512, GFP_KERNEL);
- if (!ext_csd) {
- pr_err("%s: could not allocate a buffer to "
- "receive the ext_csd.\n", mmc_hostname(card->host));
- return -ENOMEM;
- }
-
- err = mmc_send_ext_csd(card, ext_csd);
- if (err) {
- kfree(ext_csd);
- *new_ext_csd = NULL;
-
- /* If the host or the card can't do the switch,
- * fail more gracefully. */
- if ((err != -EINVAL)
- && (err != -ENOSYS)
- && (err != -EFAULT))
- return err;
-
- /*
- * High capacity cards should have this "magic" size
- * stored in their CSD.
- */
- if (card->csd.capacity == (4096 * 512)) {
- pr_err("%s: unable to read EXT_CSD "
- "on a possible high capacity card. "
- "Card will be ignored.\n",
- mmc_hostname(card->host));
- } else {
- pr_warning("%s: unable to read "
- "EXT_CSD, performance might "
- "suffer.\n",
- mmc_hostname(card->host));
- err = 0;
- }
- } else
- *new_ext_csd = ext_csd;
-
- return err;
-}
-
-/*
- * Decode extended CSD.
- */
-static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
-{
- int err = 0, idx;
- unsigned int part_size;
- u8 hc_erase_grp_sz = 0, hc_wp_grp_sz = 0;
-
- BUG_ON(!card);
-
- if (!ext_csd)
- return 0;
-
- /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */
- card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE];
- if (card->csd.structure == 3) {
- if (card->ext_csd.raw_ext_csd_structure > 2) {
- pr_err("%s: unrecognised EXT_CSD structure "
- "version %d\n", mmc_hostname(card->host),
- card->ext_csd.raw_ext_csd_structure);
- err = -EINVAL;
- goto out;
- }
- }
-
- card->ext_csd.rev = ext_csd[EXT_CSD_REV];
- if (card->ext_csd.rev > 6) {
- pr_err("%s: unrecognised EXT_CSD revision %d\n",
- mmc_hostname(card->host), card->ext_csd.rev);
- err = -EINVAL;
- goto out;
- }
-
- card->ext_csd.raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0];
- card->ext_csd.raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1];
- card->ext_csd.raw_sectors[2] = ext_csd[EXT_CSD_SEC_CNT + 2];
- card->ext_csd.raw_sectors[3] = ext_csd[EXT_CSD_SEC_CNT + 3];
- if (card->ext_csd.rev >= 2) {
- card->ext_csd.sectors =
- ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
- ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
- ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
- ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
-
- /* Cards with density > 2GiB are sector addressed */
- if (card->ext_csd.sectors > (2u * 1024 * 1024 * 1024) / 512)
- mmc_card_set_blockaddr(card);
- }
- card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
- switch (ext_csd[EXT_CSD_CARD_TYPE] & EXT_CSD_CARD_TYPE_MASK) {
- case EXT_CSD_CARD_TYPE_SDR_ALL:
- case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_8V:
- case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_1_2V:
- case EXT_CSD_CARD_TYPE_SDR_ALL_DDR_52:
- card->ext_csd.hs_max_dtr = 200000000;
- card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_200;
- break;
- case EXT_CSD_CARD_TYPE_SDR_1_2V_ALL:
- case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_8V:
- case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_1_2V:
- case EXT_CSD_CARD_TYPE_SDR_1_2V_DDR_52:
- card->ext_csd.hs_max_dtr = 200000000;
- card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_2V;
- break;
- case EXT_CSD_CARD_TYPE_SDR_1_8V_ALL:
- case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_8V:
- case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_1_2V:
- case EXT_CSD_CARD_TYPE_SDR_1_8V_DDR_52:
- card->ext_csd.hs_max_dtr = 200000000;
- card->ext_csd.card_type = EXT_CSD_CARD_TYPE_SDR_1_8V;
- break;
- 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;
- case EXT_CSD_CARD_TYPE_26:
- card->ext_csd.hs_max_dtr = 26000000;
- break;
- default:
- /* MMC v4 spec says this cannot happen */
- pr_warning("%s: card is mmc v4 but doesn't "
- "support any high-speed modes.\n",
- mmc_hostname(card->host));
- }
-
- card->ext_csd.raw_s_a_timeout = ext_csd[EXT_CSD_S_A_TIMEOUT];
- card->ext_csd.raw_erase_timeout_mult =
- ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
- card->ext_csd.raw_hc_erase_grp_size =
- ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
- if (card->ext_csd.rev >= 3) {
- u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];
- card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG];
-
- /* EXT_CSD value is in units of 10ms, but we store in ms */
- card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME];
-
- /* Sleep / awake timeout in 100ns units */
- if (sa_shift > 0 && sa_shift <= 0x17)
- card->ext_csd.sa_timeout =
- 1 << ext_csd[EXT_CSD_S_A_TIMEOUT];
- card->ext_csd.erase_group_def =
- ext_csd[EXT_CSD_ERASE_GROUP_DEF];
- card->ext_csd.hc_erase_timeout = 300 *
- ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
- card->ext_csd.hc_erase_size =
- ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10;
-
- card->ext_csd.rel_sectors = ext_csd[EXT_CSD_REL_WR_SEC_C];
-
- /*
- * There are two boot regions of equal size, defined in
- * multiples of 128K.
- */
- if (ext_csd[EXT_CSD_BOOT_MULT] && mmc_boot_partition_access(card->host)) {
- for (idx = 0; idx < MMC_NUM_BOOT_PARTITION; idx++) {
- part_size = ext_csd[EXT_CSD_BOOT_MULT] << 17;
- mmc_part_add(card, part_size,
- EXT_CSD_PART_CONFIG_ACC_BOOT0 + idx,
- "boot%d", idx, true,
- MMC_BLK_DATA_AREA_BOOT);
- }
- }
- }
-
- card->ext_csd.raw_hc_erase_gap_size =
- ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
- card->ext_csd.raw_sec_trim_mult =
- ext_csd[EXT_CSD_SEC_TRIM_MULT];
- card->ext_csd.raw_sec_erase_mult =
- ext_csd[EXT_CSD_SEC_ERASE_MULT];
- card->ext_csd.raw_sec_feature_support =
- ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
- card->ext_csd.raw_trim_mult =
- ext_csd[EXT_CSD_TRIM_MULT];
- if (card->ext_csd.rev >= 4) {
- /*
- * Enhanced area feature support -- check whether the eMMC
- * card has the Enhanced area enabled. If so, export enhanced
- * area offset and size to user by adding sysfs interface.
- */
- card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT];
- if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) &&
- (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) {
- hc_erase_grp_sz =
- ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
- hc_wp_grp_sz =
- ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
-
- card->ext_csd.enhanced_area_en = 1;
- /*
- * calculate the enhanced data area offset, in bytes
- */
- card->ext_csd.enhanced_area_offset =
- (ext_csd[139] << 24) + (ext_csd[138] << 16) +
- (ext_csd[137] << 8) + ext_csd[136];
- if (mmc_card_blockaddr(card))
- card->ext_csd.enhanced_area_offset <<= 9;
- /*
- * calculate the enhanced data area size, in kilobytes
- */
- card->ext_csd.enhanced_area_size =
- (ext_csd[142] << 16) + (ext_csd[141] << 8) +
- ext_csd[140];
- card->ext_csd.enhanced_area_size *=
- (size_t)(hc_erase_grp_sz * hc_wp_grp_sz);
- card->ext_csd.enhanced_area_size <<= 9;
- } else {
- /*
- * If the enhanced area is not enabled, disable these
- * device attributes.
- */
- card->ext_csd.enhanced_area_offset = -EINVAL;
- card->ext_csd.enhanced_area_size = -EINVAL;
- }
-
- /*
- * General purpose partition feature support --
- * If ext_csd has the size of general purpose partitions,
- * set size, part_cfg, partition name in mmc_part.
- */
- if (ext_csd[EXT_CSD_PARTITION_SUPPORT] &
- EXT_CSD_PART_SUPPORT_PART_EN) {
- if (card->ext_csd.enhanced_area_en != 1) {
- hc_erase_grp_sz =
- ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
- hc_wp_grp_sz =
- ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
-
- card->ext_csd.enhanced_area_en = 1;
- }
-
- for (idx = 0; idx < MMC_NUM_GP_PARTITION; idx++) {
- if (!ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3] &&
- !ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] &&
- !ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2])
- continue;
- part_size =
- (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2]
- << 16) +
- (ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1]
- << 8) +
- ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3];
- part_size *= (size_t)(hc_erase_grp_sz *
- hc_wp_grp_sz);
- mmc_part_add(card, part_size << 19,
- EXT_CSD_PART_CONFIG_ACC_GP0 + idx,
- "gp%d", idx, false,
- MMC_BLK_DATA_AREA_GP);
- }
- }
- card->ext_csd.sec_trim_mult =
- ext_csd[EXT_CSD_SEC_TRIM_MULT];
- card->ext_csd.sec_erase_mult =
- ext_csd[EXT_CSD_SEC_ERASE_MULT];
- card->ext_csd.sec_feature_support =
- ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
- card->ext_csd.trim_timeout = 300 *
- ext_csd[EXT_CSD_TRIM_MULT];
-
- /*
- * Note that the call to mmc_part_add above defaults to read
- * only. If this default assumption is changed, the call must
- * take into account the value of boot_locked below.
- */
- card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP];
- card->ext_csd.boot_ro_lockable = true;
- }
-
- if (card->ext_csd.rev >= 5) {
- /* check whether the eMMC card supports HPI */
- if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
- card->ext_csd.hpi = 1;
- if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
- card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION;
- else
- card->ext_csd.hpi_cmd = MMC_SEND_STATUS;
- /*
- * Indicate the maximum timeout to close
- * a command interrupted by HPI
- */
- card->ext_csd.out_of_int_time =
- ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10;
- }
-
- card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
- card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION];
- }
-
- card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT];
- if (ext_csd[EXT_CSD_ERASED_MEM_CONT])
- card->erased_byte = 0xFF;
- else
- card->erased_byte = 0x0;
-
- /* eMMC v4.5 or later */
- if (card->ext_csd.rev >= 6) {
- card->ext_csd.feature_support |= MMC_DISCARD_FEATURE;
-
- card->ext_csd.generic_cmd6_time = 10 *
- ext_csd[EXT_CSD_GENERIC_CMD6_TIME];
- card->ext_csd.power_off_longtime = 10 *
- ext_csd[EXT_CSD_POWER_OFF_LONG_TIME];
-
- card->ext_csd.cache_size =
- ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 |
- ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 |
- ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 |
- ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24;
-
- if (ext_csd[EXT_CSD_DATA_SECTOR_SIZE] == 1)
- card->ext_csd.data_sector_size = 4096;
- else
- card->ext_csd.data_sector_size = 512;
-
- if ((ext_csd[EXT_CSD_DATA_TAG_SUPPORT] & 1) &&
- (ext_csd[EXT_CSD_TAG_UNIT_SIZE] <= 8)) {
- card->ext_csd.data_tag_unit_size =
- ((unsigned int) 1 << ext_csd[EXT_CSD_TAG_UNIT_SIZE]) *
- (card->ext_csd.data_sector_size);
- } else {
- card->ext_csd.data_tag_unit_size = 0;
- }
- }
-
-out:
- return err;
-}
-
-static inline void mmc_free_ext_csd(u8 *ext_csd)
-{
- kfree(ext_csd);
-}
-
-
-static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
-{
- u8 *bw_ext_csd;
- int err;
-
- if (bus_width == MMC_BUS_WIDTH_1)
- return 0;
-
- err = mmc_get_ext_csd(card, &bw_ext_csd);
-
- if (err || bw_ext_csd == NULL) {
- if (bus_width != MMC_BUS_WIDTH_1)
- err = -EINVAL;
- goto out;
- }
-
- if (bus_width == MMC_BUS_WIDTH_1)
- goto out;
-
- /* only compare read only fields */
- err = !((card->ext_csd.raw_partition_support ==
- bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) &&
- (card->ext_csd.raw_erased_mem_count ==
- bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) &&
- (card->ext_csd.rev ==
- bw_ext_csd[EXT_CSD_REV]) &&
- (card->ext_csd.raw_ext_csd_structure ==
- bw_ext_csd[EXT_CSD_STRUCTURE]) &&
- (card->ext_csd.raw_card_type ==
- bw_ext_csd[EXT_CSD_CARD_TYPE]) &&
- (card->ext_csd.raw_s_a_timeout ==
- bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) &&
- (card->ext_csd.raw_hc_erase_gap_size ==
- bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
- (card->ext_csd.raw_erase_timeout_mult ==
- bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) &&
- (card->ext_csd.raw_hc_erase_grp_size ==
- bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
- (card->ext_csd.raw_sec_trim_mult ==
- bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) &&
- (card->ext_csd.raw_sec_erase_mult ==
- bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) &&
- (card->ext_csd.raw_sec_feature_support ==
- bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) &&
- (card->ext_csd.raw_trim_mult ==
- bw_ext_csd[EXT_CSD_TRIM_MULT]) &&
- (card->ext_csd.raw_sectors[0] ==
- bw_ext_csd[EXT_CSD_SEC_CNT + 0]) &&
- (card->ext_csd.raw_sectors[1] ==
- bw_ext_csd[EXT_CSD_SEC_CNT + 1]) &&
- (card->ext_csd.raw_sectors[2] ==
- bw_ext_csd[EXT_CSD_SEC_CNT + 2]) &&
- (card->ext_csd.raw_sectors[3] ==
- bw_ext_csd[EXT_CSD_SEC_CNT + 3]));
- if (err)
- err = -EINVAL;
-
-out:
- mmc_free_ext_csd(bw_ext_csd);
- return err;
-}
-
-MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
- card->raw_cid[2], card->raw_cid[3]);
-MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
- card->raw_csd[2], card->raw_csd[3]);
-MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
-MMC_DEV_ATTR(erase_size, "%u\n", card->erase_size << 9);
-MMC_DEV_ATTR(preferred_erase_size, "%u\n", card->pref_erase << 9);
-MMC_DEV_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
-MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
-MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
-MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
-MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
-MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
-MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
- card->ext_csd.enhanced_area_offset);
-MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
-
-static struct attribute *mmc_std_attrs[] = {
- &dev_attr_cid.attr,
- &dev_attr_csd.attr,
- &dev_attr_date.attr,
- &dev_attr_erase_size.attr,
- &dev_attr_preferred_erase_size.attr,
- &dev_attr_fwrev.attr,
- &dev_attr_hwrev.attr,
- &dev_attr_manfid.attr,
- &dev_attr_name.attr,
- &dev_attr_oemid.attr,
- &dev_attr_serial.attr,
- &dev_attr_enhanced_area_offset.attr,
- &dev_attr_enhanced_area_size.attr,
- NULL,
-};
-
-static struct attribute_group mmc_std_attr_group = {
- .attrs = mmc_std_attrs,
-};
-
-static const struct attribute_group *mmc_attr_groups[] = {
- &mmc_std_attr_group,
- NULL,
-};
-
-static struct device_type mmc_type = {
- .groups = mmc_attr_groups,
-};
-
-/*
- * Select the PowerClass for the current bus width
- * If power class is defined for 4/8 bit bus in the
- * extended CSD register, select it by executing the
- * mmc_switch command.
- */
-static int mmc_select_powerclass(struct mmc_card *card,
- unsigned int bus_width, u8 *ext_csd)
-{
- int err = 0;
- unsigned int pwrclass_val;
- unsigned int index = 0;
- struct mmc_host *host;
-
- BUG_ON(!card);
-
- host = card->host;
- BUG_ON(!host);
-
- if (ext_csd == NULL)
- return 0;
-
- /* Power class selection is supported for versions >= 4.0 */
- if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
- return 0;
-
- /* Power class values are defined only for 4/8 bit bus */
- if (bus_width == EXT_CSD_BUS_WIDTH_1)
- return 0;
-
- switch (1 << host->ios.vdd) {
- case MMC_VDD_165_195:
- if (host->ios.clock <= 26000000)
- index = EXT_CSD_PWR_CL_26_195;
- else if (host->ios.clock <= 52000000)
- index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
- EXT_CSD_PWR_CL_52_195 :
- EXT_CSD_PWR_CL_DDR_52_195;
- else if (host->ios.clock <= 200000000)
- index = EXT_CSD_PWR_CL_200_195;
- break;
- case MMC_VDD_27_28:
- case MMC_VDD_28_29:
- case MMC_VDD_29_30:
- case MMC_VDD_30_31:
- case MMC_VDD_31_32:
- case MMC_VDD_32_33:
- case MMC_VDD_33_34:
- case MMC_VDD_34_35:
- case MMC_VDD_35_36:
- if (host->ios.clock <= 26000000)
- index = EXT_CSD_PWR_CL_26_360;
- else if (host->ios.clock <= 52000000)
- index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
- EXT_CSD_PWR_CL_52_360 :
- EXT_CSD_PWR_CL_DDR_52_360;
- else if (host->ios.clock <= 200000000)
- index = EXT_CSD_PWR_CL_200_360;
- break;
- default:
- pr_warning("%s: Voltage range not supported "
- "for power class.\n", mmc_hostname(host));
- return -EINVAL;
- }
-
- pwrclass_val = ext_csd[index];
-
- if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8))
- pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >>
- EXT_CSD_PWR_CL_8BIT_SHIFT;
- else
- pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_4BIT_MASK) >>
- EXT_CSD_PWR_CL_4BIT_SHIFT;
-
- /* If the power class is different from the default value */
- if (pwrclass_val > 0) {
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_POWER_CLASS,
- pwrclass_val,
- card->ext_csd.generic_cmd6_time);
- }
-
- return err;
-}
-
-/*
- * Selects the desired buswidth and switch to the HS200 mode
- * if bus width set without error
- */
-static int mmc_select_hs200(struct mmc_card *card)
-{
- int idx, err = 0;
- struct mmc_host *host;
- static unsigned ext_csd_bits[] = {
- EXT_CSD_BUS_WIDTH_4,
- EXT_CSD_BUS_WIDTH_8,
- };
- static unsigned bus_widths[] = {
- MMC_BUS_WIDTH_4,
- MMC_BUS_WIDTH_8,
- };
-
- BUG_ON(!card);
-
- host = card->host;
-
- if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
- host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
- if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0))
- err = mmc_set_signal_voltage(host,
- MMC_SIGNAL_VOLTAGE_180, 0);
-
- /* If fails try again during next card power cycle */
- if (err)
- goto err;
-
- idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
-
- /*
- * Unlike SD, MMC cards dont have a configuration register to notify
- * supported bus width. So bus test command should be run to identify
- * the supported bus width or compare the ext csd values of current
- * bus width and ext csd values of 1 bit mode read earlier.
- */
- for (; idx >= 0; idx--) {
-
- /*
- * Host is capable of 8bit transfer, then switch
- * the device to work in 8bit transfer mode. If the
- * mmc switch command returns error then switch to
- * 4bit transfer mode. On success set the corresponding
- * bus width on the host.
- */
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BUS_WIDTH,
- ext_csd_bits[idx],
- card->ext_csd.generic_cmd6_time);
- if (err)
- continue;
-
- mmc_set_bus_width(card->host, bus_widths[idx]);
-
- if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
- err = mmc_compare_ext_csds(card, bus_widths[idx]);
- else
- err = mmc_bus_test(card, bus_widths[idx]);
- if (!err)
- break;
- }
-
- /* switch to HS200 mode if bus width set successfully */
- if (!err)
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_HS_TIMING, 2, 0);
-err:
- return err;
-}
-
-/*
- * Handle the detection and initialisation of a card.
- *
- * In the case of a resume, "oldcard" will contain the card
- * we're trying to reinitialise.
- */
-static int mmc_init_card(struct mmc_host *host, u32 ocr,
- struct mmc_card *oldcard)
-{
- struct mmc_card *card;
- int err, ddr = 0;
- u32 cid[4];
- unsigned int max_dtr;
- u32 rocr;
- u8 *ext_csd = NULL;
-
- BUG_ON(!host);
- WARN_ON(!host->claimed);
-
- /* Set correct bus mode for MMC before attempting init */
- if (!mmc_host_is_spi(host))
- mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN);
-
- /* Initialization should be done at 3.3 V I/O voltage. */
- mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
-
- /*
- * Since we're changing the OCR value, we seem to
- * need to tell some cards to go back to the idle
- * state. We wait 1ms to give cards time to
- * respond.
- * mmc_go_idle is needed for eMMC that are asleep
- */
- mmc_go_idle(host);
-
- /* The extra bit indicates that we support high capacity */
- err = mmc_send_op_cond(host, ocr | (1 << 30), &rocr);
- if (err)
- goto err;
-
- /*
- * For SPI, enable CRC as appropriate.
- */
- if (mmc_host_is_spi(host)) {
- err = mmc_spi_set_crc(host, use_spi_crc);
- if (err)
- goto err;
- }
-
- /*
- * Fetch CID from card.
- */
- if (mmc_host_is_spi(host))
- err = mmc_send_cid(host, cid);
- else
- err = mmc_all_send_cid(host, cid);
- if (err)
- goto err;
-
- if (oldcard) {
- if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) {
- err = -ENOENT;
- goto err;
- }
-
- card = oldcard;
- } else {
- /*
- * Allocate card structure.
- */
- card = mmc_alloc_card(host, &mmc_type);
- if (IS_ERR(card)) {
- err = PTR_ERR(card);
- goto err;
- }
-
- card->type = MMC_TYPE_MMC;
- card->rca = 1;
- memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
- }
-
- /*
- * For native busses: set card RCA and quit open drain mode.
- */
- if (!mmc_host_is_spi(host)) {
- err = mmc_set_relative_addr(card);
- if (err)
- goto free_card;
-
- mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
- }
-
- if (!oldcard) {
- /*
- * Fetch CSD from card.
- */
- err = mmc_send_csd(card, card->raw_csd);
- if (err)
- goto free_card;
-
- err = mmc_decode_csd(card);
- if (err)
- goto free_card;
- err = mmc_decode_cid(card);
- if (err)
- goto free_card;
- }
-
- /*
- * Select card, as all following commands rely on that.
- */
- if (!mmc_host_is_spi(host)) {
- err = mmc_select_card(card);
- if (err)
- goto free_card;
- }
-
- if (!oldcard) {
- /*
- * Fetch and process extended CSD.
- */
-
- err = mmc_get_ext_csd(card, &ext_csd);
- if (err)
- goto free_card;
- err = mmc_read_ext_csd(card, ext_csd);
- if (err)
- goto free_card;
-
- /* If doing byte addressing, check if required to do sector
- * addressing. Handle the case of <2GB cards needing sector
- * addressing. See section 8.1 JEDEC Standard JED84-A441;
- * ocr register has bit 30 set for sector addressing.
- */
- if (!(mmc_card_blockaddr(card)) && (rocr & (1<<30)))
- mmc_card_set_blockaddr(card);
-
- /* Erase size depends on CSD and Extended CSD */
- mmc_set_erase_size(card);
- }
-
- /*
- * If enhanced_area_en is TRUE, host needs to enable ERASE_GRP_DEF
- * bit. This bit will be lost every time after a reset or power off.
- */
- if (card->ext_csd.enhanced_area_en ||
- (card->ext_csd.rev >= 3 && (host->caps2 & MMC_CAP2_HC_ERASE_SZ))) {
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_ERASE_GROUP_DEF, 1,
- card->ext_csd.generic_cmd6_time);
-
- if (err && err != -EBADMSG)
- goto free_card;
-
- if (err) {
- err = 0;
- /*
- * Just disable enhanced area off & sz
- * will try to enable ERASE_GROUP_DEF
- * during next time reinit
- */
- card->ext_csd.enhanced_area_offset = -EINVAL;
- card->ext_csd.enhanced_area_size = -EINVAL;
- } else {
- card->ext_csd.erase_group_def = 1;
- /*
- * enable ERASE_GRP_DEF successfully.
- * This will affect the erase size, so
- * here need to reset erase size
- */
- mmc_set_erase_size(card);
- }
- }
-
- /*
- * Ensure eMMC user default partition is enabled
- */
- if (card->ext_csd.part_config & EXT_CSD_PART_CONFIG_ACC_MASK) {
- card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG,
- card->ext_csd.part_config,
- card->ext_csd.part_time);
- if (err && err != -EBADMSG)
- goto free_card;
- }
-
- /*
- * If the host supports the power_off_notify capability then
- * set the notification byte in the ext_csd register of device
- */
- if ((host->caps2 & MMC_CAP2_POWEROFF_NOTIFY) &&
- (card->ext_csd.rev >= 6)) {
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_POWER_OFF_NOTIFICATION,
- EXT_CSD_POWER_ON,
- card->ext_csd.generic_cmd6_time);
- if (err && err != -EBADMSG)
- goto free_card;
-
- /*
- * The err can be -EBADMSG or 0,
- * so check for success and update the flag
- */
- if (!err)
- card->poweroff_notify_state = MMC_POWERED_ON;
- }
-
- /*
- * Activate high speed (if supported)
- */
- if (card->ext_csd.hs_max_dtr != 0) {
- err = 0;
- if (card->ext_csd.hs_max_dtr > 52000000 &&
- host->caps2 & MMC_CAP2_HS200)
- err = mmc_select_hs200(card);
- else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_HS_TIMING, 1,
- card->ext_csd.generic_cmd6_time);
-
- if (err && err != -EBADMSG)
- goto free_card;
-
- if (err) {
- pr_warning("%s: switch to highspeed failed\n",
- mmc_hostname(card->host));
- err = 0;
- } else {
- if (card->ext_csd.hs_max_dtr > 52000000 &&
- host->caps2 & MMC_CAP2_HS200) {
- mmc_card_set_hs200(card);
- mmc_set_timing(card->host,
- MMC_TIMING_MMC_HS200);
- } else {
- mmc_card_set_highspeed(card);
- mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
- }
- }
- }
-
- /*
- * Compute bus speed.
- */
- max_dtr = (unsigned int)-1;
-
- if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
- if (max_dtr > card->ext_csd.hs_max_dtr)
- max_dtr = card->ext_csd.hs_max_dtr;
- } else if (max_dtr > card->csd.max_dtr) {
- max_dtr = card->csd.max_dtr;
- }
-
- mmc_set_clock(host, max_dtr);
-
- /*
- * Indicate DDR mode (if supported).
- */
- if (mmc_card_highspeed(card)) {
- if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
- && ((host->caps & (MMC_CAP_1_8V_DDR |
- MMC_CAP_UHS_DDR50))
- == (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50)))
- 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 |
- MMC_CAP_UHS_DDR50))
- == (MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50)))
- ddr = MMC_1_2V_DDR_MODE;
- }
-
- /*
- * Indicate HS200 SDR mode (if supported).
- */
- if (mmc_card_hs200(card)) {
- u32 ext_csd_bits;
- u32 bus_width = card->host->ios.bus_width;
-
- /*
- * For devices supporting HS200 mode, the bus width has
- * to be set before executing the tuning function. If
- * set before tuning, then device will respond with CRC
- * errors for responses on CMD line. So for HS200 the
- * sequence will be
- * 1. set bus width 4bit / 8 bit (1 bit not supported)
- * 2. switch to HS200 mode
- * 3. set the clock to > 52Mhz <=200MHz and
- * 4. execute tuning for HS200
- */
- if ((host->caps2 & MMC_CAP2_HS200) &&
- card->host->ops->execute_tuning) {
- mmc_host_clk_hold(card->host);
- err = card->host->ops->execute_tuning(card->host,
- MMC_SEND_TUNING_BLOCK_HS200);
- mmc_host_clk_release(card->host);
- }
- if (err) {
- pr_warning("%s: tuning execution failed\n",
- mmc_hostname(card->host));
- goto err;
- }
-
- ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
- EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
- err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
- if (err)
- pr_warning("%s: power class selection to bus width %d"
- " failed\n", mmc_hostname(card->host),
- 1 << bus_width);
- }
-
- /*
- * Activate wide bus and DDR (if supported).
- */
- if (!mmc_card_hs200(card) &&
- (card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
- (host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
- static unsigned ext_csd_bits[][2] = {
- { EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
- { EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
- { EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
- };
- static unsigned bus_widths[] = {
- MMC_BUS_WIDTH_8,
- MMC_BUS_WIDTH_4,
- MMC_BUS_WIDTH_1
- };
- unsigned idx, bus_width = 0;
-
- if (host->caps & MMC_CAP_8_BIT_DATA)
- idx = 0;
- else
- idx = 1;
- for (; idx < ARRAY_SIZE(bus_widths); idx++) {
- bus_width = bus_widths[idx];
- if (bus_width == MMC_BUS_WIDTH_1)
- ddr = 0; /* no DDR for 1-bit width */
- err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
- ext_csd);
- if (err)
- pr_warning("%s: power class selection to "
- "bus width %d failed\n",
- mmc_hostname(card->host),
- 1 << bus_width);
-
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BUS_WIDTH,
- ext_csd_bits[idx][0],
- card->ext_csd.generic_cmd6_time);
- if (!err) {
- mmc_set_bus_width(card->host, bus_width);
-
- /*
- * If controller can't handle bus width test,
- * compare ext_csd previously read in 1 bit mode
- * against ext_csd at new bus width
- */
- if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
- err = mmc_compare_ext_csds(card,
- bus_width);
- else
- err = mmc_bus_test(card, bus_width);
- if (!err)
- break;
- }
- }
-
- if (!err && ddr) {
- err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
- ext_csd);
- if (err)
- pr_warning("%s: power class selection to "
- "bus width %d ddr %d failed\n",
- mmc_hostname(card->host),
- 1 << bus_width, ddr);
-
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BUS_WIDTH,
- ext_csd_bits[idx][1],
- card->ext_csd.generic_cmd6_time);
- }
- if (err) {
- pr_warning("%s: switch to bus width %d ddr %d "
- "failed\n", mmc_hostname(card->host),
- 1 << bus_width, ddr);
- goto free_card;
- } else if (ddr) {
- /*
- * eMMC cards can support 3.3V to 1.2V i/o (vccq)
- * signaling.
- *
- * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
- *
- * 1.8V vccq at 3.3V core voltage (vcc) is not required
- * in the JEDEC spec for DDR.
- *
- * Do not force change in vccq since we are obviously
- * working and no change to vccq is needed.
- *
- * WARNING: eMMC rules are NOT the same as SD DDR
- */
- if (ddr == MMC_1_2V_DDR_MODE) {
- err = mmc_set_signal_voltage(host,
- MMC_SIGNAL_VOLTAGE_120, 0);
- if (err)
- goto err;
- }
- mmc_card_set_ddr_mode(card);
- mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
- mmc_set_bus_width(card->host, bus_width);
- }
- }
-
- /*
- * Enable HPI feature (if supported)
- */
- if (card->ext_csd.hpi) {
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_HPI_MGMT, 1,
- card->ext_csd.generic_cmd6_time);
- if (err && err != -EBADMSG)
- goto free_card;
- if (err) {
- pr_warning("%s: Enabling HPI failed\n",
- mmc_hostname(card->host));
- err = 0;
- } else
- card->ext_csd.hpi_en = 1;
- }
-
- /*
- * If cache size is higher than 0, this indicates
- * the existence of cache and it can be turned on.
- */
- if ((host->caps2 & MMC_CAP2_CACHE_CTRL) &&
- card->ext_csd.cache_size > 0) {
- err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_CACHE_CTRL, 1,
- card->ext_csd.generic_cmd6_time);
- if (err && err != -EBADMSG)
- goto free_card;
-
- /*
- * Only if no error, cache is turned on successfully.
- */
- if (err) {
- pr_warning("%s: Cache is supported, "
- "but failed to turn on (%d)\n",
- mmc_hostname(card->host), err);
- card->ext_csd.cache_ctrl = 0;
- err = 0;
- } else {
- card->ext_csd.cache_ctrl = 1;
- }
- }
-
- if (!oldcard)
- host->card = card;
-
- mmc_free_ext_csd(ext_csd);
- return 0;
-
-free_card:
- if (!oldcard)
- mmc_remove_card(card);
-err:
- mmc_free_ext_csd(ext_csd);
-
- return err;
-}
-
-/*
- * Host is being removed. Free up the current card.
- */
-static void mmc_remove(struct mmc_host *host)
-{
- BUG_ON(!host);
- BUG_ON(!host->card);
-
- mmc_remove_card(host->card);
- host->card = NULL;
-}
-
-/*
- * Card detection - card is alive.
- */
-static int mmc_alive(struct mmc_host *host)
-{
- return mmc_send_status(host->card, NULL);
-}
-
-/*
- * Card detection callback from host.
- */
-static void mmc_detect(struct mmc_host *host)
-{
- int err;
-
- BUG_ON(!host);
- BUG_ON(!host->card);
-
- mmc_claim_host(host);
-
- /*
- * Just check if our card has been removed.
- */
- err = _mmc_detect_card_removed(host);
-
- mmc_release_host(host);
-#ifdef CONFIG_MMC_UNSAFE_RESUME
- if (err || (host->card_attath_status == card_attach_status_change)) {
- host->card_attath_status = card_attach_status_unchange;
- mmc_remove(host);
-
- mmc_claim_host(host);
- mmc_detach_bus(host);
- mmc_power_off(host);
- mmc_release_host(host);
- }
-#else
- if (err) {
- mmc_remove(host);
-
- mmc_claim_host(host);
- mmc_detach_bus(host);
- mmc_power_off(host);
- mmc_release_host(host);
- }
-#endif
-}
-
-/*
- * Suspend callback from host.
- */
-static int mmc_suspend(struct mmc_host *host)
-{
- int err = 0;
-
- BUG_ON(!host);
- BUG_ON(!host->card);
-
- mmc_claim_host(host);
- if (mmc_card_can_sleep(host)) {
- err = mmc_card_sleep(host);
- if (!err)
- mmc_card_set_sleep(host->card);
- } else if (!mmc_host_is_spi(host))
- mmc_deselect_cards(host);
- host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
- mmc_release_host(host);
-
- return err;
-}
-
-/*
- * Resume callback from host.
- *
- * This function tries to determine if the same card is still present
- * and, if so, restore all state to it.
- */
-static int mmc_resume(struct mmc_host *host)
-{
- int err;
-
- BUG_ON(!host);
- BUG_ON(!host->card);
-
- mmc_claim_host(host);
- if (mmc_card_is_sleep(host->card)) {
- err = mmc_card_awake(host);
- mmc_card_clr_sleep(host->card);
- } else
- err = mmc_init_card(host, host->ocr, host->card);
- mmc_release_host(host);
-
-#ifdef CONFIG_MMC_UNSAFE_RESUME
- if (err)
- host->card_attath_status = card_attach_status_change;
-#endif
-
- return err;
-}
-
-static int mmc_power_restore(struct mmc_host *host)
-{
- int ret;
-
- host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
- mmc_card_clr_sleep(host->card);
- mmc_claim_host(host);
- ret = mmc_init_card(host, host->ocr, host->card);
- mmc_release_host(host);
-
- return ret;
-}
-
-static int mmc_sleep(struct mmc_host *host)
-{
- struct mmc_card *card = host->card;
- int err = -ENOSYS;
-
- if (card && card->ext_csd.rev >= 3) {
- err = mmc_card_sleepawake(host, 1);
- if (err < 0)
- pr_debug("%s: Error %d while putting card into sleep",
- mmc_hostname(host), err);
- }
-
- return err;
-}
-
-static int mmc_awake(struct mmc_host *host)
-{
- struct mmc_card *card = host->card;
- int err = -ENOSYS;
-
- if (card && card->ext_csd.rev >= 3) {
- err = mmc_card_sleepawake(host, 0);
- if (err < 0)
- pr_debug("%s: Error %d while awaking sleeping card",
- mmc_hostname(host), err);
- }
-
- return err;
-}
-
-static const struct mmc_bus_ops mmc_ops = {
- .awake = mmc_awake,
- .sleep = mmc_sleep,
- .remove = mmc_remove,
- .detect = mmc_detect,
- .suspend = NULL,
- .resume = NULL,
- .power_restore = mmc_power_restore,
- .alive = mmc_alive,
-};
-
-static const struct mmc_bus_ops mmc_ops_unsafe = {
- .awake = mmc_awake,
- .sleep = mmc_sleep,
- .remove = mmc_remove,
- .detect = mmc_detect,
- .suspend = mmc_suspend,
- .resume = mmc_resume,
- .power_restore = mmc_power_restore,
- .alive = mmc_alive,
-};
-
-static void mmc_attach_bus_ops(struct mmc_host *host)
-{
- const struct mmc_bus_ops *bus_ops;
-
- if (!mmc_card_is_removable(host))
- bus_ops = &mmc_ops_unsafe;
- else
- bus_ops = &mmc_ops;
- mmc_attach_bus(host, bus_ops);
-}
-
-/*
- * Starting point for MMC card init.
- */
-int mmc_attach_mmc(struct mmc_host *host)
-{
- int err;
- u32 ocr;
-
- BUG_ON(!host);
- WARN_ON(!host->claimed);
-
- /* Set correct bus mode for MMC before attempting attach */
- if (!mmc_host_is_spi(host))
- mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN);
-
- err = mmc_send_op_cond(host, 0, &ocr);
- if (err)
- return err;
-
- mmc_attach_bus_ops(host);
- if (host->ocr_avail_mmc)
- host->ocr_avail = host->ocr_avail_mmc;
-
- /*
- * We need to get OCR a different way for SPI.
- */
- if (mmc_host_is_spi(host)) {
- err = mmc_spi_read_ocr(host, 1, &ocr);
- if (err)
- goto err;
- }
-
- /*
- * Sanity check the voltages that the card claims to
- * support.
- */
- if (ocr & 0x7F) {
- pr_warning("%s: card claims to support voltages "
- "below the defined range. These will be ignored.\n",
- mmc_hostname(host));
- ocr &= ~0x7F;
- }
-
- host->ocr = mmc_select_voltage(host, ocr);
-
- /*
- * Can we support the voltage of the card?
- */
- if (!host->ocr) {
- err = -EINVAL;
- goto err;
- }
-
- /*
- * Detect and init the card.
- */
- err = mmc_init_card(host, host->ocr, NULL);
- if (err)
- goto err;
-
- mmc_release_host(host);
- err = mmc_add_card(host->card);
- mmc_claim_host(host);
- if (err)
- goto remove_card;
-
- return 0;
-
-remove_card:
- mmc_release_host(host);
- mmc_remove_card(host->card);
- mmc_claim_host(host);
- host->card = NULL;
-err:
- mmc_detach_bus(host);
-
- pr_err("%s: error %d whilst initialising MMC card\n",
- mmc_hostname(host), err);
-
- return err;
-}
diff --git a/ANDROID_3.4.5/drivers/mmc/core/mmc_ops.c b/ANDROID_3.4.5/drivers/mmc/core/mmc_ops.c
deleted file mode 100644
index cdd16e5e..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/mmc_ops.c
+++ /dev/null
@@ -1,591 +0,0 @@
-/*
- * linux/drivers/mmc/core/mmc_ops.h
- *
- * Copyright 2006-2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <linux/types.h>
-#include <linux/scatterlist.h>
-
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/mmc.h>
-
-#include "core.h"
-#include "mmc_ops.h"
-
-static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
-{
- int err;
- struct mmc_command cmd = {0};
-
- BUG_ON(!host);
-
- cmd.opcode = MMC_SELECT_CARD;
-
- if (card) {
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- } else {
- cmd.arg = 0;
- cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
- }
-
- err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
- if (err)
- return err;
-
- return 0;
-}
-
-int mmc_select_card(struct mmc_card *card)
-{
- BUG_ON(!card);
-
- return _mmc_select_card(card->host, card);
-}
-
-int mmc_deselect_cards(struct mmc_host *host)
-{
- return _mmc_select_card(host, NULL);
-}
-
-int mmc_card_sleepawake(struct mmc_host *host, int sleep)
-{
- struct mmc_command cmd = {0};
- struct mmc_card *card = host->card;
- int err;
-
- if (sleep)
- mmc_deselect_cards(host);
-
- cmd.opcode = MMC_SLEEP_AWAKE;
- cmd.arg = card->rca << 16;
- if (sleep)
- cmd.arg |= 1 << 15;
-
- cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
- err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err)
- return err;
-
- /*
- * If the host does not wait while the card signals busy, then we will
- * will have to wait the sleep/awake timeout. Note, we cannot use the
- * SEND_STATUS command to poll the status because that command (and most
- * others) is invalid while the card sleeps.
- */
- if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
- mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000));
-
- if (!sleep)
- err = mmc_select_card(card);
-
- return err;
-}
-
-int mmc_go_idle(struct mmc_host *host)
-{
- int err;
- struct mmc_command cmd = {0};
-
- /*
- * Non-SPI hosts need to prevent chipselect going active during
- * GO_IDLE; that would put chips into SPI mode. Remind them of
- * that in case of hardware that won't pull up DAT3/nCS otherwise.
- *
- * SPI hosts ignore ios.chip_select; it's managed according to
- * rules that must accommodate non-MMC slaves which this layer
- * won't even know about.
- */
- if (!mmc_host_is_spi(host)) {
- mmc_set_chip_select(host, MMC_CS_HIGH);
- mmc_delay(1);
- }
-
- cmd.opcode = MMC_GO_IDLE_STATE;
- cmd.arg = 0;
- //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
- cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
-
- err = mmc_wait_for_cmd(host, &cmd, 0);
-
- mmc_delay(1);
-
- if (!mmc_host_is_spi(host)) {
- mmc_set_chip_select(host, MMC_CS_DONTCARE);
- mmc_delay(1);
- }
-
- host->use_spi_crc = 0;
-
- return err;
-}
-
-int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
-{
- struct mmc_command cmd = {0};
- int i, err = 0;
-
- BUG_ON(!host);
-
- cmd.opcode = MMC_SEND_OP_COND;
- cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
- //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
- cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
-
- for (i = 100; i; i--) {
- err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err)
- break;
-
- /* if we're just probing, do a single pass */
- if (ocr == 0)
- break;
-
- /* otherwise wait until reset completes */
- if (mmc_host_is_spi(host)) {
- if (!(cmd.resp[0] & R1_SPI_IDLE))
- break;
- } else {
- if (cmd.resp[0] & MMC_CARD_BUSY)
- break;
- }
-
- err = -ETIMEDOUT;
-
- mmc_delay(10);
- }
-
- if (rocr && !mmc_host_is_spi(host))
- *rocr = cmd.resp[0];
-
- return err;
-}
-
-int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
-{
- int err;
- struct mmc_command cmd = {0};
-
- BUG_ON(!host);
- BUG_ON(!cid);
-
- cmd.opcode = MMC_ALL_SEND_CID;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
-
- err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
- if (err)
- return err;
-
- memcpy(cid, cmd.resp, sizeof(u32) * 4);
-
- return 0;
-}
-
-int mmc_set_relative_addr(struct mmc_card *card)
-{
- int err;
- struct mmc_command cmd = {0};
-
- BUG_ON(!card);
- BUG_ON(!card->host);
-
- cmd.opcode = MMC_SET_RELATIVE_ADDR;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
- if (err)
- return err;
-
- return 0;
-}
-
-static int
-mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
-{
- int err;
- struct mmc_command cmd = {0};
-
- BUG_ON(!host);
- BUG_ON(!cxd);
-
- cmd.opcode = opcode;
- cmd.arg = arg;
- cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
- if (err)
- return err;
-
- memcpy(cxd, cmd.resp, sizeof(u32) * 4);
-
- return 0;
-}
-
-static int
-mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
- u32 opcode, void *buf, unsigned len)
-{
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
- struct scatterlist sg;
- void *data_buf;
-
- /* dma onto stack is unsafe/nonportable, but callers to this
- * routine normally provide temporary on-stack buffers ...
- */
- data_buf = kmalloc(len, GFP_KERNEL);
- if (data_buf == NULL)
- return -ENOMEM;
-
- mrq.cmd = &cmd;
- mrq.data = &data;
-
- cmd.opcode = opcode;
- cmd.arg = 0;
-
- /* NOTE HACK: the MMC_RSP_SPI_R1 is always correct here, but we
- * rely on callers to never use this with "native" calls for reading
- * CSD or CID. Native versions of those commands use the R2 type,
- * not R1 plus a data block.
- */
- //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
- data.blksz = len;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-
- sg_init_one(&sg, data_buf, len);
-
- if (opcode == MMC_SEND_CSD || opcode == MMC_SEND_CID) {
- /*
- * The spec states that CSR and CID accesses have a timeout
- * of 64 clock cycles.
- */
- data.timeout_ns = 0;
- data.timeout_clks = 64;
- } else
- mmc_set_data_timeout(&data, card);
-
- mmc_wait_for_req(host, &mrq);
-
- memcpy(buf, data_buf, len);
- kfree(data_buf);
-
- if (cmd.error)
- return cmd.error;
- if (data.error)
- return data.error;
-
- return 0;
-}
-
-int mmc_send_csd(struct mmc_card *card, u32 *csd)
-{
- int ret, i;
-
- if (!mmc_host_is_spi(card->host))
- return mmc_send_cxd_native(card->host, card->rca << 16,
- csd, MMC_SEND_CSD);
-
- ret = mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd, 16);
- if (ret)
- return ret;
-
- for (i = 0;i < 4;i++)
- csd[i] = be32_to_cpu(csd[i]);
-
- return 0;
-}
-
-int mmc_send_cid(struct mmc_host *host, u32 *cid)
-{
- int ret, i;
-
- if (!mmc_host_is_spi(host)) {
- if (!host->card)
- return -EINVAL;
- return mmc_send_cxd_native(host, host->card->rca << 16,
- cid, MMC_SEND_CID);
- }
-
- ret = mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid, 16);
- if (ret)
- return ret;
-
- for (i = 0;i < 4;i++)
- cid[i] = be32_to_cpu(cid[i]);
-
- return 0;
-}
-
-int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
-{
- return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD,
- ext_csd, 512);
-}
-
-int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
-{
- struct mmc_command cmd = {0};
- int err;
-
- cmd.opcode = MMC_SPI_READ_OCR;
- cmd.arg = highcap ? (1 << 30) : 0;
- cmd.flags = MMC_RSP_SPI_R3;
-
- err = mmc_wait_for_cmd(host, &cmd, 0);
-
- *ocrp = cmd.resp[1];
- return err;
-}
-
-int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
-{
- struct mmc_command cmd = {0};
- int err;
-
- cmd.opcode = MMC_SPI_CRC_ON_OFF;
- cmd.flags = MMC_RSP_SPI_R1;
- cmd.arg = use_crc;
-
- err = mmc_wait_for_cmd(host, &cmd, 0);
- if (!err)
- host->use_spi_crc = use_crc;
- return err;
-}
-
-/**
- * mmc_switch - modify EXT_CSD register
- * @card: the MMC card associated with the data transfer
- * @set: cmd set values
- * @index: EXT_CSD register index
- * @value: value to program into EXT_CSD register
- * @timeout_ms: timeout (ms) for operation performed by register write,
- * timeout of zero implies maximum possible timeout
- *
- * Modifies the EXT_CSD register for selected card.
- */
-int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
- unsigned int timeout_ms)
-{
- int err;
- struct mmc_command cmd = {0};
- u32 status;
-
- BUG_ON(!card);
- BUG_ON(!card->host);
-
- cmd.opcode = MMC_SWITCH;
- cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
- (index << 16) |
- (value << 8) |
- set;
- //cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
- cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
- cmd.cmd_timeout_ms = timeout_ms;
-
- err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
- if (err)
- return err;
-
- /* Must check status to be sure of no errors */
- do {
- err = mmc_send_status(card, &status);
- if (err)
- return err;
- if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
- break;
- if (mmc_host_is_spi(card->host))
- break;
- } while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
-
- if (mmc_host_is_spi(card->host)) {
- if (status & R1_SPI_ILLEGAL_COMMAND)
- return -EBADMSG;
- } else {
- if (status & 0xFDFFA000)
- pr_warning("%s: unexpected status %#x after "
- "switch", mmc_hostname(card->host), status);
- if (status & R1_SWITCH_ERROR)
- return -EBADMSG;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(mmc_switch);
-
-int mmc_send_status(struct mmc_card *card, u32 *status)
-{
- int err;
- struct mmc_command cmd = {0};
-
- BUG_ON(!card);
- BUG_ON(!card->host);
-
- cmd.opcode = MMC_SEND_STATUS;
- if (!mmc_host_is_spi(card->host))
- cmd.arg = card->rca << 16;
- //cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
- if (err)
- return err;
-
- /* NOTE: callers are required to understand the difference
- * between "native" and SPI format status words!
- */
- if (status)
- *status = cmd.resp[0];
-
- return 0;
-}
-
-static int
-mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
- u8 len)
-{
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
- struct scatterlist sg;
- u8 *data_buf;
- u8 *test_buf;
- int i, err;
- static u8 testdata_8bit[8] = { 0x55, 0xaa, 0, 0, 0, 0, 0, 0 };
- static u8 testdata_4bit[4] = { 0x5a, 0, 0, 0 };
-
- /* dma onto stack is unsafe/nonportable, but callers to this
- * routine normally provide temporary on-stack buffers ...
- */
- data_buf = kmalloc(len, GFP_KERNEL);
- if (!data_buf)
- return -ENOMEM;
-
- if (len == 8)
- test_buf = testdata_8bit;
- else if (len == 4)
- test_buf = testdata_4bit;
- else {
- pr_err("%s: Invalid bus_width %d\n",
- mmc_hostname(host), len);
- kfree(data_buf);
- return -EINVAL;
- }
-
- if (opcode == MMC_BUS_TEST_W)
- memcpy(data_buf, test_buf, len);
-
- mrq.cmd = &cmd;
- mrq.data = &data;
- cmd.opcode = opcode;
- cmd.arg = 0;
-
- /* NOTE HACK: the MMC_RSP_SPI_R1 is always correct here, but we
- * rely on callers to never use this with "native" calls for reading
- * CSD or CID. Native versions of those commands use the R2 type,
- * not R1 plus a data block.
- */
- //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
- data.blksz = len;
- data.blocks = 1;
- if (opcode == MMC_BUS_TEST_R)
- data.flags = MMC_DATA_READ;
- else
- data.flags = MMC_DATA_WRITE;
-
- data.sg = &sg;
- data.sg_len = 1;
- sg_init_one(&sg, data_buf, len);
- mmc_wait_for_req(host, &mrq);
- err = 0;
- if (opcode == MMC_BUS_TEST_R) {
- for (i = 0; i < len / 4; i++)
- if ((test_buf[i] ^ data_buf[i]) != 0xff) {
- err = -EIO;
- break;
- }
- }
- kfree(data_buf);
-
- if (cmd.error)
- return cmd.error;
- if (data.error)
- return data.error;
-
- return err;
-}
-
-int mmc_bus_test(struct mmc_card *card, u8 bus_width)
-{
- int err, width;
-
- if (bus_width == MMC_BUS_WIDTH_8)
- width = 8;
- else if (bus_width == MMC_BUS_WIDTH_4)
- width = 4;
- else if (bus_width == MMC_BUS_WIDTH_1)
- return 0; /* no need for test */
- else
- return -EINVAL;
-
- /*
- * Ignore errors from BUS_TEST_W. BUS_TEST_R will fail if there
- * is a problem. This improves chances that the test will work.
- */
- mmc_send_bus_test(card, card->host, MMC_BUS_TEST_W, width);
- err = mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width);
- return err;
-}
-
-int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
-{
- struct mmc_command cmd = {0};
- unsigned int opcode;
- int err;
-
- if (!card->ext_csd.hpi) {
- pr_warning("%s: Card didn't support HPI command\n",
- mmc_hostname(card->host));
- return -EINVAL;
- }
-
- opcode = card->ext_csd.hpi_cmd;
- if (opcode == MMC_STOP_TRANSMISSION)
- cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
- else if (opcode == MMC_SEND_STATUS)
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
- cmd.opcode = opcode;
- cmd.arg = card->rca << 16 | 1;
- cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time;
-
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
- if (err) {
- pr_warn("%s: error %d interrupting operation. "
- "HPI command response %#x\n", mmc_hostname(card->host),
- err, cmd.resp[0]);
- return err;
- }
- if (status)
- *status = cmd.resp[0];
-
- return 0;
-}
diff --git a/ANDROID_3.4.5/drivers/mmc/core/mmc_ops.h b/ANDROID_3.4.5/drivers/mmc/core/mmc_ops.h
deleted file mode 100644
index 3dd8941c..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/mmc_ops.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * linux/drivers/mmc/core/mmc_ops.h
- *
- * Copyright 2006-2007 Pierre Ossman
- *
- * 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 _MMC_MMC_OPS_H
-#define _MMC_MMC_OPS_H
-
-int mmc_select_card(struct mmc_card *card);
-int mmc_deselect_cards(struct mmc_host *host);
-int mmc_go_idle(struct mmc_host *host);
-int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
-int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
-int mmc_set_relative_addr(struct mmc_card *card);
-int mmc_send_csd(struct mmc_card *card, u32 *csd);
-int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
-int mmc_send_status(struct mmc_card *card, u32 *status);
-int mmc_send_cid(struct mmc_host *host, u32 *cid);
-int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
-int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
-int mmc_card_sleepawake(struct mmc_host *host, int sleep);
-int mmc_bus_test(struct mmc_card *card, u8 bus_width);
-int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
-
-#endif
-
diff --git a/ANDROID_3.4.5/drivers/mmc/core/quirks.c b/ANDROID_3.4.5/drivers/mmc/core/quirks.c
deleted file mode 100644
index 06ee1aea..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/quirks.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * This file contains work-arounds for many known SD/MMC
- * and SDIO hardware bugs.
- *
- * Copyright (c) 2011 Andrei Warkentin <andreiw@motorola.com>
- * Copyright (c) 2011 Pierre Tardy <tardyp@gmail.com>
- * Inspired from pci fixup code:
- * Copyright (c) 1999 Martin Mares <mj@ucw.cz>
- *
- */
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/mmc/card.h>
-
-#ifndef SDIO_VENDOR_ID_TI
-#define SDIO_VENDOR_ID_TI 0x0097
-#endif
-
-#ifndef SDIO_DEVICE_ID_TI_WL1271
-#define SDIO_DEVICE_ID_TI_WL1271 0x4076
-#endif
-
-#ifndef SDIO_VENDOR_ID_STE
-#define SDIO_VENDOR_ID_STE 0x0020
-#endif
-
-#ifndef SDIO_DEVICE_ID_STE_CW1200
-#define SDIO_DEVICE_ID_STE_CW1200 0x2280
-#endif
-
-/*
- * This hook just adds a quirk for all sdio devices
- */
-static void add_quirk_for_sdio_devices(struct mmc_card *card, int data)
-{
- if (mmc_card_sdio(card))
- card->quirks |= data;
-}
-
-static const struct mmc_fixup mmc_fixup_methods[] = {
- /* by default sdio devices are considered CLK_GATING broken */
- /* good cards will be whitelisted as they are tested */
- SDIO_FIXUP(SDIO_ANY_ID, SDIO_ANY_ID,
- add_quirk_for_sdio_devices,
- MMC_QUIRK_BROKEN_CLK_GATING),
-
- SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
- remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
-
- SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
- add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
-
- SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
- add_quirk, MMC_QUIRK_DISABLE_CD),
-
- SDIO_FIXUP(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200,
- add_quirk, MMC_QUIRK_BROKEN_BYTE_MODE_512),
-
- END_FIXUP
-};
-
-void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table)
-{
- const struct mmc_fixup *f;
- u64 rev = cid_rev_card(card);
-
- /* Non-core specific workarounds. */
- if (!table)
- table = mmc_fixup_methods;
-
- for (f = table; f->vendor_fixup; f++) {
- if ((f->manfid == CID_MANFID_ANY ||
- f->manfid == card->cid.manfid) &&
- (f->oemid == CID_OEMID_ANY ||
- f->oemid == card->cid.oemid) &&
- (f->name == CID_NAME_ANY ||
- !strncmp(f->name, card->cid.prod_name,
- sizeof(card->cid.prod_name))) &&
- (f->cis_vendor == card->cis.vendor ||
- f->cis_vendor == (u16) SDIO_ANY_ID) &&
- (f->cis_device == card->cis.device ||
- f->cis_device == (u16) SDIO_ANY_ID) &&
- rev >= f->rev_start && rev <= f->rev_end) {
- dev_dbg(&card->dev, "calling %pF\n", f->vendor_fixup);
- f->vendor_fixup(card, f->data);
- }
- }
-}
-EXPORT_SYMBOL(mmc_fixup_device);
diff --git a/ANDROID_3.4.5/drivers/mmc/core/sd.c b/ANDROID_3.4.5/drivers/mmc/core/sd.c
deleted file mode 100644
index 5dbafd8e..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/sd.c
+++ /dev/null
@@ -1,1341 +0,0 @@
-/*
- * linux/drivers/mmc/core/sd.c
- *
- * Copyright (C) 2003-2004 Russell King, All Rights Reserved.
- * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
- * Copyright (C) 2005-2007 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 version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/sd.h>
-
-#include "core.h"
-#include "bus.h"
-#include "mmc_ops.h"
-#include "sd.h"
-#include "sd_ops.h"
-
-static const unsigned int tran_exp[] = {
- 10000, 100000, 1000000, 10000000,
- 0, 0, 0, 0
-};
-
-static const unsigned char tran_mant[] = {
- 0, 10, 12, 13, 15, 20, 25, 30,
- 35, 40, 45, 50, 55, 60, 70, 80,
-};
-
-static const unsigned int tacc_exp[] = {
- 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
-};
-
-static const unsigned int tacc_mant[] = {
- 0, 10, 12, 13, 15, 20, 25, 30,
- 35, 40, 45, 50, 55, 60, 70, 80,
-};
-
-#define UNSTUFF_BITS(resp,start,size) \
- ({ \
- const int __size = size; \
- const u32 __mask = (__size < 32 ? 1 << __size : 0) - 1; \
- const int __off = 3 - ((start) / 32); \
- const int __shft = (start) & 31; \
- u32 __res; \
- \
- __res = resp[__off] >> __shft; \
- if (__size + __shft > 32) \
- __res |= resp[__off-1] << ((32 - __shft) % 32); \
- __res & __mask; \
- })
-
-/*
- * Given the decoded CSD structure, decode the raw CID to our CID structure.
- */
-void mmc_decode_cid(struct mmc_card *card)
-{
- u32 *resp = card->raw_cid;
-
- memset(&card->cid, 0, sizeof(struct mmc_cid));
-
- /*
- * SD doesn't currently have a version field so we will
- * have to assume we can parse this.
- */
- card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
- card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
- card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
- card->cid.prod_name[1] = UNSTUFF_BITS(resp, 88, 8);
- card->cid.prod_name[2] = UNSTUFF_BITS(resp, 80, 8);
- card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
- card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
- card->cid.hwrev = UNSTUFF_BITS(resp, 60, 4);
- card->cid.fwrev = UNSTUFF_BITS(resp, 56, 4);
- card->cid.serial = UNSTUFF_BITS(resp, 24, 32);
- card->cid.year = UNSTUFF_BITS(resp, 12, 8);
- card->cid.month = UNSTUFF_BITS(resp, 8, 4);
-
- card->cid.year += 2000; /* SD cards year offset */
-}
-
-/*
- * Given a 128-bit response, decode to our card CSD structure.
- */
-static int mmc_decode_csd(struct mmc_card *card)
-{
- struct mmc_csd *csd = &card->csd;
- unsigned int e, m, csd_struct;
- u32 *resp = card->raw_csd;
-
- csd_struct = UNSTUFF_BITS(resp, 126, 2);
-
- switch (csd_struct) {
- case 0:
- m = UNSTUFF_BITS(resp, 115, 4);
- e = UNSTUFF_BITS(resp, 112, 3);
- csd->tacc_ns = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
- csd->tacc_clks = UNSTUFF_BITS(resp, 104, 8) * 100;
-
- m = UNSTUFF_BITS(resp, 99, 4);
- e = UNSTUFF_BITS(resp, 96, 3);
- csd->max_dtr = tran_exp[e] * tran_mant[m];
- csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
-
- e = UNSTUFF_BITS(resp, 47, 3);
- m = UNSTUFF_BITS(resp, 62, 12);
- csd->capacity = (1 + m) << (e + 2);
-
- csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
- csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
- csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
- csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
- csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
- csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
- csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
-
- if (UNSTUFF_BITS(resp, 46, 1)) {
- csd->erase_size = 1;
- } else if (csd->write_blkbits >= 9) {
- csd->erase_size = UNSTUFF_BITS(resp, 39, 7) + 1;
- csd->erase_size <<= csd->write_blkbits - 9;
- }
- break;
- case 1:
- /*
- * This is a block-addressed SDHC or SDXC card. Most
- * interesting fields are unused and have fixed
- * values. To avoid getting tripped by buggy cards,
- * we assume those fixed values ourselves.
- */
- mmc_card_set_blockaddr(card);
-
- csd->tacc_ns = 0; /* Unused */
- csd->tacc_clks = 0; /* Unused */
-
- m = UNSTUFF_BITS(resp, 99, 4);
- e = UNSTUFF_BITS(resp, 96, 3);
- csd->max_dtr = tran_exp[e] * tran_mant[m];
- csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
- csd->c_size = UNSTUFF_BITS(resp, 48, 22);
-
- /* SDXC cards have a minimum C_SIZE of 0x00FFFF */
- if (csd->c_size >= 0xFFFF)
- mmc_card_set_ext_capacity(card);
-
- m = UNSTUFF_BITS(resp, 48, 22);
- csd->capacity = (1 + m) << 10;
-
- csd->read_blkbits = 9;
- csd->read_partial = 0;
- csd->write_misalign = 0;
- csd->read_misalign = 0;
- csd->r2w_factor = 4; /* Unused */
- csd->write_blkbits = 9;
- csd->write_partial = 0;
- csd->erase_size = 1;
- break;
- default:
- pr_err("%s: unrecognised CSD structure version %d\n",
- mmc_hostname(card->host), csd_struct);
- return -EINVAL;
- }
-
- card->erase_size = csd->erase_size;
-
- return 0;
-}
-
-/*
- * Given a 64-bit response, decode to our card SCR structure.
- */
-static int mmc_decode_scr(struct mmc_card *card)
-{
- struct sd_scr *scr = &card->scr;
- unsigned int scr_struct;
- u32 resp[4];
-
- resp[3] = card->raw_scr[1];
- resp[2] = card->raw_scr[0];
-
- scr_struct = UNSTUFF_BITS(resp, 60, 4);
- if (scr_struct != 0) {
- pr_err("%s: unrecognised SCR structure version %d\n",
- mmc_hostname(card->host), scr_struct);
- return -EINVAL;
- }
-
- scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
- scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
- if (scr->sda_vsn == SCR_SPEC_VER_2)
- /* Check if Physical Layer Spec v3.0 is supported */
- scr->sda_spec3 = UNSTUFF_BITS(resp, 47, 1);
-
- if (UNSTUFF_BITS(resp, 55, 1))
- card->erased_byte = 0xFF;
- else
- card->erased_byte = 0x0;
-
- if (scr->sda_spec3)
- scr->cmds = UNSTUFF_BITS(resp, 32, 2);
- return 0;
-}
-
-/*
- * Fetch and process SD Status register.
- */
-static int mmc_read_ssr(struct mmc_card *card)
-{
- unsigned int au, es, et, eo;
- int err, i;
- u32 *ssr;
-
- if (!(card->csd.cmdclass & CCC_APP_SPEC)) {
- pr_warning("%s: card lacks mandatory SD Status "
- "function.\n", mmc_hostname(card->host));
- return 0;
- }
-
- ssr = kmalloc(64, GFP_KERNEL);
- if (!ssr)
- return -ENOMEM;
-
- err = mmc_app_sd_status(card, ssr);
- if (err) {
- pr_warning("%s: problem reading SD Status "
- "register.\n", mmc_hostname(card->host));
- err = 0;
- goto out;
- }
-
- for (i = 0; i < 16; i++)
- ssr[i] = be32_to_cpu(ssr[i]);
-
- /*
- * UNSTUFF_BITS only works with four u32s so we have to offset the
- * bitfield positions accordingly.
- */
- au = UNSTUFF_BITS(ssr, 428 - 384, 4);
- if (au > 0 || au <= 9) {
- card->ssr.au = 1 << (au + 4);
- es = UNSTUFF_BITS(ssr, 408 - 384, 16);
- et = UNSTUFF_BITS(ssr, 402 - 384, 6);
- eo = UNSTUFF_BITS(ssr, 400 - 384, 2);
- if (es && et) {
- card->ssr.erase_timeout = (et * 1000) / es;
- card->ssr.erase_offset = eo * 1000;
- }
- } else {
- pr_warning("%s: SD Status: Invalid Allocation Unit "
- "size.\n", mmc_hostname(card->host));
- }
-out:
- kfree(ssr);
- return err;
-}
-
-/*
- * Fetches and decodes switch information
- */
-static int mmc_read_switch(struct mmc_card *card)
-{
- int err;
- u8 *status;
-
- if (card->scr.sda_vsn < SCR_SPEC_VER_1)
- return 0;
-
- if (!(card->csd.cmdclass & CCC_SWITCH)) {
- pr_warning("%s: card lacks mandatory switch "
- "function, performance might suffer.\n",
- mmc_hostname(card->host));
- return 0;
- }
-
- err = -EIO;
-
- status = kmalloc(64, GFP_KERNEL);
- if (!status) {
- pr_err("%s: could not allocate a buffer for "
- "switch capabilities.\n",
- mmc_hostname(card->host));
- return -ENOMEM;
- }
-
- /* Find out the supported Bus Speed Modes. */
- err = mmc_sd_switch(card, 0, 0, 1, status);
- if (err) {
- /*
- * If the host or the card can't do the switch,
- * fail more gracefully.
- */
- if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
- goto out;
-
- pr_warning("%s: problem reading Bus Speed modes.\n",
- mmc_hostname(card->host));
- err = 0;
-
- goto out;
- }
-
- if (status[13] & SD_MODE_HIGH_SPEED)
- card->sw_caps.hs_max_dtr = HIGH_SPEED_MAX_DTR;
-
- if (card->scr.sda_spec3) {
- card->sw_caps.sd3_bus_mode = status[13];
-
- /* Find out Driver Strengths supported by the card */
- err = mmc_sd_switch(card, 0, 2, 1, status);
- if (err) {
- /*
- * If the host or the card can't do the switch,
- * fail more gracefully.
- */
- if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
- goto out;
-
- pr_warning("%s: problem reading "
- "Driver Strength.\n",
- mmc_hostname(card->host));
- err = 0;
-
- goto out;
- }
-
- card->sw_caps.sd3_drv_type = status[9];
-
- /* Find out Current Limits supported by the card */
- err = mmc_sd_switch(card, 0, 3, 1, status);
- if (err) {
- /*
- * If the host or the card can't do the switch,
- * fail more gracefully.
- */
- if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
- goto out;
-
- pr_warning("%s: problem reading "
- "Current Limit.\n",
- mmc_hostname(card->host));
- err = 0;
-
- goto out;
- }
-
- card->sw_caps.sd3_curr_limit = status[7];
- }
-
-out:
- kfree(status);
-
- return err;
-}
-
-/*
- * Test if the card supports high-speed mode and, if so, switch to it.
- */
-int mmc_sd_switch_hs(struct mmc_card *card)
-{
- int err;
- u8 *status;
-
- if (card->scr.sda_vsn < SCR_SPEC_VER_1)
- return 0;
-
- if (!(card->csd.cmdclass & CCC_SWITCH))
- return 0;
-
- if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
- return 0;
-
- if (card->sw_caps.hs_max_dtr == 0)
- return 0;
-
- err = -EIO;
-
- status = kmalloc(64, GFP_KERNEL);
- if (!status) {
- pr_err("%s: could not allocate a buffer for "
- "switch capabilities.\n", mmc_hostname(card->host));
- return -ENOMEM;
- }
-
- err = mmc_sd_switch(card, 1, 0, 1, status);
- if (err)
- goto out;
-
- if ((status[16] & 0xF) != 1) {
- pr_warning("%s: Problem switching card "
- "into high-speed mode!\n",
- mmc_hostname(card->host));
- err = 0;
- } else {
- err = 1;
- }
-
-out:
- kfree(status);
-
- return err;
-}
-
-static int sd_select_driver_type(struct mmc_card *card, u8 *status)
-{
- int host_drv_type = SD_DRIVER_TYPE_B;
- int card_drv_type = SD_DRIVER_TYPE_B;
- int drive_strength;
- int err;
-
- /*
- * If the host doesn't support any of the Driver Types A,C or D,
- * or there is no board specific handler then default Driver
- * Type B is used.
- */
- if (!(card->host->caps & (MMC_CAP_DRIVER_TYPE_A | MMC_CAP_DRIVER_TYPE_C
- | MMC_CAP_DRIVER_TYPE_D)))
- return 0;
-
- if (!card->host->ops->select_drive_strength)
- return 0;
-
- if (card->host->caps & MMC_CAP_DRIVER_TYPE_A)
- host_drv_type |= SD_DRIVER_TYPE_A;
-
- if (card->host->caps & MMC_CAP_DRIVER_TYPE_C)
- host_drv_type |= SD_DRIVER_TYPE_C;
-
- if (card->host->caps & MMC_CAP_DRIVER_TYPE_D)
- host_drv_type |= SD_DRIVER_TYPE_D;
-
- if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A)
- card_drv_type |= SD_DRIVER_TYPE_A;
-
- if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
- card_drv_type |= SD_DRIVER_TYPE_C;
-
- if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_D)
- card_drv_type |= SD_DRIVER_TYPE_D;
-
- /*
- * The drive strength that the hardware can support
- * depends on the board design. Pass the appropriate
- * information and let the hardware specific code
- * return what is possible given the options
- */
- mmc_host_clk_hold(card->host);
- drive_strength = card->host->ops->select_drive_strength(
- card->sw_caps.uhs_max_dtr,
- host_drv_type, card_drv_type);
- mmc_host_clk_release(card->host);
-
- err = mmc_sd_switch(card, 1, 2, drive_strength, status);
- if (err)
- return err;
-
- if ((status[15] & 0xF) != drive_strength) {
- pr_warning("%s: Problem setting drive strength!\n",
- mmc_hostname(card->host));
- return 0;
- }
-
- mmc_set_driver_type(card->host, drive_strength);
-
- return 0;
-}
-
-static void sd_update_bus_speed_mode(struct mmc_card *card)
-{
- /*
- * If the host doesn't support any of the UHS-I modes, fallback on
- * default speed.
- */
- if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))) {
- card->sd_bus_speed = 0;
- return;
- }
-
- if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
- (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) {
- card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
- } else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
- (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
- card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
- } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
- MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
- SD_MODE_UHS_SDR50)) {
- card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
- } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
- (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
- card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
- } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
- SD_MODE_UHS_SDR12)) {
- card->sd_bus_speed = UHS_SDR12_BUS_SPEED;
- }
-}
-
-static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
-{
- int err;
- unsigned int timing = 0;
-
- switch (card->sd_bus_speed) {
- case UHS_SDR104_BUS_SPEED:
- timing = MMC_TIMING_UHS_SDR104;
- card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
- break;
- case UHS_DDR50_BUS_SPEED:
- timing = MMC_TIMING_UHS_DDR50;
- card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
- break;
- case UHS_SDR50_BUS_SPEED:
- timing = MMC_TIMING_UHS_SDR50;
- card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
- break;
- case UHS_SDR25_BUS_SPEED:
- timing = MMC_TIMING_UHS_SDR25;
- card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
- break;
- case UHS_SDR12_BUS_SPEED:
- timing = MMC_TIMING_UHS_SDR12;
- card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
- break;
- default:
- return 0;
- }
-
- err = mmc_sd_switch(card, 1, 0, card->sd_bus_speed, status);
- if (err)
- return err;
-
- if ((status[16] & 0xF) != card->sd_bus_speed)
- pr_warning("%s: Problem setting bus speed mode!\n",
- mmc_hostname(card->host));
- else {
- mmc_set_timing(card->host, timing);
- mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
- }
-
- return 0;
-}
-
-static int sd_set_current_limit(struct mmc_card *card, u8 *status)
-{
- int current_limit = 0;
- int err;
-
- /*
- * Current limit switch is only defined for SDR50, SDR104, and DDR50
- * bus speed modes. For other bus speed modes, we set the default
- * current limit of 200mA.
- */
- if ((card->sd_bus_speed == UHS_SDR50_BUS_SPEED) ||
- (card->sd_bus_speed == UHS_SDR104_BUS_SPEED) ||
- (card->sd_bus_speed == UHS_DDR50_BUS_SPEED)) {
- if (card->host->caps & MMC_CAP_MAX_CURRENT_800) {
- if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_800)
- current_limit = SD_SET_CURRENT_LIMIT_800;
- else if (card->sw_caps.sd3_curr_limit &
- SD_MAX_CURRENT_600)
- current_limit = SD_SET_CURRENT_LIMIT_600;
- else if (card->sw_caps.sd3_curr_limit &
- SD_MAX_CURRENT_400)
- current_limit = SD_SET_CURRENT_LIMIT_400;
- else if (card->sw_caps.sd3_curr_limit &
- SD_MAX_CURRENT_200)
- current_limit = SD_SET_CURRENT_LIMIT_200;
- } else if (card->host->caps & MMC_CAP_MAX_CURRENT_600) {
- if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_600)
- current_limit = SD_SET_CURRENT_LIMIT_600;
- else if (card->sw_caps.sd3_curr_limit &
- SD_MAX_CURRENT_400)
- current_limit = SD_SET_CURRENT_LIMIT_400;
- else if (card->sw_caps.sd3_curr_limit &
- SD_MAX_CURRENT_200)
- current_limit = SD_SET_CURRENT_LIMIT_200;
- } else if (card->host->caps & MMC_CAP_MAX_CURRENT_400) {
- if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400)
- current_limit = SD_SET_CURRENT_LIMIT_400;
- else if (card->sw_caps.sd3_curr_limit &
- SD_MAX_CURRENT_200)
- current_limit = SD_SET_CURRENT_LIMIT_200;
- } else if (card->host->caps & MMC_CAP_MAX_CURRENT_200) {
- if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_200)
- current_limit = SD_SET_CURRENT_LIMIT_200;
- }
- } else
- current_limit = SD_SET_CURRENT_LIMIT_200;
-
- err = mmc_sd_switch(card, 1, 3, current_limit, status);
- if (err)
- return err;
-
- if (((status[15] >> 4) & 0x0F) != current_limit)
- pr_warning("%s: Problem setting current limit!\n",
- mmc_hostname(card->host));
-
- return 0;
-}
-
-/*
- * UHS-I specific initialization procedure
- */
-static int mmc_sd_init_uhs_card(struct mmc_card *card)
-{
- int err;
- u8 *status;
-
- if (!card->scr.sda_spec3)
- return 0;
-
- if (!(card->csd.cmdclass & CCC_SWITCH))
- return 0;
-
- status = kmalloc(64, GFP_KERNEL);
- if (!status) {
- pr_err("%s: could not allocate a buffer for "
- "switch capabilities.\n", mmc_hostname(card->host));
- return -ENOMEM;
- }
-
- /* Set 4-bit bus width */
- if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
- (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
- err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
- if (err)
- goto out;
-
- mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
- }
-
- /*
- * Select the bus speed mode depending on host
- * and card capability.
- */
- sd_update_bus_speed_mode(card);
-
- /* Set the driver strength for the card */
- err = sd_select_driver_type(card, status);
- if (err)
- goto out;
-
- /* Set current limit for the card */
- err = sd_set_current_limit(card, status);
- if (err)
- goto out;
-
- /* Set bus speed mode of the card */
- err = sd_set_bus_speed_mode(card, status);
- if (err)
- goto out;
-
- /* SPI mode doesn't define CMD19 */
- if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) {
- mmc_host_clk_hold(card->host);
- err = card->host->ops->execute_tuning(card->host,
- MMC_SEND_TUNING_BLOCK);
- mmc_host_clk_release(card->host);
- }
-
-out:
- kfree(status);
-
- return err;
-}
-
-MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
- card->raw_cid[2], card->raw_cid[3]);
-MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
- card->raw_csd[2], card->raw_csd[3]);
-MMC_DEV_ATTR(scr, "%08x%08x\n", card->raw_scr[0], card->raw_scr[1]);
-MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
-MMC_DEV_ATTR(erase_size, "%u\n", card->erase_size << 9);
-MMC_DEV_ATTR(preferred_erase_size, "%u\n", card->pref_erase << 9);
-MMC_DEV_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
-MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
-MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
-MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
-MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
-MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
-
-
-static struct attribute *sd_std_attrs[] = {
- &dev_attr_cid.attr,
- &dev_attr_csd.attr,
- &dev_attr_scr.attr,
- &dev_attr_date.attr,
- &dev_attr_erase_size.attr,
- &dev_attr_preferred_erase_size.attr,
- &dev_attr_fwrev.attr,
- &dev_attr_hwrev.attr,
- &dev_attr_manfid.attr,
- &dev_attr_name.attr,
- &dev_attr_oemid.attr,
- &dev_attr_serial.attr,
- NULL,
-};
-
-static struct attribute_group sd_std_attr_group = {
- .attrs = sd_std_attrs,
-};
-
-static const struct attribute_group *sd_attr_groups[] = {
- &sd_std_attr_group,
- NULL,
-};
-
-struct device_type sd_type = {
- .groups = sd_attr_groups,
-};
-
-/*
- * Fetch CID from card.
- */
-int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
-{
- int err;
-
- /*
- * Since we're changing the OCR value, we seem to
- * need to tell some cards to go back to the idle
- * state. We wait 1ms to give cards time to
- * respond.
- */
- mmc_go_idle(host);
-
- /*
- * If SD_SEND_IF_COND indicates an SD 2.0
- * compliant card and we should set bit 30
- * of the ocr to indicate that we can handle
- * block-addressed SDHC cards.
- */
- err = mmc_send_if_cond(host, ocr);
- if (!err)
- ocr |= SD_OCR_CCS;
-
- /*
- * If the host supports one of UHS-I modes, request the card
- * to switch to 1.8V signaling level.
- */
- if (host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))
- ocr |= SD_OCR_S18R;
-
- /* If the host can supply more than 150mA, XPC should be set to 1. */
- if (host->caps & (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
- MMC_CAP_SET_XPC_180))
- ocr |= SD_OCR_XPC;
-
-try_again:
- err = mmc_send_app_op_cond(host, ocr, rocr);
- if (err)
- return err;
-
- /*
- * In case CCS and S18A in the response is set, start Signal Voltage
- * Switch procedure. SPI mode doesn't support CMD11.
- */
- if (!mmc_host_is_spi(host) && rocr &&
- ((*rocr & 0x41000000) == 0x41000000)) {
- err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, true);
- if (err) {
- ocr &= ~SD_OCR_S18R;
- goto try_again;
- }
- }
-
- if (mmc_host_is_spi(host))
- err = mmc_send_cid(host, cid);
- else
- err = mmc_all_send_cid(host, cid);
-
- return err;
-}
-
-int mmc_sd_get_csd(struct mmc_host *host, struct mmc_card *card)
-{
- int err;
-
- /*
- * Fetch CSD from card.
- */
- err = mmc_send_csd(card, card->raw_csd);
- if (err)
- return err;
-
- err = mmc_decode_csd(card);
- if (err)
- return err;
-
- return 0;
-}
-
-int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
- bool reinit)
-{
- int err;
-#ifdef CONFIG_MMC_PARANOID_SD_INIT
- int retries;
-#endif
-
- if (!reinit) {
- /*
- * Fetch SCR from card.
- */
- err = mmc_app_send_scr(card, card->raw_scr);
- if (err)
- return err;
-
- err = mmc_decode_scr(card);
- if (err)
- return err;
-
- /*
- * Fetch and process SD Status register.
- */
- err = mmc_read_ssr(card);
- if (err)
- return err;
-
- /* Erase init depends on CSD and SSR */
- mmc_init_erase(card);
-
- /*
- * Fetch switch information from card.
- */
-#ifdef CONFIG_MMC_PARANOID_SD_INIT
- for (retries = 1; retries <= 3; retries++) {
- err = mmc_read_switch(card);
- if (!err) {
- if (retries > 1) {
- printk(KERN_WARNING
- "%s: recovered\n",
- mmc_hostname(host));
- }
- break;
- } else {
- printk(KERN_WARNING
- "%s: read switch failed (attempt %d)\n",
- mmc_hostname(host), retries);
- }
- }
-#else
- err = mmc_read_switch(card);
-#endif
-
- if (err)
- return err;
- }
-
- /*
- * For SPI, enable CRC as appropriate.
- * This CRC enable is located AFTER the reading of the
- * card registers because some SDHC cards are not able
- * to provide valid CRCs for non-512-byte blocks.
- */
- if (mmc_host_is_spi(host)) {
- err = mmc_spi_set_crc(host, use_spi_crc);
- if (err)
- return err;
- }
-
- /*
- * Check if read-only switch is active.
- */
- if (!reinit) {
- int ro = -1;
-
- if (host->ops->get_ro) {
- mmc_host_clk_hold(card->host);
- ro = host->ops->get_ro(host);
- mmc_host_clk_release(card->host);
- }
-
- if (ro < 0) {
- pr_warning("%s: host does not "
- "support reading read-only "
- "switch. assuming write-enable.\n",
- mmc_hostname(host));
- } else if (ro > 0) {
- mmc_card_set_readonly(card);
- }
- }
-
- return 0;
-}
-
-unsigned mmc_sd_get_max_clock(struct mmc_card *card)
-{
- unsigned max_dtr = (unsigned int)-1;
-
- if (mmc_card_highspeed(card)) {
- if (max_dtr > card->sw_caps.hs_max_dtr)
- max_dtr = card->sw_caps.hs_max_dtr;
- } else if (max_dtr > card->csd.max_dtr) {
- max_dtr = card->csd.max_dtr;
- }
-
- return max_dtr;
-}
-
-void mmc_sd_go_highspeed(struct mmc_card *card)
-{
- mmc_card_set_highspeed(card);
- mmc_set_timing(card->host, MMC_TIMING_SD_HS);
-}
-
-/*
- * Handle the detection and initialisation of a card.
- *
- * In the case of a resume, "oldcard" will contain the card
- * we're trying to reinitialise.
- */
-static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
- struct mmc_card *oldcard)
-{
- struct mmc_card *card;
- int err;
- u32 cid[4];
- u32 rocr = 0;
-
- BUG_ON(!host);
- WARN_ON(!host->claimed);
-
- /* The initialization should be done at 3.3 V I/O voltage. */
- mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
-
- err = mmc_sd_get_cid(host, ocr, cid, &rocr);
- if (err)
- return err;
-
- if (oldcard) {
- if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0)
- return -ENOENT;
-
- card = oldcard;
- } else {
- /*
- * Allocate card structure.
- */
- card = mmc_alloc_card(host, &sd_type);
- if (IS_ERR(card))
- return PTR_ERR(card);
-
- card->type = MMC_TYPE_SD;
- memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
- }
-
- /*
- * For native busses: get card RCA and quit open drain mode.
- */
- if (!mmc_host_is_spi(host)) {
- err = mmc_send_relative_addr(host, &card->rca);
- if (err)
- return err;
- }
-
- if (!oldcard) {
- err = mmc_sd_get_csd(host, card);
- if (err)
- return err;
-
- mmc_decode_cid(card);
- }
-
- /*
- * Select card, as all following commands rely on that.
- */
- if (!mmc_host_is_spi(host)) {
- err = mmc_select_card(card);
- if (err)
- return err;
- }
-
- err = mmc_sd_setup_card(host, card, oldcard != NULL);
- if (err)
- goto free_card;
-
- /* Initialization sequence for UHS-I cards */
- if (rocr & SD_ROCR_S18A) {
- err = mmc_sd_init_uhs_card(card);
- if (err)
- goto free_card;
-
- /* Card is an ultra-high-speed card */
- mmc_card_set_uhs(card);
-
- /*
- * Since initialization is now complete, enable preset
- * value registers for UHS-I cards.
- */
- if (host->ops->enable_preset_value) {
- mmc_host_clk_hold(card->host);
- host->ops->enable_preset_value(host, true);
- mmc_host_clk_release(card->host);
- }
- } else {
- /*
- * Attempt to change to high-speed (if supported)
- */
- err = mmc_sd_switch_hs(card);
- if (err > 0)
- mmc_sd_go_highspeed(card);
- else if (err)
- goto free_card;
-
- /*
- * Set bus speed.
- */
- mmc_set_clock(host, mmc_sd_get_max_clock(card));
-
- /*
- * Switch to wider bus (if supported).
- */
- if ((host->caps & MMC_CAP_4_BIT_DATA) &&
- (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
- err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
- if (err)
- goto free_card;
-
- mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
- }
- }
-
- host->card = card;
- return 0;
-
-free_card:
- if (!oldcard)
- mmc_remove_card(card);
-
- return err;
-}
-
-/*
- * Host is being removed. Free up the current card.
- */
-static void mmc_sd_remove(struct mmc_host *host)
-{
- BUG_ON(!host);
- BUG_ON(!host->card);
-
- mmc_remove_card(host->card);
- host->card = NULL;
-}
-
-/*
- * Card detection - card is alive.
- */
-static int mmc_sd_alive(struct mmc_host *host)
-{
- return mmc_send_status(host->card, NULL);
-}
-
-/*
- * Card detection callback from host.
- */
-static void mmc_sd_detect(struct mmc_host *host)
-{
- int err = 0;
-#ifdef CONFIG_MMC_PARANOID_SD_INIT
- int retries = 5;
-#endif
-
- BUG_ON(!host);
- BUG_ON(!host->card);
-
- mmc_claim_host(host);
-
- /*
- * Just check if our card has been removed.
- */
-#ifdef CONFIG_MMC_PARANOID_SD_INIT
- while(retries) {
- err = mmc_send_status(host->card, NULL);
- if (err) {
- retries--;
- udelay(5);
- continue;
- }
- break;
- }
- if (!retries) {
- printk(KERN_ERR "%s(%s): Unable to re-detect card (%d)\n",
- __func__, mmc_hostname(host), err);
- }
-#else
- err = _mmc_detect_card_removed(host);
-#endif
- mmc_release_host(host);
-
-#ifdef CONFIG_MMC_UNSAFE_RESUME
- if (err || (host->card_attath_status == card_attach_status_change)) {
- host->card_attath_status = card_attach_status_unchange;
- mmc_sd_remove(host);
- mmc_claim_host(host);
- mmc_detach_bus(host);
- mmc_power_off(host);
- mmc_release_host(host);
- }
-#else
- if (err) {
- mmc_sd_remove(host);
-
- mmc_claim_host(host);
- mmc_detach_bus(host);
- mmc_power_off(host);
- mmc_release_host(host);
- }
-#endif
-}
-
-/*
- * Suspend callback from host.
- */
-static int mmc_sd_suspend(struct mmc_host *host)
-{
- BUG_ON(!host);
- BUG_ON(!host->card);
-
- mmc_claim_host(host);
- if (!mmc_host_is_spi(host))
- mmc_deselect_cards(host);
- host->card->state &= ~MMC_STATE_HIGHSPEED;
- mmc_release_host(host);
-
- return 0;
-}
-
-/*
- * Resume callback from host.
- *
- * This function tries to determine if the same card is still present
- * and, if so, restore all state to it.
- */
-static int mmc_sd_resume(struct mmc_host *host)
-{
- int err;
-#ifdef CONFIG_MMC_PARANOID_SD_INIT
- int retries;
-#endif
-
- BUG_ON(!host);
- BUG_ON(!host->card);
-
- mmc_claim_host(host);
-#ifdef CONFIG_MMC_PARANOID_SD_INIT
- retries = 5;
- while (retries) {
- err = mmc_sd_init_card(host, host->ocr, host->card);
-
- if (err) {
- printk(KERN_ERR "%s: Re-init card rc = %d (retries = %d)\n",
- mmc_hostname(host), err, retries);
- mdelay(5);
- retries--;
- continue;
- }
- break;
- }
-#else
- err = mmc_sd_init_card(host, host->ocr, host->card);
-#endif
- mmc_release_host(host);
-
-#ifdef CONFIG_MMC_UNSAFE_RESUME
- if (err)
- host->card_attath_status = card_attach_status_change;
-#endif
-
- return err;
-}
-
-static int mmc_sd_power_restore(struct mmc_host *host)
-{
- int ret;
-
- host->card->state &= ~MMC_STATE_HIGHSPEED;
- mmc_claim_host(host);
- ret = mmc_sd_init_card(host, host->ocr, host->card);
- mmc_release_host(host);
-
- return ret;
-}
-
-static const struct mmc_bus_ops mmc_sd_ops = {
- .remove = mmc_sd_remove,
- .detect = mmc_sd_detect,
- .suspend = NULL,
- .resume = NULL,
- .power_restore = mmc_sd_power_restore,
- .alive = mmc_sd_alive,
-};
-
-static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
- .remove = mmc_sd_remove,
- .detect = mmc_sd_detect,
- .suspend = mmc_sd_suspend,
- .resume = mmc_sd_resume,
- .power_restore = mmc_sd_power_restore,
- .alive = mmc_sd_alive,
-};
-
-static void mmc_sd_attach_bus_ops(struct mmc_host *host)
-{
- const struct mmc_bus_ops *bus_ops;
-
- if (!mmc_card_is_removable(host))
- bus_ops = &mmc_sd_ops_unsafe;
- else
- bus_ops = &mmc_sd_ops;
- mmc_attach_bus(host, bus_ops);
-}
-
-/*
- * Starting point for SD card init.
- */
-int mmc_attach_sd(struct mmc_host *host)
-{
- int err;
- u32 ocr;
-#ifdef CONFIG_MMC_PARANOID_SD_INIT
- int retries;
-#endif
-
- BUG_ON(!host);
- WARN_ON(!host->claimed);
-
- /* Disable preset value enable if already set since last time */
- if (host->ops->enable_preset_value) {
- mmc_host_clk_hold(host);
- host->ops->enable_preset_value(host, false);
- mmc_host_clk_release(host);
- }
-
- err = mmc_send_app_op_cond(host, 0, &ocr);
- if (err)
- return err;
-
- mmc_sd_attach_bus_ops(host);
- if (host->ocr_avail_sd)
- host->ocr_avail = host->ocr_avail_sd;
-
- /*
- * We need to get OCR a different way for SPI.
- */
- if (mmc_host_is_spi(host)) {
- mmc_go_idle(host);
-
- err = mmc_spi_read_ocr(host, 0, &ocr);
- if (err)
- goto err;
- }
-
- /*
- * Sanity check the voltages that the card claims to
- * support.
- */
- if (ocr & 0x7F) {
- pr_warning("%s: card claims to support voltages "
- "below the defined range. These will be ignored.\n",
- mmc_hostname(host));
- ocr &= ~0x7F;
- }
-
- if ((ocr & MMC_VDD_165_195) &&
- !(host->ocr_avail_sd & MMC_VDD_165_195)) {
- pr_warning("%s: SD card claims to support the "
- "incompletely defined 'low voltage range'. This "
- "will be ignored.\n", mmc_hostname(host));
- ocr &= ~MMC_VDD_165_195;
- }
-
- host->ocr = mmc_select_voltage(host, ocr);
-
- /*
- * Can we support the voltage(s) of the card(s)?
- */
- if (!host->ocr) {
- err = -EINVAL;
- goto err;
- }
-
- /*
- * Detect and init the card.
- */
-#ifdef CONFIG_MMC_PARANOID_SD_INIT
- retries = 5;
- while (retries) {
- err = mmc_sd_init_card(host, host->ocr, NULL);
- if (err) {
- retries--;
- continue;
- }
- break;
- }
-
- if (!retries) {
- printk(KERN_ERR "%s: mmc_sd_init_card() failure (err = %d)\n",
- mmc_hostname(host), err);
- goto err;
- }
-#else
- err = mmc_sd_init_card(host, host->ocr, NULL);
- if (err)
- goto err;
-#endif
-
- mmc_release_host(host);
- err = mmc_add_card(host->card);
- mmc_claim_host(host);
- if (err)
- goto remove_card;
-
- return 0;
-
-remove_card:
- mmc_release_host(host);
- mmc_remove_card(host->card);
- host->card = NULL;
- mmc_claim_host(host);
-err:
- mmc_detach_bus(host);
-
- pr_err("%s: error %d whilst initialising SD card\n",
- mmc_hostname(host), err);
-
- return err;
-}
-
diff --git a/ANDROID_3.4.5/drivers/mmc/core/sd.h b/ANDROID_3.4.5/drivers/mmc/core/sd.h
deleted file mode 100644
index 4b34b24f..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/sd.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef _MMC_CORE_SD_H
-#define _MMC_CORE_SD_H
-
-#include <linux/mmc/card.h>
-
-extern struct device_type sd_type;
-
-int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr);
-int mmc_sd_get_csd(struct mmc_host *host, struct mmc_card *card);
-void mmc_decode_cid(struct mmc_card *card);
-int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
- bool reinit);
-unsigned mmc_sd_get_max_clock(struct mmc_card *card);
-int mmc_sd_switch_hs(struct mmc_card *card);
-void mmc_sd_go_highspeed(struct mmc_card *card);
-
-#endif
diff --git a/ANDROID_3.4.5/drivers/mmc/core/sd_ops.c b/ANDROID_3.4.5/drivers/mmc/core/sd_ops.c
deleted file mode 100644
index e01d12a3..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/sd_ops.c
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
- * linux/drivers/mmc/core/sd_ops.h
- *
- * Copyright 2006-2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/export.h>
-#include <linux/scatterlist.h>
-
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/sd.h>
-
-#include "core.h"
-#include "sd_ops.h"
-
-int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
-{
- int err;
- struct mmc_command cmd = {0};
-
- BUG_ON(!host);
- BUG_ON(card && (card->host != host));
-
- cmd.opcode = MMC_APP_CMD;
-
- if (card) {
- cmd.arg = card->rca << 16;
- //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- } else {
- cmd.arg = 0;
- //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_BCR;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR;
- }
-
- err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err)
- return err;
-
- /* Check that card supported application commands */
- if (!mmc_host_is_spi(host) && !(cmd.resp[0] & R1_APP_CMD))
- return -EOPNOTSUPP;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(mmc_app_cmd);
-
-/**
- * mmc_wait_for_app_cmd - start an application command and wait for
- completion
- * @host: MMC host to start command
- * @card: Card to send MMC_APP_CMD to
- * @cmd: MMC command to start
- * @retries: maximum number of retries
- *
- * Sends a MMC_APP_CMD, checks the card response, sends the command
- * in the parameter and waits for it to complete. Return any error
- * that occurred while the command was executing. Do not attempt to
- * parse the response.
- */
-int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
- struct mmc_command *cmd, int retries)
-{
- struct mmc_request mrq = {NULL};
-
- int i, err;
-
- BUG_ON(!cmd);
- BUG_ON(retries < 0);
-
- err = -EIO;
-
- /*
- * We have to resend MMC_APP_CMD for each attempt so
- * we cannot use the retries field in mmc_command.
- */
- for (i = 0;i <= retries;i++) {
- err = mmc_app_cmd(host, card);
- if (err) {
- /* no point in retrying; no APP commands allowed */
- if (mmc_host_is_spi(host)) {
- if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
- break;
- }
- continue;
- }
-
- memset(&mrq, 0, sizeof(struct mmc_request));
-
- memset(cmd->resp, 0, sizeof(cmd->resp));
- cmd->retries = 0;
-
- mrq.cmd = cmd;
- cmd->data = NULL;
-
- mmc_wait_for_req(host, &mrq);
-
- err = cmd->error;
- if (!cmd->error)
- break;
-
- /* no point in retrying illegal APP commands */
- if (mmc_host_is_spi(host)) {
- if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
- break;
- }
- }
-
- return err;
-}
-
-EXPORT_SYMBOL(mmc_wait_for_app_cmd);
-
-int mmc_app_set_bus_width(struct mmc_card *card, int width)
-{
- int err;
- struct mmc_command cmd = {0};
-
- BUG_ON(!card);
- BUG_ON(!card->host);
-
- cmd.opcode = SD_APP_SET_BUS_WIDTH;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-
- switch (width) {
- case MMC_BUS_WIDTH_1:
- cmd.arg = SD_BUS_WIDTH_1;
- break;
- case MMC_BUS_WIDTH_4:
- cmd.arg = SD_BUS_WIDTH_4;
- break;
- default:
- return -EINVAL;
- }
-
- err = mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES);
- if (err)
- return err;
-
- return 0;
-}
-
-int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
-{
- struct mmc_command cmd = {0};
- int i, err = 0;
-
- BUG_ON(!host);
-
- cmd.opcode = SD_APP_OP_COND;
- if (mmc_host_is_spi(host))
- cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */
- else
- cmd.arg = ocr;
- //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
- cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
-
- for (i = 100; i; i--) {
- err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES);
- if (err)
- break;
-
- /* if we're just probing, do a single pass */
- if (ocr == 0)
- break;
-
- /* otherwise wait until reset completes */
- if (mmc_host_is_spi(host)) {
- if (!(cmd.resp[0] & R1_SPI_IDLE))
- break;
- } else {
- if (cmd.resp[0] & MMC_CARD_BUSY)
- break;
- }
-
- err = -ETIMEDOUT;
-
- mmc_delay(10);
- }
-
- if (rocr && !mmc_host_is_spi(host))
- *rocr = cmd.resp[0];
-
- return err;
-}
-
-int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
-{
- struct mmc_command cmd = {0};
- int err;
- static const u8 test_pattern = 0xAA;
- u8 result_pattern;
-
- /*
- * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
- * before SD_APP_OP_COND. This command will harmlessly fail for
- * SD 1.0 cards.
- */
- cmd.opcode = SD_SEND_IF_COND;
- cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
- //cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR;
- cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
-
- err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err)
- return err;
-
- if (mmc_host_is_spi(host))
- result_pattern = cmd.resp[1] & 0xFF;
- else
- result_pattern = cmd.resp[0] & 0xFF;
-
- if (result_pattern != test_pattern)
- return -EIO;
-
- return 0;
-}
-
-int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
-{
- int err;
- struct mmc_command cmd = {0};
-
- BUG_ON(!host);
- BUG_ON(!rca);
-
- cmd.opcode = SD_SEND_RELATIVE_ADDR;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
-
- err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
- if (err)
- return err;
-
- *rca = cmd.resp[0] >> 16;
-
- return 0;
-}
-
-int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
-{
- int err;
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
- struct scatterlist sg;
- void *data_buf;
-
- BUG_ON(!card);
- BUG_ON(!card->host);
- BUG_ON(!scr);
-
- /* NOTE: caller guarantees scr is heap-allocated */
-
- err = mmc_app_cmd(card->host, card);
- if (err)
- return err;
-
- /* dma onto stack is unsafe/nonportable, but callers to this
- * routine normally provide temporary on-stack buffers ...
- */
- data_buf = kmalloc(sizeof(card->raw_scr), GFP_KERNEL);
- if (data_buf == NULL)
- return -ENOMEM;
-
- mrq.cmd = &cmd;
- mrq.data = &data;
-
- cmd.opcode = SD_APP_SEND_SCR;
- cmd.arg = 0;
- //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
- data.blksz = 8;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-
- sg_init_one(&sg, data_buf, 8);
-
- mmc_set_data_timeout(&data, card);
-
- mmc_wait_for_req(card->host, &mrq);
-
- memcpy(scr, data_buf, sizeof(card->raw_scr));
- kfree(data_buf);
-
- if (cmd.error)
- return cmd.error;
- if (data.error)
- return data.error;
-
- scr[0] = be32_to_cpu(scr[0]);
- scr[1] = be32_to_cpu(scr[1]);
-
- return 0;
-}
-
-int mmc_sd_switch(struct mmc_card *card, int mode, int group,
- u8 value, u8 *resp)
-{
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
- struct scatterlist sg;
-
- BUG_ON(!card);
- BUG_ON(!card->host);
-
- /* NOTE: caller guarantees resp is heap-allocated */
-
- mode = !!mode;
- value &= 0xF;
-
- mrq.cmd = &cmd;
- mrq.data = &data;
-
- cmd.opcode = SD_SWITCH;
- cmd.arg = mode << 31 | 0x00FFFFFF;
- cmd.arg &= ~(0xF << (group * 4));
- cmd.arg |= value << (group * 4);
- //cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
- data.blksz = 64;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-
- sg_init_one(&sg, resp, 64);
-
- mmc_set_data_timeout(&data, card);
-
- mmc_wait_for_req(card->host, &mrq);
-
- if (cmd.error)
- return cmd.error;
- if (data.error)
- return data.error;
-
- return 0;
-}
-
-int mmc_app_sd_status(struct mmc_card *card, void *ssr)
-{
- int err;
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
- struct scatterlist sg;
-
- BUG_ON(!card);
- BUG_ON(!card->host);
- BUG_ON(!ssr);
-
- /* NOTE: caller guarantees ssr is heap-allocated */
-
- err = mmc_app_cmd(card->host, card);
- if (err)
- return err;
-
- mrq.cmd = &cmd;
- mrq.data = &data;
-
- cmd.opcode = SD_APP_SD_STATUS;
- cmd.arg = 0;
- //cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_ADTC;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
- data.blksz = 64;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-
- sg_init_one(&sg, ssr, 64);
-
- mmc_set_data_timeout(&data, card);
-
- mmc_wait_for_req(card->host, &mrq);
-
- if (cmd.error)
- return cmd.error;
- if (data.error)
- return data.error;
-
- return 0;
-}
diff --git a/ANDROID_3.4.5/drivers/mmc/core/sd_ops.h b/ANDROID_3.4.5/drivers/mmc/core/sd_ops.h
deleted file mode 100644
index ffc2305d..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/sd_ops.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * linux/drivers/mmc/core/sd_ops.h
- *
- * Copyright 2006-2007 Pierre Ossman
- *
- * 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 _MMC_SD_OPS_H
-#define _MMC_SD_OPS_H
-
-int mmc_app_set_bus_width(struct mmc_card *card, int width);
-int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
-int mmc_send_if_cond(struct mmc_host *host, u32 ocr);
-int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca);
-int mmc_app_send_scr(struct mmc_card *card, u32 *scr);
-int mmc_sd_switch(struct mmc_card *card, int mode, int group,
- u8 value, u8 *resp);
-int mmc_app_sd_status(struct mmc_card *card, void *ssr);
-
-#endif
-
diff --git a/ANDROID_3.4.5/drivers/mmc/core/sdio.c b/ANDROID_3.4.5/drivers/mmc/core/sdio.c
deleted file mode 100644
index 341b4c0f..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/sdio.c
+++ /dev/null
@@ -1,1260 +0,0 @@
-/*
- * linux/drivers/mmc/sdio.c
- *
- * Copyright 2006-2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/pm_runtime.h>
-
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/sdio_ids.h>
-
-#include "core.h"
-#include "bus.h"
-#include "sd.h"
-#include "sdio_bus.h"
-#include "mmc_ops.h"
-#include "sd_ops.h"
-#include "sdio_ops.h"
-#include "sdio_cis.h"
-
-#ifdef CONFIG_MMC_EMBEDDED_SDIO
-#include <linux/mmc/sdio_ids.h>
-#endif
-
-static int sdio_read_fbr(struct sdio_func *func)
-{
- int ret;
- unsigned char data;
-
- if (mmc_card_nonstd_func_interface(func->card)) {
- func->class = SDIO_CLASS_NONE;
- return 0;
- }
-
- ret = mmc_io_rw_direct(func->card, 0, 0,
- SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF, 0, &data);
- if (ret)
- goto out;
-
- data &= 0x0f;
-
- if (data == 0x0f) {
- ret = mmc_io_rw_direct(func->card, 0, 0,
- SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF_EXT, 0, &data);
- if (ret)
- goto out;
- }
-
- func->class = data;
-
-out:
- return ret;
-}
-
-static int sdio_init_func(struct mmc_card *card, unsigned int fn)
-{
- int ret;
- struct sdio_func *func;
-
- BUG_ON(fn > SDIO_MAX_FUNCS);
-
- func = sdio_alloc_func(card);
- if (IS_ERR(func))
- return PTR_ERR(func);
-
- func->num = fn;
-
- if (!(card->quirks & MMC_QUIRK_NONSTD_SDIO)) {
- ret = sdio_read_fbr(func);
- if (ret)
- goto fail;
-
- ret = sdio_read_func_cis(func);
- if (ret)
- goto fail;
- } else {
- func->vendor = func->card->cis.vendor;
- func->device = func->card->cis.device;
- func->max_blksize = func->card->cis.blksize;
- }
-
- card->sdio_func[fn - 1] = func;
-
- return 0;
-
-fail:
- /*
- * It is okay to remove the function here even though we hold
- * the host lock as we haven't registered the device yet.
- */
- sdio_remove_func(func);
- return ret;
-}
-
-static int sdio_read_cccr(struct mmc_card *card, u32 ocr)
-{
- int ret;
- int cccr_vsn;
- int uhs = ocr & R4_18V_PRESENT;
- unsigned char data;
- unsigned char speed;
-
- memset(&card->cccr, 0, sizeof(struct sdio_cccr));
-
- ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data);
- if (ret)
- goto out;
-
- cccr_vsn = data & 0x0f;
-
- if (cccr_vsn > SDIO_CCCR_REV_3_00) {
- pr_err("%s: unrecognised CCCR structure version %d\n",
- mmc_hostname(card->host), cccr_vsn);
- return -EINVAL;
- }
-
- card->cccr.sdio_vsn = (data & 0xf0) >> 4;
-
- ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CAPS, 0, &data);
- if (ret)
- goto out;
-
- if (data & SDIO_CCCR_CAP_SMB)
- card->cccr.multi_block = 1;
- if (data & SDIO_CCCR_CAP_LSC)
- card->cccr.low_speed = 1;
- if (data & SDIO_CCCR_CAP_4BLS)
- card->cccr.wide_bus = 1;
-
- if (cccr_vsn >= SDIO_CCCR_REV_1_10) {
- ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_POWER, 0, &data);
- if (ret)
- goto out;
-
- if (data & SDIO_POWER_SMPC)
- card->cccr.high_power = 1;
- }
-
- if (cccr_vsn >= SDIO_CCCR_REV_1_20) {
- ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
- if (ret)
- goto out;
-
- card->scr.sda_spec3 = 0;
- card->sw_caps.sd3_bus_mode = 0;
- card->sw_caps.sd3_drv_type = 0;
- if (cccr_vsn >= SDIO_CCCR_REV_3_00 && uhs) {
- card->scr.sda_spec3 = 1;
- ret = mmc_io_rw_direct(card, 0, 0,
- SDIO_CCCR_UHS, 0, &data);
- if (ret)
- goto out;
-
- if (card->host->caps &
- (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
- MMC_CAP_UHS_DDR50)) {
- if (data & SDIO_UHS_DDR50)
- card->sw_caps.sd3_bus_mode
- |= SD_MODE_UHS_DDR50;
-
- if (data & SDIO_UHS_SDR50)
- card->sw_caps.sd3_bus_mode
- |= SD_MODE_UHS_SDR50;
-
- if (data & SDIO_UHS_SDR104)
- card->sw_caps.sd3_bus_mode
- |= SD_MODE_UHS_SDR104;
- }
-
- ret = mmc_io_rw_direct(card, 0, 0,
- SDIO_CCCR_DRIVE_STRENGTH, 0, &data);
- if (ret)
- goto out;
-
- if (data & SDIO_DRIVE_SDTA)
- card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_A;
- if (data & SDIO_DRIVE_SDTC)
- card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_C;
- if (data & SDIO_DRIVE_SDTD)
- card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_D;
- }
-
- /* if no uhs mode ensure we check for high speed */
- if (!card->sw_caps.sd3_bus_mode) {
- if (speed & SDIO_SPEED_SHS) {
- card->cccr.high_speed = 1;
- card->sw_caps.hs_max_dtr = 50000000;
- } else {
- card->cccr.high_speed = 0;
- card->sw_caps.hs_max_dtr = 25000000;
- }
- }
- }
-
-out:
- return ret;
-}
-
-static int sdio_enable_wide(struct mmc_card *card)
-{
- int ret;
- u8 ctrl;
-
- if (!(card->host->caps & MMC_CAP_4_BIT_DATA))
- return 0;
-
- if (card->cccr.low_speed && !card->cccr.wide_bus)
- return 0;
-
- ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl);
- if (ret)
- return ret;
-
- ctrl |= SDIO_BUS_WIDTH_4BIT;
-
- ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL);
- if (ret)
- return ret;
-
- return 1;
-}
-
-/*
- * If desired, disconnect the pull-up resistor on CD/DAT[3] (pin 1)
- * of the card. This may be required on certain setups of boards,
- * controllers and embedded sdio device which do not need the card's
- * pull-up. As a result, card detection is disabled and power is saved.
- */
-static int sdio_disable_cd(struct mmc_card *card)
-{
- int ret;
- u8 ctrl;
-
- if (!mmc_card_disable_cd(card))
- return 0;
-
- ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl);
- if (ret)
- return ret;
-
- ctrl |= SDIO_BUS_CD_DISABLE;
-
- return mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL);
-}
-
-/*
- * Devices that remain active during a system suspend are
- * put back into 1-bit mode.
- */
-static int sdio_disable_wide(struct mmc_card *card)
-{
- int ret;
- u8 ctrl;
-
- if (!(card->host->caps & MMC_CAP_4_BIT_DATA))
- return 0;
-
- if (card->cccr.low_speed && !card->cccr.wide_bus)
- return 0;
-
- ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl);
- if (ret)
- return ret;
-
- if (!(ctrl & SDIO_BUS_WIDTH_4BIT))
- return 0;
-
- ctrl &= ~SDIO_BUS_WIDTH_4BIT;
- ctrl |= SDIO_BUS_ASYNC_INT;
-
- ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL);
- if (ret)
- return ret;
-
- mmc_set_bus_width(card->host, MMC_BUS_WIDTH_1);
-
- return 0;
-}
-
-
-static int sdio_enable_4bit_bus(struct mmc_card *card)
-{
- int err;
-
- if (card->type == MMC_TYPE_SDIO)
- return sdio_enable_wide(card);
-
- if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
- (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
- err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
- if (err)
- return err;
- } else
- return 0;
-
- err = sdio_enable_wide(card);
- if (err <= 0)
- mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1);
-
- return err;
-}
-
-
-/*
- * Test if the card supports high-speed mode and, if so, switch to it.
- */
-static int mmc_sdio_switch_hs(struct mmc_card *card, int enable)
-{
- int ret;
- u8 speed;
-
- if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
- return 0;
-
- if (!card->cccr.high_speed)
- return 0;
-
- ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
- if (ret)
- return ret;
-
- if (enable)
- speed |= SDIO_SPEED_EHS;
- else
- speed &= ~SDIO_SPEED_EHS;
-
- ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL);
- if (ret)
- return ret;
-
- return 1;
-}
-
-/*
- * Enable SDIO/combo card's high-speed mode. Return 0/1 if [not]supported.
- */
-static int sdio_enable_hs(struct mmc_card *card)
-{
- int ret;
-
- ret = mmc_sdio_switch_hs(card, true);
- if (ret <= 0 || card->type == MMC_TYPE_SDIO)
- return ret;
-
- ret = mmc_sd_switch_hs(card);
- if (ret <= 0)
- mmc_sdio_switch_hs(card, false);
-
- return ret;
-}
-
-static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
-{
- unsigned max_dtr;
-
- if (mmc_card_highspeed(card)) {
- /*
- * The SDIO specification doesn't mention how
- * the CIS transfer speed register relates to
- * high-speed, but it seems that 50 MHz is
- * mandatory.
- */
- max_dtr = 50000000;
- } else {
- max_dtr = card->cis.max_dtr;
- }
-
- if (card->type == MMC_TYPE_SD_COMBO)
- max_dtr = min(max_dtr, mmc_sd_get_max_clock(card));
-
- return max_dtr;
-}
-
-static unsigned char host_drive_to_sdio_drive(int host_strength)
-{
- switch (host_strength) {
- case MMC_SET_DRIVER_TYPE_A:
- return SDIO_DTSx_SET_TYPE_A;
- case MMC_SET_DRIVER_TYPE_B:
- return SDIO_DTSx_SET_TYPE_B;
- case MMC_SET_DRIVER_TYPE_C:
- return SDIO_DTSx_SET_TYPE_C;
- case MMC_SET_DRIVER_TYPE_D:
- return SDIO_DTSx_SET_TYPE_D;
- default:
- return SDIO_DTSx_SET_TYPE_B;
- }
-}
-
-static void sdio_select_driver_type(struct mmc_card *card)
-{
- int host_drv_type = SD_DRIVER_TYPE_B;
- int card_drv_type = SD_DRIVER_TYPE_B;
- int drive_strength;
- unsigned char card_strength;
- int err;
-
- /*
- * If the host doesn't support any of the Driver Types A,C or D,
- * or there is no board specific handler then default Driver
- * Type B is used.
- */
- if (!(card->host->caps &
- (MMC_CAP_DRIVER_TYPE_A |
- MMC_CAP_DRIVER_TYPE_C |
- MMC_CAP_DRIVER_TYPE_D)))
- return;
-
- if (!card->host->ops->select_drive_strength)
- return;
-
- if (card->host->caps & MMC_CAP_DRIVER_TYPE_A)
- host_drv_type |= SD_DRIVER_TYPE_A;
-
- if (card->host->caps & MMC_CAP_DRIVER_TYPE_C)
- host_drv_type |= SD_DRIVER_TYPE_C;
-
- if (card->host->caps & MMC_CAP_DRIVER_TYPE_D)
- host_drv_type |= SD_DRIVER_TYPE_D;
-
- if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A)
- card_drv_type |= SD_DRIVER_TYPE_A;
-
- if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
- card_drv_type |= SD_DRIVER_TYPE_C;
-
- if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_D)
- card_drv_type |= SD_DRIVER_TYPE_D;
-
- /*
- * The drive strength that the hardware can support
- * depends on the board design. Pass the appropriate
- * information and let the hardware specific code
- * return what is possible given the options
- */
- drive_strength = card->host->ops->select_drive_strength(
- card->sw_caps.uhs_max_dtr,
- host_drv_type, card_drv_type);
-
- /* if error just use default for drive strength B */
- err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_DRIVE_STRENGTH, 0,
- &card_strength);
- if (err)
- return;
-
- card_strength &= ~(SDIO_DRIVE_DTSx_MASK<<SDIO_DRIVE_DTSx_SHIFT);
- card_strength |= host_drive_to_sdio_drive(drive_strength);
-
- err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_DRIVE_STRENGTH,
- card_strength, NULL);
-
- /* if error default to drive strength B */
- if (!err)
- mmc_set_driver_type(card->host, drive_strength);
-}
-
-
-static int sdio_set_bus_speed_mode(struct mmc_card *card)
-{
- unsigned int bus_speed, timing;
- int err;
- unsigned char speed;
-
- /*
- * If the host doesn't support any of the UHS-I modes, fallback on
- * default speed.
- */
- if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50)))
- return 0;
-
- bus_speed = SDIO_SPEED_SDR12;
- timing = MMC_TIMING_UHS_SDR12;
- if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
- (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) {
- bus_speed = SDIO_SPEED_SDR104;
- timing = MMC_TIMING_UHS_SDR104;
- card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
- } else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
- (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
- bus_speed = SDIO_SPEED_DDR50;
- timing = MMC_TIMING_UHS_DDR50;
- card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
- } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
- MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
- SD_MODE_UHS_SDR50)) {
- bus_speed = SDIO_SPEED_SDR50;
- timing = MMC_TIMING_UHS_SDR50;
- card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
- } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
- (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
- bus_speed = SDIO_SPEED_SDR25;
- timing = MMC_TIMING_UHS_SDR25;
- card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
- } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
- SD_MODE_UHS_SDR12)) {
- bus_speed = SDIO_SPEED_SDR12;
- timing = MMC_TIMING_UHS_SDR12;
- card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
- }
-
- err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);
- if (err)
- return err;
-
- speed &= ~SDIO_SPEED_BSS_MASK;
- speed |= bus_speed;
- err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL);
- if (err)
- return err;
-
- if (bus_speed) {
- mmc_set_timing(card->host, timing);
- mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
- }
-
- return 0;
-}
-
-/*
- * UHS-I specific initialization procedure
- */
-static int mmc_sdio_init_uhs_card(struct mmc_card *card)
-{
- int err;
-
- if (!card->scr.sda_spec3)
- return 0;
-
- /*
- * Switch to wider bus (if supported).
- */
- if (card->host->caps & MMC_CAP_4_BIT_DATA) {
- err = sdio_enable_4bit_bus(card);
- if (err > 0) {
- mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
- err = 0;
- }
- }
-
- /* Set the driver strength for the card */
- sdio_select_driver_type(card);
-
- /* Set bus speed mode of the card */
- err = sdio_set_bus_speed_mode(card);
- if (err)
- goto out;
-
- /* Initialize and start re-tuning timer */
- if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
- err = card->host->ops->execute_tuning(card->host,
- MMC_SEND_TUNING_BLOCK);
-
-out:
-
- return err;
-}
-
-/*
- * Handle the detection and initialisation of a card.
- *
- * In the case of a resume, "oldcard" will contain the card
- * we're trying to reinitialise.
- */
-static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
- struct mmc_card *oldcard, int powered_resume)
-{
- struct mmc_card *card;
- int err;
-
- BUG_ON(!host);
- WARN_ON(!host->claimed);
-
- /*
- * Inform the card of the voltage
- */
- if (!powered_resume) {
- /* The initialization should be done at 3.3 V I/O voltage. */
- mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
-
- err = mmc_send_io_op_cond(host, host->ocr, &ocr);
- if (err)
- goto err;
- }
-
- /*
- * For SPI, enable CRC as appropriate.
- */
- if (mmc_host_is_spi(host)) {
- err = mmc_spi_set_crc(host, use_spi_crc);
- if (err)
- goto err;
- }
-
- /*
- * Allocate card structure.
- */
- card = mmc_alloc_card(host, NULL);
- if (IS_ERR(card)) {
- err = PTR_ERR(card);
- goto err;
- }
-
- if ((ocr & R4_MEMORY_PRESENT) &&
- mmc_sd_get_cid(host, host->ocr & ocr, card->raw_cid, NULL) == 0) {
- card->type = MMC_TYPE_SD_COMBO;
-
- if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO ||
- memcmp(card->raw_cid, oldcard->raw_cid, sizeof(card->raw_cid)) != 0)) {
- mmc_remove_card(card);
- return -ENOENT;
- }
- } else {
- card->type = MMC_TYPE_SDIO;
-
- if (oldcard && oldcard->type != MMC_TYPE_SDIO) {
- mmc_remove_card(card);
- return -ENOENT;
- }
- }
-
- /*
- * Call the optional HC's init_card function to handle quirks.
- */
- if (host->ops->init_card)
- host->ops->init_card(host, card);
-
- /*
- * If the host and card support UHS-I mode request the card
- * to switch to 1.8V signaling level. No 1.8v signalling if
- * UHS mode is not enabled to maintain compatibilty and some
- * systems that claim 1.8v signalling in fact do not support
- * it.
- */
- if ((ocr & R4_18V_PRESENT) &&
- (host->caps &
- (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 |
- MMC_CAP_UHS_DDR50))) {
- err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
- true);
- if (err) {
- ocr &= ~R4_18V_PRESENT;
- host->ocr &= ~R4_18V_PRESENT;
- }
- err = 0;
- } else {
- ocr &= ~R4_18V_PRESENT;
- host->ocr &= ~R4_18V_PRESENT;
- }
-
- /*
- * For native busses: set card RCA and quit open drain mode.
- */
- if (!powered_resume && !mmc_host_is_spi(host)) {
- err = mmc_send_relative_addr(host, &card->rca);
- if (err)
- goto remove;
-
- /*
- * Update oldcard with the new RCA received from the SDIO
- * device -- we're doing this so that it's updated in the
- * "card" struct when oldcard overwrites that later.
- */
- if (oldcard)
- oldcard->rca = card->rca;
- }
-
- /*
- * Read CSD, before selecting the card
- */
- if (!oldcard && card->type == MMC_TYPE_SD_COMBO) {
- err = mmc_sd_get_csd(host, card);
- if (err)
- return err;
-
- mmc_decode_cid(card);
- }
-
- /*
- * Select card, as all following commands rely on that.
- */
- if (!powered_resume && !mmc_host_is_spi(host)) {
- err = mmc_select_card(card);
- if (err)
- goto remove;
- }
-
- if (card->quirks & MMC_QUIRK_NONSTD_SDIO) {
- /*
- * This is non-standard SDIO device, meaning it doesn't
- * have any CIA (Common I/O area) registers present.
- * It's host's responsibility to fill cccr and cis
- * structures in init_card().
- */
- mmc_set_clock(host, card->cis.max_dtr);
-
- if (card->cccr.high_speed) {
- mmc_card_set_highspeed(card);
- mmc_set_timing(card->host, MMC_TIMING_SD_HS);
- }
-
- goto finish;
- }
-
-#ifdef CONFIG_MMC_EMBEDDED_SDIO
- if (host->embedded_sdio_data.cccr)
- memcpy(&card->cccr, host->embedded_sdio_data.cccr, sizeof(struct sdio_cccr));
- else {
-#endif
- /*
- * Read the common registers.
- */
- err = sdio_read_cccr(card, ocr);
- if (err)
- goto remove;
-#ifdef CONFIG_MMC_EMBEDDED_SDIO
- }
-#endif
-
-#ifdef CONFIG_MMC_EMBEDDED_SDIO
- if (host->embedded_sdio_data.cis)
- memcpy(&card->cis, host->embedded_sdio_data.cis, sizeof(struct sdio_cis));
- else {
-#endif
- /*
- * Read the common CIS tuples.
- */
- err = sdio_read_common_cis(card);
- if (err)
- goto remove;
-#ifdef CONFIG_MMC_EMBEDDED_SDIO
- }
-#endif
-
- if (oldcard) {
- int same = (card->cis.vendor == oldcard->cis.vendor &&
- card->cis.device == oldcard->cis.device);
- mmc_remove_card(card);
- if (!same)
- return -ENOENT;
-
- card = oldcard;
- }
- mmc_fixup_device(card, NULL);
-
- if (card->type == MMC_TYPE_SD_COMBO) {
- err = mmc_sd_setup_card(host, card, oldcard != NULL);
- /* handle as SDIO-only card if memory init failed */
- if (err) {
- mmc_go_idle(host);
- if (mmc_host_is_spi(host))
- /* should not fail, as it worked previously */
- mmc_spi_set_crc(host, use_spi_crc);
- card->type = MMC_TYPE_SDIO;
- } else
- card->dev.type = &sd_type;
- }
-
- /*
- * If needed, disconnect card detection pull-up resistor.
- */
- err = sdio_disable_cd(card);
- if (err)
- goto remove;
-
- /* Initialization sequence for UHS-I cards */
- /* Only if card supports 1.8v and UHS signaling */
- if ((ocr & R4_18V_PRESENT) && card->sw_caps.sd3_bus_mode) {
- err = mmc_sdio_init_uhs_card(card);
- if (err)
- goto remove;
-
- /* Card is an ultra-high-speed card */
- mmc_card_set_uhs(card);
- } else {
- /*
- * Switch to high-speed (if supported).
- */
- err = sdio_enable_hs(card);
- if (err > 0)
- mmc_sd_go_highspeed(card);
- else if (err)
- goto remove;
-
- /*
- * Change to the card's maximum speed.
- */
- mmc_set_clock(host, mmc_sdio_get_max_clock(card));
-
- /*
- * Switch to wider bus (if supported).
- */
- err = sdio_enable_4bit_bus(card);
- if (err > 0)
- mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
- else if (err)
- goto remove;
- }
-finish:
- if (!oldcard)
- host->card = card;
- return 0;
-
-remove:
- if (!oldcard)
- mmc_remove_card(card);
-
-err:
- return err;
-}
-
-/*
- * Host is being removed. Free up the current card.
- */
-static void mmc_sdio_remove(struct mmc_host *host)
-{
- int i;
-
- BUG_ON(!host);
- BUG_ON(!host->card);
-
- for (i = 0;i < host->card->sdio_funcs;i++) {
- if (host->card->sdio_func[i]) {
- sdio_remove_func(host->card->sdio_func[i]);
- host->card->sdio_func[i] = NULL;
- }
- }
-
- mmc_remove_card(host->card);
- host->card = NULL;
-}
-
-/*
- * Card detection - card is alive.
- */
-static int mmc_sdio_alive(struct mmc_host *host)
-{
- return mmc_select_card(host->card);
-}
-
-/*
- * Card detection callback from host.
- */
-static void mmc_sdio_detect(struct mmc_host *host)
-{
- int err;
-
- BUG_ON(!host);
- BUG_ON(!host->card);
-
- /* Make sure card is powered before detecting it */
- if (host->caps & MMC_CAP_POWER_OFF_CARD) {
- err = pm_runtime_get_sync(&host->card->dev);
- if (err < 0)
- goto out;
- }
-
- mmc_claim_host(host);
-
- /*
- * Just check if our card has been removed.
- */
- err = _mmc_detect_card_removed(host);
-
- mmc_release_host(host);
-
- /*
- * Tell PM core it's OK to power off the card now.
- *
- * The _sync variant is used in order to ensure that the card
- * is left powered off in case an error occurred, and the card
- * is going to be removed.
- *
- * Since there is no specific reason to believe a new user
- * is about to show up at this point, the _sync variant is
- * desirable anyway.
- */
- if (host->caps & MMC_CAP_POWER_OFF_CARD)
- pm_runtime_put_sync(&host->card->dev);
-
-out:
- if (err) {
- mmc_sdio_remove(host);
-
- mmc_claim_host(host);
- mmc_detach_bus(host);
- mmc_power_off(host);
- mmc_release_host(host);
- }
-}
-
-/*
- * SDIO suspend. We need to suspend all functions separately.
- * Therefore all registered functions must have drivers with suspend
- * and resume methods. Failing that we simply remove the whole card.
- */
-static int mmc_sdio_suspend(struct mmc_host *host)
-{
- int i, err = 0;
-
- for (i = 0; i < host->card->sdio_funcs; i++) {
- struct sdio_func *func = host->card->sdio_func[i];
- if (func && sdio_func_present(func) && func->dev.driver) {
- const struct dev_pm_ops *pmops = func->dev.driver->pm;
- if (!pmops || !pmops->suspend || !pmops->resume) {
- /* force removal of entire card in that case */
- err = -ENOSYS;
- } else
- err = pmops->suspend(&func->dev);
- if (err)
- break;
- }
- }
- while (err && --i >= 0) {
- struct sdio_func *func = host->card->sdio_func[i];
- if (func && sdio_func_present(func) && func->dev.driver) {
- const struct dev_pm_ops *pmops = func->dev.driver->pm;
- pmops->resume(&func->dev);
- }
- }
-
- if (!err && mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
- mmc_claim_host(host);
- sdio_disable_wide(host->card);
- mmc_release_host(host);
- }
-
- return err;
-}
-
-static int mmc_sdio_resume(struct mmc_host *host)
-{
- int i, err = 0;
-
- BUG_ON(!host);
- BUG_ON(!host->card);
-
- /* Basic card reinitialization. */
- mmc_claim_host(host);
-
- /* No need to reinitialize powered-resumed nonremovable cards */
- if (mmc_card_is_removable(host) || !mmc_card_keep_power(host))
- err = mmc_sdio_init_card(host, host->ocr, host->card,
- mmc_card_keep_power(host));
- else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
- /* 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)
- wake_up_process(host->sdio_irq_thread);
- mmc_release_host(host);
-
- /*
- * If the card looked to be the same as before suspending, then
- * we proceed to resume all card functions. If one of them returns
- * an error then we simply return that error to the core and the
- * card will be redetected as new. It is the responsibility of
- * the function driver to perform further tests with the extra
- * knowledge it has of the card to confirm the card is indeed the
- * same as before suspending (same MAC address for network cards,
- * etc.) and return an error otherwise.
- */
- for (i = 0; !err && i < host->card->sdio_funcs; i++) {
- struct sdio_func *func = host->card->sdio_func[i];
- if (func && sdio_func_present(func) && func->dev.driver) {
- const struct dev_pm_ops *pmops = func->dev.driver->pm;
- err = pmops->resume(&func->dev);
- }
- }
-
- return err;
-}
-
-static int mmc_sdio_power_restore(struct mmc_host *host)
-{
- int ret;
- u32 ocr;
-
- BUG_ON(!host);
- BUG_ON(!host->card);
-
- mmc_claim_host(host);
-
- /*
- * Reset the card by performing the same steps that are taken by
- * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe.
- *
- * sdio_reset() is technically not needed. Having just powered up the
- * hardware, it should already be in reset state. However, some
- * platforms (such as SD8686 on OLPC) do not instantly cut power,
- * meaning that a reset is required when restoring power soon after
- * powering off. It is harmless in other cases.
- *
- * The CMD5 reset (mmc_send_io_op_cond()), according to the SDIO spec,
- * is not necessary for non-removable cards. However, it is required
- * for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and
- * harmless in other situations.
- *
- * With these steps taken, mmc_select_voltage() is also required to
- * restore the correct voltage setting of the card.
- */
-
- /* The initialization should be done at 3.3 V I/O voltage. */
- if (!mmc_card_keep_power(host))
- mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, 0);
-
- sdio_reset(host);
- mmc_go_idle(host);
- mmc_send_if_cond(host, host->ocr_avail);
-
- ret = mmc_send_io_op_cond(host, 0, &ocr);
- if (ret)
- goto out;
-
- if (host->ocr_avail_sdio)
- host->ocr_avail = host->ocr_avail_sdio;
-
- host->ocr = mmc_select_voltage(host, ocr & ~0x7F);
- if (!host->ocr) {
- ret = -EINVAL;
- goto out;
- }
-
- ret = mmc_sdio_init_card(host, host->ocr, host->card,
- mmc_card_keep_power(host));
- if (!ret && host->sdio_irqs)
- mmc_signal_sdio_irq(host);
-
-out:
- 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,
- .alive = mmc_sdio_alive,
-};
-
-
-/*
- * Starting point for SDIO card init.
- */
-int mmc_attach_sdio(struct mmc_host *host)
-{
- int err, i, funcs;
- u32 ocr;
- struct mmc_card *card;
-
- BUG_ON(!host);
- WARN_ON(!host->claimed);
-
- err = mmc_send_io_op_cond(host, 0, &ocr);
- if (err)
- return err;
-
- mmc_attach_bus(host, &mmc_sdio_ops);
- if (host->ocr_avail_sdio)
- host->ocr_avail = host->ocr_avail_sdio;
-
- /*
- * Sanity check the voltages that the card claims to
- * support.
- */
- if (ocr & 0x7F) {
- pr_warning("%s: card claims to support voltages "
- "below the defined range. These will be ignored.\n",
- mmc_hostname(host));
- ocr &= ~0x7F;
- }
-
- host->ocr = mmc_select_voltage(host, ocr);
-
- /*
- * Can we support the voltage(s) of the card(s)?
- */
- if (!host->ocr) {
- err = -EINVAL;
- goto err;
- }
-
- /*
- * Detect and init the card.
- */
- err = mmc_sdio_init_card(host, host->ocr, NULL, 0);
- if (err) {
- if (err == -EAGAIN) {
- /*
- * Retry initialization with S18R set to 0.
- */
- host->ocr &= ~R4_18V_PRESENT;
- err = mmc_sdio_init_card(host, host->ocr, NULL, 0);
- }
- if (err)
- goto err;
- }
- card = host->card;
-
- /*
- * Enable runtime PM only if supported by host+card+board
- */
- if (host->caps & MMC_CAP_POWER_OFF_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.
- */
- funcs = (ocr & 0x70000000) >> 28;
- card->sdio_funcs = 0;
-
-#ifdef CONFIG_MMC_EMBEDDED_SDIO
- if (host->embedded_sdio_data.funcs)
- card->sdio_funcs = funcs = host->embedded_sdio_data.num_funcs;
-#endif
-
- /*
- * Initialize (but don't add) all present functions.
- */
- for (i = 0; i < funcs; i++, card->sdio_funcs++) {
-#ifdef CONFIG_MMC_EMBEDDED_SDIO
- if (host->embedded_sdio_data.funcs) {
- struct sdio_func *tmp;
-
- tmp = sdio_alloc_func(host->card);
- if (IS_ERR(tmp))
- goto remove;
- tmp->num = (i + 1);
- card->sdio_func[i] = tmp;
- tmp->class = host->embedded_sdio_data.funcs[i].f_class;
- tmp->max_blksize = host->embedded_sdio_data.funcs[i].f_maxblksize;
- tmp->vendor = card->cis.vendor;
- tmp->device = card->cis.device;
- } else {
-#endif
- err = sdio_init_func(host->card, i + 1);
- if (err)
- goto remove;
-#ifdef CONFIG_MMC_EMBEDDED_SDIO
- }
-#endif
- /*
- * Enable Runtime PM for this func (if supported)
- */
- if (host->caps & MMC_CAP_POWER_OFF_CARD)
- pm_runtime_enable(&card->sdio_func[i]->dev);
- }
-
- /*
- * First add the card to the driver model...
- */
- mmc_release_host(host);
- err = mmc_add_card(host->card);
- if (err)
- goto remove_added;
-
- /*
- * ...then the SDIO functions.
- */
- for (i = 0;i < funcs;i++) {
- err = sdio_add_func(host->card->sdio_func[i]);
- if (err)
- goto remove_added;
- }
-
- mmc_claim_host(host);
- return 0;
-
-
-remove_added:
- /* Remove without lock if the device has been added. */
- mmc_sdio_remove(host);
- mmc_claim_host(host);
-remove:
- /* And with lock if it hasn't been added. */
- mmc_release_host(host);
- if (host->card)
- mmc_sdio_remove(host);
- mmc_claim_host(host);
-err:
- mmc_detach_bus(host);
-
- pr_err("%s: error %d whilst initialising SDIO card\n",
- mmc_hostname(host), err);
-
- return err;
-}
-
-int sdio_reset_comm(struct mmc_card *card)
-{
- struct mmc_host *host = card->host;
- u32 ocr;
- int err;
-
- printk("%s():\n", __func__);
- mmc_claim_host(host);
-
- mmc_go_idle(host);
-
- mmc_set_clock(host, host->f_min);
-
- err = mmc_send_io_op_cond(host, 0, &ocr);
- if (err)
- goto err;
-
- host->ocr = mmc_select_voltage(host, ocr);
- if (!host->ocr) {
- err = -EINVAL;
- goto err;
- }
-
- err = mmc_sdio_init_card(host, host->ocr, card, 0);
- if (err)
- goto err;
-
- mmc_release_host(host);
- return 0;
-err:
- printk("%s: Error resetting SDIO communications (%d)\n",
- mmc_hostname(host), err);
- mmc_release_host(host);
- return err;
-}
-EXPORT_SYMBOL(sdio_reset_comm);
diff --git a/ANDROID_3.4.5/drivers/mmc/core/sdio_bus.c b/ANDROID_3.4.5/drivers/mmc/core/sdio_bus.c
deleted file mode 100644
index 56d020e2..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/sdio_bus.c
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * linux/drivers/mmc/core/sdio_bus.c
- *
- * Copyright 2007 Pierre Ossman
- *
- * 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.
- *
- * SDIO function driver model
- */
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include <linux/pm_runtime.h>
-
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/sdio_func.h>
-
-#include "sdio_cis.h"
-#include "sdio_bus.h"
-
-#ifdef CONFIG_MMC_EMBEDDED_SDIO
-#include <linux/mmc/host.h>
-#endif
-
-/* show configuration fields */
-#define sdio_config_attr(field, format_string) \
-static ssize_t \
-field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
-{ \
- struct sdio_func *func; \
- \
- func = dev_to_sdio_func (dev); \
- return sprintf (buf, format_string, func->field); \
-}
-
-sdio_config_attr(class, "0x%02x\n");
-sdio_config_attr(vendor, "0x%04x\n");
-sdio_config_attr(device, "0x%04x\n");
-
-static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct sdio_func *func = dev_to_sdio_func (dev);
-
- return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n",
- func->class, func->vendor, func->device);
-}
-
-static struct device_attribute sdio_dev_attrs[] = {
- __ATTR_RO(class),
- __ATTR_RO(vendor),
- __ATTR_RO(device),
- __ATTR_RO(modalias),
- __ATTR_NULL,
-};
-
-static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,
- const struct sdio_device_id *id)
-{
- if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class)
- return NULL;
- if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor)
- return NULL;
- if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device)
- return NULL;
- return id;
-}
-
-static const struct sdio_device_id *sdio_match_device(struct sdio_func *func,
- struct sdio_driver *sdrv)
-{
- const struct sdio_device_id *ids;
-
- ids = sdrv->id_table;
-
- if (ids) {
- while (ids->class || ids->vendor || ids->device) {
- if (sdio_match_one(func, ids))
- return ids;
- ids++;
- }
- }
-
- return NULL;
-}
-
-static int sdio_bus_match(struct device *dev, struct device_driver *drv)
-{
- struct sdio_func *func = dev_to_sdio_func(dev);
- struct sdio_driver *sdrv = to_sdio_driver(drv);
-
- if (sdio_match_device(func, sdrv))
- return 1;
-
- return 0;
-}
-
-static int
-sdio_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- struct sdio_func *func = dev_to_sdio_func(dev);
-
- if (add_uevent_var(env,
- "SDIO_CLASS=%02X", func->class))
- return -ENOMEM;
-
- if (add_uevent_var(env,
- "SDIO_ID=%04X:%04X", func->vendor, func->device))
- return -ENOMEM;
-
- if (add_uevent_var(env,
- "MODALIAS=sdio:c%02Xv%04Xd%04X",
- func->class, func->vendor, func->device))
- return -ENOMEM;
-
- return 0;
-}
-
-static int sdio_bus_probe(struct device *dev)
-{
- struct sdio_driver *drv = to_sdio_driver(dev->driver);
- struct sdio_func *func = dev_to_sdio_func(dev);
- const struct sdio_device_id *id;
- int ret;
-
- id = sdio_match_device(func, drv);
- 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.
- */
- if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) {
- 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)
- goto disable_runtimepm;
-
- ret = drv->probe(func, id);
- if (ret)
- goto disable_runtimepm;
-
- return 0;
-
-disable_runtimepm:
- if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
- 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 = 0;
-
- /* Make sure card is powered before invoking ->remove() */
- if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
- pm_runtime_get_sync(dev);
-
- drv->remove(func);
-
- if (func->irq_handler) {
- pr_warning("WARNING: driver %s did not remove "
- "its interrupt handler!\n", drv->name);
- sdio_claim_host(func);
- sdio_release_irq(func);
- sdio_release_host(func);
- }
-
- /* First, undo the increment made directly above */
- if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
- pm_runtime_put_noidle(dev);
-
- /* Then undo the runtime PM settings in sdio_bus_probe() */
- if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
- pm_runtime_put_sync(dev);
-
- return ret;
-}
-
-#ifdef CONFIG_PM
-
-static int pm_no_operation(struct device *dev)
-{
- return 0;
-}
-
-static const struct dev_pm_ops sdio_bus_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(pm_no_operation, pm_no_operation)
- SET_RUNTIME_PM_OPS(
- pm_generic_runtime_suspend,
- pm_generic_runtime_resume,
- pm_generic_runtime_idle
- )
-};
-
-#define SDIO_PM_OPS_PTR (&sdio_bus_pm_ops)
-
-#else /* !CONFIG_PM */
-
-#define SDIO_PM_OPS_PTR NULL
-
-#endif /* !CONFIG_PM */
-
-static struct bus_type sdio_bus_type = {
- .name = "sdio",
- .dev_attrs = sdio_dev_attrs,
- .match = sdio_bus_match,
- .uevent = sdio_bus_uevent,
- .probe = sdio_bus_probe,
- .remove = sdio_bus_remove,
- .pm = SDIO_PM_OPS_PTR,
-};
-
-int sdio_register_bus(void)
-{
- return bus_register(&sdio_bus_type);
-}
-
-void sdio_unregister_bus(void)
-{
- bus_unregister(&sdio_bus_type);
-}
-
-/**
- * sdio_register_driver - register a function driver
- * @drv: SDIO function driver
- */
-int sdio_register_driver(struct sdio_driver *drv)
-{
- drv->drv.name = drv->name;
- drv->drv.bus = &sdio_bus_type;
- return driver_register(&drv->drv);
-}
-EXPORT_SYMBOL_GPL(sdio_register_driver);
-
-/**
- * sdio_unregister_driver - unregister a function driver
- * @drv: SDIO function driver
- */
-void sdio_unregister_driver(struct sdio_driver *drv)
-{
- drv->drv.bus = &sdio_bus_type;
- driver_unregister(&drv->drv);
-}
-EXPORT_SYMBOL_GPL(sdio_unregister_driver);
-
-static void sdio_release_func(struct device *dev)
-{
- struct sdio_func *func = dev_to_sdio_func(dev);
-
-#ifdef CONFIG_MMC_EMBEDDED_SDIO
- /*
- * If this device is embedded then we never allocated
- * cis tables for this func
- */
- if (!func->card->host->embedded_sdio_data.funcs)
-#endif
- sdio_free_func_cis(func);
-
- if (func->info)
- kfree(func->info);
-
- kfree(func);
-}
-
-/*
- * Allocate and initialise a new SDIO function structure.
- */
-struct sdio_func *sdio_alloc_func(struct mmc_card *card)
-{
- struct sdio_func *func;
-
- func = kzalloc(sizeof(struct sdio_func), GFP_KERNEL);
- if (!func)
- return ERR_PTR(-ENOMEM);
-
- func->card = card;
-
- device_initialize(&func->dev);
-
- func->dev.parent = &card->dev;
- func->dev.bus = &sdio_bus_type;
- func->dev.release = sdio_release_func;
-
- return func;
-}
-
-/*
- * Register a new SDIO function with the driver model.
- */
-int sdio_add_func(struct sdio_func *func)
-{
- int ret;
-
- dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num);
-
- ret = device_add(&func->dev);
- if (ret == 0)
- sdio_func_set_present(func);
-
- return ret;
-}
-
-/*
- * Unregister a SDIO function with the driver model, and
- * (eventually) free it.
- * This function can be called through error paths where sdio_add_func() was
- * never executed (because a failure occurred at an earlier point).
- */
-void sdio_remove_func(struct sdio_func *func)
-{
- if (!sdio_func_present(func))
- return;
-
- device_del(&func->dev);
- put_device(&func->dev);
-}
-
diff --git a/ANDROID_3.4.5/drivers/mmc/core/sdio_bus.h b/ANDROID_3.4.5/drivers/mmc/core/sdio_bus.h
deleted file mode 100644
index 567a7682..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/sdio_bus.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * linux/drivers/mmc/core/sdio_bus.h
- *
- * Copyright 2007 Pierre Ossman
- *
- * 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 _MMC_CORE_SDIO_BUS_H
-#define _MMC_CORE_SDIO_BUS_H
-
-struct sdio_func *sdio_alloc_func(struct mmc_card *card);
-int sdio_add_func(struct sdio_func *func);
-void sdio_remove_func(struct sdio_func *func);
-
-int sdio_register_bus(void);
-void sdio_unregister_bus(void);
-
-#endif
-
diff --git a/ANDROID_3.4.5/drivers/mmc/core/sdio_cis.c b/ANDROID_3.4.5/drivers/mmc/core/sdio_cis.c
deleted file mode 100644
index f1c7ed8f..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/sdio_cis.c
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * linux/drivers/mmc/core/sdio_cis.c
- *
- * Author: Nicolas Pitre
- * Created: June 11, 2007
- * Copyright: MontaVista Software Inc.
- *
- * Copyright 2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/sdio_func.h>
-
-#include "sdio_cis.h"
-#include "sdio_ops.h"
-
-static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
- const unsigned char *buf, unsigned size)
-{
- unsigned i, nr_strings;
- char **buffer, *string;
-
- /* Find all null-terminated (including zero length) strings in
- the TPLLV1_INFO field. Trailing garbage is ignored. */
- buf += 2;
- size -= 2;
-
- nr_strings = 0;
- for (i = 0; i < size; i++) {
- if (buf[i] == 0xff)
- break;
- if (buf[i] == 0)
- nr_strings++;
- }
- if (nr_strings == 0)
- return 0;
-
- size = i;
-
- buffer = kzalloc(sizeof(char*) * nr_strings + size, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- string = (char*)(buffer + nr_strings);
-
- for (i = 0; i < nr_strings; i++) {
- buffer[i] = string;
- strcpy(string, buf);
- string += strlen(string) + 1;
- buf += strlen(buf) + 1;
- }
-
- if (func) {
- func->num_info = nr_strings;
- func->info = (const char**)buffer;
- } else {
- card->num_info = nr_strings;
- card->info = (const char**)buffer;
- }
-
- return 0;
-}
-
-static int cistpl_manfid(struct mmc_card *card, struct sdio_func *func,
- const unsigned char *buf, unsigned size)
-{
- unsigned int vendor, device;
-
- /* TPLMID_MANF */
- vendor = buf[0] | (buf[1] << 8);
-
- /* TPLMID_CARD */
- device = buf[2] | (buf[3] << 8);
-
- if (func) {
- func->vendor = vendor;
- func->device = device;
- } else {
- card->cis.vendor = vendor;
- card->cis.device = device;
- }
-
- return 0;
-}
-
-static const unsigned char speed_val[16] =
- { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 };
-static const unsigned int speed_unit[8] =
- { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 };
-
-
-typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *,
- const unsigned char *, unsigned);
-
-struct cis_tpl {
- unsigned char code;
- unsigned char min_size;
- tpl_parse_t *parse;
-};
-
-static int cis_tpl_parse(struct mmc_card *card, struct sdio_func *func,
- const char *tpl_descr,
- const struct cis_tpl *tpl, int tpl_count,
- unsigned char code,
- const unsigned char *buf, unsigned size)
-{
- int i, ret;
-
- /* look for a matching code in the table */
- for (i = 0; i < tpl_count; i++, tpl++) {
- if (tpl->code == code)
- break;
- }
- if (i < tpl_count) {
- if (size >= tpl->min_size) {
- if (tpl->parse)
- ret = tpl->parse(card, func, buf, size);
- else
- ret = -EILSEQ; /* known tuple, not parsed */
- } else {
- /* invalid tuple */
- ret = -EINVAL;
- }
- if (ret && ret != -EILSEQ && ret != -ENOENT) {
- pr_err("%s: bad %s tuple 0x%02x (%u bytes)\n",
- mmc_hostname(card->host), tpl_descr, code, size);
- }
- } else {
- /* unknown tuple */
- ret = -ENOENT;
- }
-
- return ret;
-}
-
-static int cistpl_funce_common(struct mmc_card *card, struct sdio_func *func,
- const unsigned char *buf, unsigned size)
-{
- /* Only valid for the common CIS (function 0) */
- if (func)
- return -EINVAL;
-
- /* TPLFE_FN0_BLK_SIZE */
- card->cis.blksize = buf[1] | (buf[2] << 8);
-
- /* TPLFE_MAX_TRAN_SPEED */
- card->cis.max_dtr = speed_val[(buf[3] >> 3) & 15] *
- speed_unit[buf[3] & 7];
-
- return 0;
-}
-
-static int cistpl_funce_func(struct mmc_card *card, struct sdio_func *func,
- const unsigned char *buf, unsigned size)
-{
- unsigned vsn;
- unsigned min_size;
-
- /* Only valid for the individual function's CIS (1-7) */
- if (!func)
- return -EINVAL;
-
- /*
- * This tuple has a different length depending on the SDIO spec
- * version.
- */
- vsn = func->card->cccr.sdio_vsn;
- min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42;
-
- if (size < min_size)
- return -EINVAL;
-
- /* TPLFE_MAX_BLK_SIZE */
- func->max_blksize = buf[12] | (buf[13] << 8);
-
- /* TPLFE_ENABLE_TIMEOUT_VAL, present in ver 1.1 and above */
- if (vsn > SDIO_SDIO_REV_1_00)
- func->enable_timeout = (buf[28] | (buf[29] << 8)) * 10;
- else
- func->enable_timeout = jiffies_to_msecs(HZ);
-
- return 0;
-}
-
-/*
- * Known TPLFE_TYPEs table for CISTPL_FUNCE tuples.
- *
- * Note that, unlike PCMCIA, CISTPL_FUNCE tuples are not parsed depending
- * on the TPLFID_FUNCTION value of the previous CISTPL_FUNCID as on SDIO
- * TPLFID_FUNCTION is always hardcoded to 0x0C.
- */
-static const struct cis_tpl cis_tpl_funce_list[] = {
- { 0x00, 4, cistpl_funce_common },
- { 0x01, 0, cistpl_funce_func },
- { 0x04, 1+1+6, /* CISTPL_FUNCE_LAN_NODE_ID */ },
-};
-
-static int cistpl_funce(struct mmc_card *card, struct sdio_func *func,
- const unsigned char *buf, unsigned size)
-{
- if (size < 1)
- return -EINVAL;
-
- return cis_tpl_parse(card, func, "CISTPL_FUNCE",
- cis_tpl_funce_list,
- ARRAY_SIZE(cis_tpl_funce_list),
- buf[0], buf, size);
-}
-
-/* Known TPL_CODEs table for CIS tuples */
-static const struct cis_tpl cis_tpl_list[] = {
- { 0x15, 3, cistpl_vers_1 },
- { 0x20, 4, cistpl_manfid },
- { 0x21, 2, /* cistpl_funcid */ },
- { 0x22, 0, cistpl_funce },
-};
-
-static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
-{
- int ret;
- struct sdio_func_tuple *this, **prev;
- unsigned i, ptr = 0;
-
- /*
- * Note that this works for the common CIS (function number 0) as
- * well as a function's CIS * since SDIO_CCCR_CIS and SDIO_FBR_CIS
- * have the same offset.
- */
- for (i = 0; i < 3; i++) {
- unsigned char x, fn;
-
- if (func)
- fn = func->num;
- else
- fn = 0;
-
- ret = mmc_io_rw_direct(card, 0, 0,
- SDIO_FBR_BASE(fn) + SDIO_FBR_CIS + i, 0, &x);
- if (ret)
- return ret;
- ptr |= x << (i * 8);
- }
-
- if (func)
- prev = &func->tuples;
- else
- prev = &card->tuples;
-
- BUG_ON(*prev);
-
- do {
- unsigned char tpl_code, tpl_link;
-
- ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code);
- if (ret)
- break;
-
- /* 0xff means we're done */
- if (tpl_code == 0xff)
- break;
-
- /* null entries have no link field or data */
- if (tpl_code == 0x00)
- continue;
-
- ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link);
- if (ret)
- break;
-
- /* a size of 0xff also means we're done */
- if (tpl_link == 0xff)
- break;
-
- this = kmalloc(sizeof(*this) + tpl_link, GFP_KERNEL);
- if (!this)
- return -ENOMEM;
-
- for (i = 0; i < tpl_link; i++) {
- ret = mmc_io_rw_direct(card, 0, 0,
- ptr + i, 0, &this->data[i]);
- if (ret)
- break;
- }
- if (ret) {
- kfree(this);
- break;
- }
-
- /* Try to parse the CIS tuple */
- ret = cis_tpl_parse(card, func, "CIS",
- cis_tpl_list, ARRAY_SIZE(cis_tpl_list),
- tpl_code, this->data, tpl_link);
- if (ret == -EILSEQ || ret == -ENOENT) {
- /*
- * The tuple is unknown or known but not parsed.
- * Queue the tuple for the function driver.
- */
- this->next = NULL;
- this->code = tpl_code;
- this->size = tpl_link;
- *prev = this;
- prev = &this->next;
-
- if (ret == -ENOENT) {
- /* warn about unknown tuples */
- pr_warning("%s: queuing unknown"
- " CIS tuple 0x%02x (%u bytes)\n",
- mmc_hostname(card->host),
- tpl_code, tpl_link);
- }
-
- /* keep on analyzing tuples */
- ret = 0;
- } else {
- /*
- * We don't need the tuple anymore if it was
- * successfully parsed by the SDIO core or if it is
- * not going to be queued for a driver.
- */
- kfree(this);
- }
-
- ptr += tpl_link;
- } while (!ret);
-
- /*
- * Link in all unknown tuples found in the common CIS so that
- * drivers don't have to go digging in two places.
- */
- if (func)
- *prev = card->tuples;
-
- return ret;
-}
-
-int sdio_read_common_cis(struct mmc_card *card)
-{
- return sdio_read_cis(card, NULL);
-}
-
-void sdio_free_common_cis(struct mmc_card *card)
-{
- struct sdio_func_tuple *tuple, *victim;
-
- tuple = card->tuples;
-
- while (tuple) {
- victim = tuple;
- tuple = tuple->next;
- kfree(victim);
- }
-
- card->tuples = NULL;
-}
-
-int sdio_read_func_cis(struct sdio_func *func)
-{
- int ret;
-
- ret = sdio_read_cis(func->card, func);
- if (ret)
- return ret;
-
- /*
- * Since we've linked to tuples in the card structure,
- * we must make sure we have a reference to it.
- */
- get_device(&func->card->dev);
-
- /*
- * Vendor/device id is optional for function CIS, so
- * copy it from the card structure as needed.
- */
- if (func->vendor == 0) {
- func->vendor = func->card->cis.vendor;
- func->device = func->card->cis.device;
- }
-
- return 0;
-}
-
-void sdio_free_func_cis(struct sdio_func *func)
-{
- struct sdio_func_tuple *tuple, *victim;
-
- tuple = func->tuples;
-
- while (tuple && tuple != func->card->tuples) {
- victim = tuple;
- tuple = tuple->next;
- kfree(victim);
- }
-
- func->tuples = NULL;
-
- /*
- * We have now removed the link to the tuples in the
- * card structure, so remove the reference.
- */
- put_device(&func->card->dev);
-}
-
diff --git a/ANDROID_3.4.5/drivers/mmc/core/sdio_cis.h b/ANDROID_3.4.5/drivers/mmc/core/sdio_cis.h
deleted file mode 100644
index 4d903c2e..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/sdio_cis.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * linux/drivers/mmc/core/sdio_cis.h
- *
- * Author: Nicolas Pitre
- * Created: June 11, 2007
- * Copyright: MontaVista Software Inc.
- *
- * 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 _MMC_SDIO_CIS_H
-#define _MMC_SDIO_CIS_H
-
-int sdio_read_common_cis(struct mmc_card *card);
-void sdio_free_common_cis(struct mmc_card *card);
-
-int sdio_read_func_cis(struct sdio_func *func);
-void sdio_free_func_cis(struct sdio_func *func);
-
-#endif
diff --git a/ANDROID_3.4.5/drivers/mmc/core/sdio_io.c b/ANDROID_3.4.5/drivers/mmc/core/sdio_io.c
deleted file mode 100755
index 01fa6e86..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/sdio_io.c
+++ /dev/null
@@ -1,759 +0,0 @@
-/*
- * linux/drivers/mmc/core/sdio_io.c
- *
- * Copyright 2007-2008 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/export.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/sdio_func.h>
-
-#include "sdio_ops.h"
-
-/**
- * sdio_claim_host - exclusively claim a bus for a certain SDIO function
- * @func: SDIO function that will be accessed
- *
- * Claim a bus for a set of operations. The SDIO function given
- * is used to figure out which bus is relevant.
- */
-void sdio_claim_host(struct sdio_func *func)
-{
- BUG_ON(!func);
- BUG_ON(!func->card);
-
- mmc_claim_host(func->card->host);
-}
-EXPORT_SYMBOL_GPL(sdio_claim_host);
-
-/**
- * sdio_release_host - release a bus for a certain SDIO function
- * @func: SDIO function that was accessed
- *
- * Release a bus, allowing others to claim the bus for their
- * operations.
- */
-void sdio_release_host(struct sdio_func *func)
-{
- BUG_ON(!func);
- BUG_ON(!func->card);
-
- mmc_release_host(func->card->host);
-}
-EXPORT_SYMBOL_GPL(sdio_release_host);
-
-/**
- * sdio_enable_func - enables a SDIO function for usage
- * @func: SDIO function to enable
- *
- * Powers up and activates a SDIO function so that register
- * access is possible.
- */
-int sdio_enable_func(struct sdio_func *func)
-{
- int ret;
- unsigned char reg;
- unsigned long timeout;
-
- BUG_ON(!func);
- BUG_ON(!func->card);
-
- pr_debug("SDIO: Enabling device %s...\n", sdio_func_id(func));
-
- ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IOEx, 0, &reg);
- if (ret)
- goto err;
-
- reg |= 1 << func->num;
-
- ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IOEx, reg, NULL);
- if (ret)
- goto err;
-
- timeout = jiffies + msecs_to_jiffies(func->enable_timeout);
-
- while (1) {
- ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IORx, 0, &reg);
- if (ret)
- goto err;
- if (reg & (1 << func->num))
- break;
- ret = -ETIME;
- if (time_after(jiffies, timeout))
- goto err;
- }
-
- pr_debug("SDIO: Enabled device %s\n", sdio_func_id(func));
-
- return 0;
-
-err:
- pr_debug("SDIO: Failed to enable device %s\n", sdio_func_id(func));
- return ret;
-}
-EXPORT_SYMBOL_GPL(sdio_enable_func);
-
-/**
- * sdio_disable_func - disable a SDIO function
- * @func: SDIO function to disable
- *
- * Powers down and deactivates a SDIO function. Register access
- * to this function will fail until the function is reenabled.
- */
-int sdio_disable_func(struct sdio_func *func)
-{
- int ret;
- unsigned char reg;
-
- BUG_ON(!func);
- BUG_ON(!func->card);
-
- pr_debug("SDIO: Disabling device %s...\n", sdio_func_id(func));
-
- ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IOEx, 0, &reg);
- if (ret)
- goto err;
-
- reg &= ~(1 << func->num);
-
- ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IOEx, reg, NULL);
- if (ret)
- goto err;
-
- pr_debug("SDIO: Disabled device %s\n", sdio_func_id(func));
-
- return 0;
-
-err:
- pr_debug("SDIO: Failed to disable device %s\n", sdio_func_id(func));
- return -EIO;
-}
-EXPORT_SYMBOL_GPL(sdio_disable_func);
-
-/**
- * sdio_set_block_size - set the block size of an SDIO function
- * @func: SDIO function to change
- * @blksz: new block size or 0 to use the default.
- *
- * The default block size is the largest supported by both the function
- * and the host, with a maximum of 512 to ensure that arbitrarily sized
- * data transfer use the optimal (least) number of commands.
- *
- * A driver may call this to override the default block size set by the
- * core. This can be used to set a block size greater than the maximum
- * that reported by the card; it is the driver's responsibility to ensure
- * it uses a value that the card supports.
- *
- * Returns 0 on success, -EINVAL if the host does not support the
- * requested block size, or -EIO (etc.) if one of the resultant FBR block
- * size register writes failed.
- *
- */
-int sdio_set_block_size(struct sdio_func *func, unsigned blksz)
-{
- int ret;
-
- if (blksz > func->card->host->max_blk_size)
- return -EINVAL;
-
- if (blksz == 0) {
- blksz = min(func->max_blksize, func->card->host->max_blk_size);
- blksz = min(blksz, 512u);
- }
-
- ret = mmc_io_rw_direct(func->card, 1, 0,
- SDIO_FBR_BASE(func->num) + SDIO_FBR_BLKSIZE,
- blksz & 0xff, NULL);
- if (ret)
- return ret;
- ret = mmc_io_rw_direct(func->card, 1, 0,
- SDIO_FBR_BASE(func->num) + SDIO_FBR_BLKSIZE + 1,
- (blksz >> 8) & 0xff, NULL);
- if (ret)
- return ret;
- func->cur_blksize = blksz;
- return 0;
-}
-EXPORT_SYMBOL_GPL(sdio_set_block_size);
-
-/*
- * Calculate the maximum byte mode transfer size
- */
-static inline unsigned int sdio_max_byte_size(struct sdio_func *func)
-{
- unsigned mval = min(func->card->host->max_seg_size,
- func->card->host->max_blk_size);
-
- if (mmc_blksz_for_byte_mode(func->card))
- mval = min(mval, func->cur_blksize);
- else
- mval = min(mval, func->max_blksize);
-
- if (mmc_card_broken_byte_mode_512(func->card))
- return min(mval, 511u);
-
- return min(mval, 512u); /* maximum size for byte mode */
-}
-
-/**
- * sdio_align_size - pads a transfer size to a more optimal value
- * @func: SDIO function
- * @sz: original transfer size
- *
- * Pads the original data size with a number of extra bytes in
- * order to avoid controller bugs and/or performance hits
- * (e.g. some controllers revert to PIO for certain sizes).
- *
- * If possible, it will also adjust the size so that it can be
- * handled in just a single request.
- *
- * Returns the improved size, which might be unmodified.
- */
-unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz)
-{
- unsigned int orig_sz;
- unsigned int blk_sz, byte_sz;
- unsigned chunk_sz;
-
- orig_sz = sz;
-
- /*
- * Do a first check with the controller, in case it
- * wants to increase the size up to a point where it
- * might need more than one block.
- */
- sz = mmc_align_data_size(func->card, sz);
-
- /*
- * If we can still do this with just a byte transfer, then
- * we're done.
- */
- if (sz <= sdio_max_byte_size(func))
- return sz;
-
- if (func->card->cccr.multi_block) {
- /*
- * Check if the transfer is already block aligned
- */
- if ((sz % func->cur_blksize) == 0)
- return sz;
-
- /*
- * Realign it so that it can be done with one request,
- * and recheck if the controller still likes it.
- */
- blk_sz = ((sz + func->cur_blksize - 1) /
- func->cur_blksize) * func->cur_blksize;
- blk_sz = mmc_align_data_size(func->card, blk_sz);
-
- /*
- * This value is only good if it is still just
- * one request.
- */
- if ((blk_sz % func->cur_blksize) == 0)
- return blk_sz;
-
- /*
- * We failed to do one request, but at least try to
- * pad the remainder properly.
- */
- byte_sz = mmc_align_data_size(func->card,
- sz % func->cur_blksize);
- if (byte_sz <= sdio_max_byte_size(func)) {
- blk_sz = sz / func->cur_blksize;
- return blk_sz * func->cur_blksize + byte_sz;
- }
- } else {
- /*
- * We need multiple requests, so first check that the
- * controller can handle the chunk size;
- */
- chunk_sz = mmc_align_data_size(func->card,
- sdio_max_byte_size(func));
- if (chunk_sz == sdio_max_byte_size(func)) {
- /*
- * Fix up the size of the remainder (if any)
- */
- byte_sz = orig_sz % chunk_sz;
- if (byte_sz) {
- byte_sz = mmc_align_data_size(func->card,
- byte_sz);
- }
-
- return (orig_sz / chunk_sz) * chunk_sz + byte_sz;
- }
- }
-
- /*
- * The controller is simply incapable of transferring the size
- * we want in decent manner, so just return the original size.
- */
- return orig_sz;
-}
-EXPORT_SYMBOL_GPL(sdio_align_size);
-
-/* Split an arbitrarily sized data transfer into several
- * IO_RW_EXTENDED commands. */
-static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
- unsigned addr, int incr_addr, u8 *buf, unsigned size)
-{
- unsigned remainder = size;
- unsigned max_blocks;
- int ret;
-
- /* Do the bulk of the transfer using block mode (if supported). */
- if (func->card->cccr.multi_block && (size > sdio_max_byte_size(func))) {
- /* Blocks per command is limited by host count, host transfer
- * size (we only use a single sg entry) and the maximum for
- * IO_RW_EXTENDED of 511 blocks. */
- max_blocks = min(func->card->host->max_blk_count,
- func->card->host->max_seg_size / func->cur_blksize);
- max_blocks = min(max_blocks, 511u);
-
- while (remainder >= func->cur_blksize) {
- unsigned blocks;
-
- blocks = remainder / func->cur_blksize;
- if (blocks > max_blocks)
- blocks = max_blocks;
- size = blocks * func->cur_blksize;
-
- ret = mmc_io_rw_extended(func->card, write,
- func->num, addr, incr_addr, buf,
- blocks, func->cur_blksize);
- if (ret)
- return ret;
-
- remainder -= size;
- buf += size;
- if (incr_addr)
- addr += size;
- }
- }
-
- /* Write the remainder using byte mode. */
- while (remainder > 0) {
- size = min(remainder, sdio_max_byte_size(func));
-
- /* Indicate byte mode by setting "blocks" = 0 */
- ret = mmc_io_rw_extended(func->card, write, func->num, addr,
- incr_addr, buf, 0, size);
- if (ret)
- return ret;
-
- remainder -= size;
- buf += size;
- if (incr_addr)
- addr += size;
- }
- return 0;
-}
-
-/**
- * sdio_readb - read a single byte from a SDIO function
- * @func: SDIO function to access
- * @addr: address to read
- * @err_ret: optional status value from transfer
- *
- * Reads a single byte from the address space of a given SDIO
- * function. If there is a problem reading the address, 0xff
- * is returned and @err_ret will contain the error code.
- */
-u8 sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret)
-{
- int ret;
- u8 val;
-
- BUG_ON(!func);
-
- if (err_ret)
- *err_ret = 0;
-
- ret = mmc_io_rw_direct(func->card, 0, func->num, addr, 0, &val);
- if (ret) {
- if (err_ret)
- *err_ret = ret;
- return 0xFF;
- }
-
- return val;
-}
-EXPORT_SYMBOL_GPL(sdio_readb);
-
-/**
- * sdio_readb_ext - read a single byte from a SDIO function
- * @func: SDIO function to access
- * @addr: address to read
- * @err_ret: optional status value from transfer
- * @in: value to add to argument
- *
- * Reads a single byte from the address space of a given SDIO
- * function. If there is a problem reading the address, 0xff
- * is returned and @err_ret will contain the error code.
- */
-unsigned char sdio_readb_ext(struct sdio_func *func, unsigned int addr,
- int *err_ret, unsigned in)
-{
- int ret;
- unsigned char val;
-
- BUG_ON(!func);
-
- if (err_ret)
- *err_ret = 0;
-
- ret = mmc_io_rw_direct(func->card, 0, func->num, addr, (u8)in, &val);
- if (ret) {
- if (err_ret)
- *err_ret = ret;
- return 0xFF;
- }
-
- return val;
-}
-EXPORT_SYMBOL_GPL(sdio_readb_ext);
-
-/**
- * sdio_writeb - write a single byte to a SDIO function
- * @func: SDIO function to access
- * @b: byte to write
- * @addr: address to write to
- * @err_ret: optional status value from transfer
- *
- * Writes a single byte to the address space of a given SDIO
- * function. @err_ret will contain the status of the actual
- * transfer.
- */
-void sdio_writeb(struct sdio_func *func, u8 b, unsigned int addr, int *err_ret)
-{
- int ret;
-
- BUG_ON(!func);
-
- ret = mmc_io_rw_direct(func->card, 1, func->num, addr, b, NULL);
- if (err_ret)
- *err_ret = ret;
-}
-EXPORT_SYMBOL_GPL(sdio_writeb);
-
-/**
- * sdio_writeb_readb - write and read a byte from SDIO function
- * @func: SDIO function to access
- * @write_byte: byte to write
- * @addr: address to write to
- * @err_ret: optional status value from transfer
- *
- * Performs a RAW (Read after Write) operation as defined by SDIO spec -
- * single byte is written to address space of a given SDIO function and
- * response is read back from the same address, both using single request.
- * If there is a problem with the operation, 0xff is returned and
- * @err_ret will contain the error code.
- */
-u8 sdio_writeb_readb(struct sdio_func *func, u8 write_byte,
- unsigned int addr, int *err_ret)
-{
- int ret;
- u8 val;
-
- ret = mmc_io_rw_direct(func->card, 1, func->num, addr,
- write_byte, &val);
- if (err_ret)
- *err_ret = ret;
- if (ret)
- val = 0xff;
-
- return val;
-}
-EXPORT_SYMBOL_GPL(sdio_writeb_readb);
-
-/**
- * sdio_memcpy_fromio - read a chunk of memory from a SDIO function
- * @func: SDIO function to access
- * @dst: buffer to store the data
- * @addr: address to begin reading from
- * @count: number of bytes to read
- *
- * Reads from the address space of a given SDIO function. Return
- * value indicates if the transfer succeeded or not.
- */
-int sdio_memcpy_fromio(struct sdio_func *func, void *dst,
- unsigned int addr, int count)
-{
- return sdio_io_rw_ext_helper(func, 0, addr, 1, dst, count);
-}
-EXPORT_SYMBOL_GPL(sdio_memcpy_fromio);
-
-/**
- * sdio_memcpy_toio - write a chunk of memory to a SDIO function
- * @func: SDIO function to access
- * @addr: address to start writing to
- * @src: buffer that contains the data to write
- * @count: number of bytes to write
- *
- * Writes to the address space of a given SDIO function. Return
- * value indicates if the transfer succeeded or not.
- */
-int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr,
- void *src, int count)
-{
- return sdio_io_rw_ext_helper(func, 1, addr, 1, src, count);
-}
-EXPORT_SYMBOL_GPL(sdio_memcpy_toio);
-
-/**
- * sdio_readsb - read from a FIFO on a SDIO function
- * @func: SDIO function to access
- * @dst: buffer to store the data
- * @addr: address of (single byte) FIFO
- * @count: number of bytes to read
- *
- * Reads from the specified FIFO of a given SDIO function. Return
- * value indicates if the transfer succeeded or not.
- */
-int sdio_readsb(struct sdio_func *func, void *dst, unsigned int addr,
- int count)
-{
- return sdio_io_rw_ext_helper(func, 0, addr, 0, dst, count);
-}
-EXPORT_SYMBOL_GPL(sdio_readsb);
-
-/**
- * sdio_writesb - write to a FIFO of a SDIO function
- * @func: SDIO function to access
- * @addr: address of (single byte) FIFO
- * @src: buffer that contains the data to write
- * @count: number of bytes to write
- *
- * Writes to the specified FIFO of a given SDIO function. Return
- * value indicates if the transfer succeeded or not.
- */
-int sdio_writesb(struct sdio_func *func, unsigned int addr, void *src,
- int count)
-{
- return sdio_io_rw_ext_helper(func, 1, addr, 0, src, count);
-}
-EXPORT_SYMBOL_GPL(sdio_writesb);
-
-/**
- * sdio_readw - read a 16 bit integer from a SDIO function
- * @func: SDIO function to access
- * @addr: address to read
- * @err_ret: optional status value from transfer
- *
- * Reads a 16 bit integer from the address space of a given SDIO
- * function. If there is a problem reading the address, 0xffff
- * is returned and @err_ret will contain the error code.
- */
-u16 sdio_readw(struct sdio_func *func, unsigned int addr, int *err_ret)
-{
- int ret;
-
- if (err_ret)
- *err_ret = 0;
-
- ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 2);
- if (ret) {
- if (err_ret)
- *err_ret = ret;
- return 0xFFFF;
- }
-
- return le16_to_cpup((__le16 *)func->tmpbuf);
-}
-EXPORT_SYMBOL_GPL(sdio_readw);
-
-/**
- * sdio_writew - write a 16 bit integer to a SDIO function
- * @func: SDIO function to access
- * @b: integer to write
- * @addr: address to write to
- * @err_ret: optional status value from transfer
- *
- * Writes a 16 bit integer to the address space of a given SDIO
- * function. @err_ret will contain the status of the actual
- * transfer.
- */
-void sdio_writew(struct sdio_func *func, u16 b, unsigned int addr, int *err_ret)
-{
- int ret;
-
- *(__le16 *)func->tmpbuf = cpu_to_le16(b);
-
- ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 2);
- if (err_ret)
- *err_ret = ret;
-}
-EXPORT_SYMBOL_GPL(sdio_writew);
-
-/**
- * sdio_readl - read a 32 bit integer from a SDIO function
- * @func: SDIO function to access
- * @addr: address to read
- * @err_ret: optional status value from transfer
- *
- * Reads a 32 bit integer from the address space of a given SDIO
- * function. If there is a problem reading the address,
- * 0xffffffff is returned and @err_ret will contain the error
- * code.
- */
-u32 sdio_readl(struct sdio_func *func, unsigned int addr, int *err_ret)
-{
- int ret;
-
- if (err_ret)
- *err_ret = 0;
-
- ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 4);
- if (ret) {
- if (err_ret)
- *err_ret = ret;
- return 0xFFFFFFFF;
- }
-
- return le32_to_cpup((__le32 *)func->tmpbuf);
-}
-EXPORT_SYMBOL_GPL(sdio_readl);
-
-/**
- * sdio_writel - write a 32 bit integer to a SDIO function
- * @func: SDIO function to access
- * @b: integer to write
- * @addr: address to write to
- * @err_ret: optional status value from transfer
- *
- * Writes a 32 bit integer to the address space of a given SDIO
- * function. @err_ret will contain the status of the actual
- * transfer.
- */
-void sdio_writel(struct sdio_func *func, u32 b, unsigned int addr, int *err_ret)
-{
- int ret;
-
- *(__le32 *)func->tmpbuf = cpu_to_le32(b);
-
- ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 4);
- if (err_ret)
- *err_ret = ret;
-}
-EXPORT_SYMBOL_GPL(sdio_writel);
-
-/**
- * sdio_f0_readb - read a single byte from SDIO function 0
- * @func: an SDIO function of the card
- * @addr: address to read
- * @err_ret: optional status value from transfer
- *
- * Reads a single byte from the address space of SDIO function 0.
- * If there is a problem reading the address, 0xff is returned
- * and @err_ret will contain the error code.
- */
-unsigned char sdio_f0_readb(struct sdio_func *func, unsigned int addr,
- int *err_ret)
-{
- int ret;
- unsigned char val;
-
- BUG_ON(!func);
-
- if (err_ret)
- *err_ret = 0;
-
- ret = mmc_io_rw_direct(func->card, 0, 0, addr, 0, &val);
- if (ret) {
- if (err_ret)
- *err_ret = ret;
- return 0xFF;
- }
-
- return val;
-}
-EXPORT_SYMBOL_GPL(sdio_f0_readb);
-
-/**
- * sdio_f0_writeb - write a single byte to SDIO function 0
- * @func: an SDIO function of the card
- * @b: byte to write
- * @addr: address to write to
- * @err_ret: optional status value from transfer
- *
- * Writes a single byte to the address space of SDIO function 0.
- * @err_ret will contain the status of the actual transfer.
- *
- * Only writes to the vendor specific CCCR registers (0xF0 -
- * 0xFF) are permiited; @err_ret will be set to -EINVAL for *
- * writes outside this range.
- */
-void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr,
- int *err_ret)
-{
- int ret;
-
- BUG_ON(!func);
-
- if ((addr < 0xF0 || addr > 0xFF) && (!mmc_card_lenient_fn0(func->card))) {
- if (err_ret)
- *err_ret = -EINVAL;
- return;
- }
-
- ret = mmc_io_rw_direct(func->card, 1, 0, addr, b, NULL);
- if (err_ret)
- *err_ret = ret;
-}
-EXPORT_SYMBOL_GPL(sdio_f0_writeb);
-
-/**
- * sdio_get_host_pm_caps - get host power management capabilities
- * @func: SDIO function attached to host
- *
- * Returns a capability bitmask corresponding to power management
- * features supported by the host controller that the card function
- * might rely upon during a system suspend. The host doesn't need
- * to be claimed, nor the function active, for this information to be
- * obtained.
- */
-mmc_pm_flag_t sdio_get_host_pm_caps(struct sdio_func *func)
-{
- BUG_ON(!func);
- BUG_ON(!func->card);
-
- return func->card->host->pm_caps;
-}
-EXPORT_SYMBOL_GPL(sdio_get_host_pm_caps);
-
-/**
- * sdio_set_host_pm_flags - set wanted host power management capabilities
- * @func: SDIO function attached to host
- *
- * Set a capability bitmask corresponding to wanted host controller
- * power management features for the upcoming suspend state.
- * This must be called, if needed, each time the suspend method of
- * the function driver is called, and must contain only bits that
- * were returned by sdio_get_host_pm_caps().
- * The host doesn't need to be claimed, nor the function active,
- * for this information to be set.
- */
-int sdio_set_host_pm_flags(struct sdio_func *func, mmc_pm_flag_t flags)
-{
- struct mmc_host *host;
-
- BUG_ON(!func);
- BUG_ON(!func->card);
-
- host = func->card->host;
-
- if (flags & ~host->pm_caps)
- return -EINVAL;
-
- /* function suspend methods are serialized, hence no lock needed */
- host->pm_flags |= flags;
- return 0;
-}
-EXPORT_SYMBOL_GPL(sdio_set_host_pm_flags);
diff --git a/ANDROID_3.4.5/drivers/mmc/core/sdio_irq.c b/ANDROID_3.4.5/drivers/mmc/core/sdio_irq.c
deleted file mode 100644
index 3d8ceb40..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/sdio_irq.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * linux/drivers/mmc/core/sdio_irq.c
- *
- * Author: Nicolas Pitre
- * Created: June 18, 2007
- * Copyright: MontaVista Software Inc.
- *
- * Copyright 2008 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/kthread.h>
-#include <linux/export.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-
-#include <linux/mmc/core.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/sdio_func.h>
-
-#include "sdio_ops.h"
-
-static int process_sdio_pending_irqs(struct mmc_host *host)
-{
- struct mmc_card *card = host->card;
- int i, ret, count;
- unsigned char pending;
- struct sdio_func *func;
-
- /*
- * Optimization, if there is only 1 function interrupt registered
- * and we know an IRQ was signaled then call irq handler directly.
- * Otherwise do the full probe.
- */
- func = card->sdio_single_irq;
- if (func && host->sdio_irq_pending) {
- func->irq_handler(func);
- return 1;
- }
-
- ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending);
- if (ret) {
- pr_debug("%s: error %d reading SDIO_CCCR_INTx\n",
- mmc_card_id(card), ret);
- return ret;
- }
-
- count = 0;
- for (i = 1; i <= 7; i++) {
- if (pending & (1 << i)) {
- func = card->sdio_func[i - 1];
- if (!func) {
- pr_warning("%s: pending IRQ for "
- "non-existent function\n",
- mmc_card_id(card));
- ret = -EINVAL;
- } else if (func->irq_handler) {
- func->irq_handler(func);
- count++;
- } else {
- pr_warning("%s: pending IRQ with no handler\n",
- sdio_func_id(func));
- ret = -EINVAL;
- }
- }
- }
-
- if (count)
- return count;
-
- return ret;
-}
-
-static int sdio_irq_thread(void *_host)
-{
- struct mmc_host *host = _host;
- struct sched_param param = { .sched_priority = 1 };
- unsigned long period, idle_period;
- int ret;
-
- sched_setscheduler(current, SCHED_FIFO, &param);
-
- /*
- * We want to allow for SDIO cards to work even on non SDIO
- * aware hosts. One thing that non SDIO host cannot do is
- * asynchronous notification of pending SDIO card interrupts
- * hence we poll for them in that case.
- */
- idle_period = msecs_to_jiffies(10);
- period = (host->caps & MMC_CAP_SDIO_IRQ) ?
- MAX_SCHEDULE_TIMEOUT : idle_period;
-
- pr_debug("%s: IRQ thread started (poll period = %lu jiffies)\n",
- mmc_hostname(host), period);
-
- do {
- /*
- * We claim the host here on drivers behalf for a couple
- * reasons:
- *
- * 1) it is already needed to retrieve the CCCR_INTx;
- * 2) we want the driver(s) to clear the IRQ condition ASAP;
- * 3) we need to control the abort condition locally.
- *
- * Just like traditional hard IRQ handlers, we expect SDIO
- * IRQ handlers to be quick and to the point, so that the
- * holding of the host lock does not cover too much work
- * that doesn't require that lock to be held.
- */
- ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort);
- if (ret)
- break;
- ret = process_sdio_pending_irqs(host);
- host->sdio_irq_pending = false;
- mmc_release_host(host);
-
- /*
- * Give other threads a chance to run in the presence of
- * errors.
- */
- if (ret < 0) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (!kthread_should_stop())
- schedule_timeout(HZ);
- set_current_state(TASK_RUNNING);
- }
-
- /*
- * Adaptive polling frequency based on the assumption
- * that an interrupt will be closely followed by more.
- * This has a substantial benefit for network devices.
- */
- if (!(host->caps & MMC_CAP_SDIO_IRQ)) {
- if (ret > 0)
- period /= 2;
- else {
- period++;
- if (period > idle_period)
- period = idle_period;
- }
- }
-
- set_current_state(TASK_INTERRUPTIBLE);
- if (host->caps & MMC_CAP_SDIO_IRQ) {
- mmc_host_clk_hold(host);
- host->ops->enable_sdio_irq(host, 1);
- mmc_host_clk_release(host);
- }
- if (!kthread_should_stop())
- schedule_timeout(period);
- set_current_state(TASK_RUNNING);
- } while (!kthread_should_stop());
-
- if (host->caps & MMC_CAP_SDIO_IRQ) {
- mmc_host_clk_hold(host);
- host->ops->enable_sdio_irq(host, 0);
- mmc_host_clk_release(host);
- }
-
- pr_debug("%s: IRQ thread exiting with code %d\n",
- mmc_hostname(host), ret);
-
- return ret;
-}
-
-static int sdio_card_irq_get(struct mmc_card *card)
-{
- struct mmc_host *host = card->host;
-
- WARN_ON(!host->claimed);
-
- if (!host->sdio_irqs++) {
- atomic_set(&host->sdio_irq_thread_abort, 0);
- host->sdio_irq_thread =
- kthread_run(sdio_irq_thread, host, "ksdioirqd/%s",
- mmc_hostname(host));
- if (IS_ERR(host->sdio_irq_thread)) {
- int err = PTR_ERR(host->sdio_irq_thread);
- host->sdio_irqs--;
- return err;
- }
- }
-
- return 0;
-}
-
-static int sdio_card_irq_put(struct mmc_card *card)
-{
- struct mmc_host *host = card->host;
-
- WARN_ON(!host->claimed);
- BUG_ON(host->sdio_irqs < 1);
-
- if (!--host->sdio_irqs) {
- atomic_set(&host->sdio_irq_thread_abort, 1);
- kthread_stop(host->sdio_irq_thread);
- }
-
- return 0;
-}
-
-/* If there is only 1 function registered set sdio_single_irq */
-static void sdio_single_irq_set(struct mmc_card *card)
-{
- struct sdio_func *func;
- int i;
-
- card->sdio_single_irq = NULL;
- if ((card->host->caps & MMC_CAP_SDIO_IRQ) &&
- card->host->sdio_irqs == 1)
- for (i = 0; i < card->sdio_funcs; i++) {
- func = card->sdio_func[i];
- if (func && func->irq_handler) {
- card->sdio_single_irq = func;
- break;
- }
- }
-}
-
-/**
- * sdio_claim_irq - claim the IRQ for a SDIO function
- * @func: SDIO function
- * @handler: IRQ handler callback
- *
- * Claim and activate the IRQ for the given SDIO function. The provided
- * handler will be called when that IRQ is asserted. The host is always
- * claimed already when the handler is called so the handler must not
- * call sdio_claim_host() nor sdio_release_host().
- */
-int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler)
-{
- int ret;
- unsigned char reg;
-
- BUG_ON(!func);
- BUG_ON(!func->card);
-
- pr_debug("SDIO: Enabling IRQ for %s...\n", sdio_func_id(func));
-
- if (func->irq_handler) {
- pr_debug("SDIO: IRQ for %s already in use.\n", sdio_func_id(func));
- return -EBUSY;
- }
-
- ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
- if (ret)
- return ret;
-
- reg |= 1 << func->num;
-
- reg |= 1; /* Master interrupt enable */
-
- ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL);
- if (ret)
- return ret;
-
- func->irq_handler = handler;
- ret = sdio_card_irq_get(func->card);
- if (ret)
- func->irq_handler = NULL;
- sdio_single_irq_set(func->card);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(sdio_claim_irq);
-
-/**
- * sdio_release_irq - release the IRQ for a SDIO function
- * @func: SDIO function
- *
- * Disable and release the IRQ for the given SDIO function.
- */
-int sdio_release_irq(struct sdio_func *func)
-{
- int ret;
- unsigned char reg;
-
- BUG_ON(!func);
- BUG_ON(!func->card);
-
- pr_debug("SDIO: Disabling IRQ for %s...\n", sdio_func_id(func));
-
- if (func->irq_handler) {
- func->irq_handler = NULL;
- sdio_card_irq_put(func->card);
- sdio_single_irq_set(func->card);
- }
-
- ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
- if (ret)
- return ret;
-
- reg &= ~(1 << func->num);
-
- /* Disable master interrupt with the last function interrupt */
- if (!(reg & 0xFE))
- reg = 0;
-
- ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL);
- if (ret)
- return ret;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(sdio_release_irq);
-
diff --git a/ANDROID_3.4.5/drivers/mmc/core/sdio_ops.c b/ANDROID_3.4.5/drivers/mmc/core/sdio_ops.c
deleted file mode 100644
index d29e2063..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/sdio_ops.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * linux/drivers/mmc/sdio_ops.c
- *
- * Copyright 2006-2007 Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/scatterlist.h>
-
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/sdio.h>
-
-#include "core.h"
-#include "sdio_ops.h"
-
-int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
-{
- struct mmc_command cmd = {0};
- int i, err = 0;
-
- BUG_ON(!host);
-
- cmd.opcode = SD_IO_SEND_OP_COND;
- cmd.arg = ocr;
- cmd.flags = MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR;
-
- for (i = 100; i; i--) {
- err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
- if (err)
- break;
-
- /* if we're just probing, do a single pass */
- if (ocr == 0)
- break;
-
- /* otherwise wait until reset completes */
- if (mmc_host_is_spi(host)) {
- /*
- * Both R1_SPI_IDLE and MMC_CARD_BUSY indicate
- * an initialized card under SPI, but some cards
- * (Marvell's) only behave when looking at this
- * one.
- */
- if (cmd.resp[1] & MMC_CARD_BUSY)
- break;
- } else {
- if (cmd.resp[0] & MMC_CARD_BUSY)
- break;
- }
-
- err = -ETIMEDOUT;
-
- mmc_delay(10);
- }
-
- if (rocr)
- *rocr = cmd.resp[mmc_host_is_spi(host) ? 1 : 0];
-
- return err;
-}
-
-static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
- unsigned addr, u8 in, u8 *out)
-{
- struct mmc_command cmd = {0};
- int err;
-
- BUG_ON(!host);
- BUG_ON(fn > 7);
-
- /* sanity check */
- if (addr & ~0x1FFFF)
- return -EINVAL;
-
- cmd.opcode = SD_IO_RW_DIRECT;
- cmd.arg = write ? 0x80000000 : 0x00000000;
- cmd.arg |= fn << 28;
- cmd.arg |= (write && out) ? 0x08000000 : 0x00000000;
- cmd.arg |= addr << 9;
- cmd.arg |= in;
- cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
-
- err = mmc_wait_for_cmd(host, &cmd, 0);
- if (err)
- return err;
-
- if (mmc_host_is_spi(host)) {
- /* host driver already reported errors */
- } else {
- if (cmd.resp[0] & R5_ERROR)
- return -EIO;
- if (cmd.resp[0] & R5_FUNCTION_NUMBER)
- return -EINVAL;
- if (cmd.resp[0] & R5_OUT_OF_RANGE)
- return -ERANGE;
- }
-
- if (out) {
- if (mmc_host_is_spi(host))
- *out = (cmd.resp[0] >> 8) & 0xFF;
- else
- *out = cmd.resp[0] & 0xFF;
- }
-
- return 0;
-}
-
-int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
- unsigned addr, u8 in, u8 *out)
-{
- BUG_ON(!card);
- return mmc_io_rw_direct_host(card->host, write, fn, addr, in, out);
-}
-
-int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
- unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
-{
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_data data = {0};
- struct scatterlist sg;
-
- BUG_ON(!card);
- BUG_ON(fn > 7);
- WARN_ON(blksz == 0);
-
- /* sanity check */
- if (addr & ~0x1FFFF)
- return -EINVAL;
-
- mrq.cmd = &cmd;
- mrq.data = &data;
-
- cmd.opcode = SD_IO_RW_EXTENDED;
- cmd.arg = write ? 0x80000000 : 0x00000000;
- cmd.arg |= fn << 28;
- cmd.arg |= incr_addr ? 0x04000000 : 0x00000000;
- cmd.arg |= addr << 9;
- if (blocks == 0)
- cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */
- else
- cmd.arg |= 0x08000000 | blocks; /* block mode */
- cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
-
- data.blksz = blksz;
- /* Code in host drivers/fwk assumes that "blocks" always is >=1 */
- data.blocks = blocks ? blocks : 1;
- data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-
- sg_init_one(&sg, buf, data.blksz * data.blocks);
-
- mmc_set_data_timeout(&data, card);
-
- mmc_wait_for_req(card->host, &mrq);
-
- if (cmd.error)
- return cmd.error;
- if (data.error)
- return data.error;
-
- if (mmc_host_is_spi(card->host)) {
- /* host driver already reported errors */
- } else {
- if (cmd.resp[0] & R5_ERROR)
- return -EIO;
- if (cmd.resp[0] & R5_FUNCTION_NUMBER)
- return -EINVAL;
- if (cmd.resp[0] & R5_OUT_OF_RANGE)
- return -ERANGE;
- }
-
- return 0;
-}
-
-int sdio_reset(struct mmc_host *host)
-{
- int ret;
- u8 abort;
-
- /* SDIO Simplified Specification V2.0, 4.4 Reset for SDIO */
-
- ret = mmc_io_rw_direct_host(host, 0, 0, SDIO_CCCR_ABORT, 0, &abort);
- if (ret)
- abort = 0x08;
- else
- abort |= 0x08;
-
- ret = mmc_io_rw_direct_host(host, 1, 0, SDIO_CCCR_ABORT, abort, NULL);
- return ret;
-}
-
diff --git a/ANDROID_3.4.5/drivers/mmc/core/sdio_ops.h b/ANDROID_3.4.5/drivers/mmc/core/sdio_ops.h
deleted file mode 100644
index 12a4d3ab..00000000
--- a/ANDROID_3.4.5/drivers/mmc/core/sdio_ops.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * linux/drivers/mmc/sdio_ops.c
- *
- * Copyright 2006-2007 Pierre Ossman
- *
- * 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 _MMC_SDIO_OPS_H
-#define _MMC_SDIO_OPS_H
-
-int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
-int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
- unsigned addr, u8 in, u8* out);
-int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
- unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz);
-int sdio_reset(struct mmc_host *host);
-
-#endif
-
diff --git a/ANDROID_3.4.5/drivers/mmc/host/Kconfig b/ANDROID_3.4.5/drivers/mmc/host/Kconfig
deleted file mode 100644
index e7b73ea5..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/Kconfig
+++ /dev/null
@@ -1,646 +0,0 @@
-#
-# MMC/SD host controller drivers
-#
-
-comment "MMC/SD/SDIO Host Controller Drivers"
-
-config MMC_ARMMMCI
- tristate "ARM AMBA Multimedia Card Interface support"
- depends on ARM_AMBA
- help
- This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card
- Interface (PL180 and PL181) support. If you have an ARM(R)
- platform with a Multimedia Card slot, say Y or M here.
-
- If unsure, say N.
-
-config MMC_PXA
- tristate "Intel PXA25x/26x/27x Multimedia Card Interface support"
- depends on ARCH_PXA
- help
- This selects the Intel(R) PXA(R) Multimedia card Interface.
- If you have a PXA(R) platform with a Multimedia Card slot,
- say Y or M here.
-
- If unsure, say N.
-
-config MMC_SDHCI
- tristate "Secure Digital Host Controller Interface support"
- depends on HAS_DMA
- help
- This selects the generic Secure Digital Host Controller Interface.
- It is used by manufacturers such as Texas Instruments(R), Ricoh(R)
- and Toshiba(R). Most controllers found in laptops are of this type.
-
- If you have a controller with this interface, say Y or M here. You
- also need to enable an appropriate bus interface.
-
- If unsure, say N.
-
-config MMC_SDHCI_IO_ACCESSORS
- bool
- depends on MMC_SDHCI
- help
- This is silent Kconfig symbol that is selected by the drivers that
- need to overwrite SDHCI IO memory accessors.
-
-config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
- bool
- select MMC_SDHCI_IO_ACCESSORS
- help
- This option is selected by drivers running on big endian hosts
- and performing I/O to a SDHCI controller through a bus that
- implements a hardware byte swapper using a 32-bit datum.
- This endian mapping mode is called "data invariance" and
- has the effect of scrambling the addresses and formats of data
- accessed in sizes other than the datum size.
-
- This is the case for the Freescale eSDHC and Nintendo Wii SDHCI.
-
-config MMC_SDHCI_PCI
- tristate "SDHCI support on PCI bus"
- depends on MMC_SDHCI && PCI
- help
- This selects the PCI Secure Digital Host Controller Interface.
- Most controllers found today are PCI devices.
-
- If you have a controller with this interface, say Y or M here.
-
- If unsure, say N.
-
-config MMC_RICOH_MMC
- bool "Ricoh MMC Controller Disabler (EXPERIMENTAL)"
- depends on MMC_SDHCI_PCI
- help
- This adds a pci quirk to disable Ricoh MMC Controller. This
- proprietary controller is unnecessary because the SDHCI driver
- supports MMC cards on the SD controller, but if it is not
- disabled, it will steal the MMC cards away - rendering them
- useless. It is safe to select this even if you don't
- have a Ricoh based card reader.
-
- If unsure, say Y.
-
-config MMC_SDHCI_PLTFM
- tristate "SDHCI platform and OF driver helper"
- depends on MMC_SDHCI
- help
- This selects the common helper functions support for Secure Digital
- Host Controller Interface based platform and OF drivers.
-
- If you have a controller with this interface, say Y or M here.
-
- If unsure, say N.
-
-config MMC_SDHCI_OF_ESDHC
- tristate "SDHCI OF support for the Freescale eSDHC controller"
- depends on MMC_SDHCI_PLTFM
- depends on PPC_OF
- select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
- help
- This selects the Freescale eSDHC controller support.
-
- If you have a controller with this interface, say Y or M here.
-
- If unsure, say N.
-
-config MMC_SDHCI_OF_HLWD
- tristate "SDHCI OF support for the Nintendo Wii SDHCI controllers"
- depends on MMC_SDHCI_PLTFM
- depends on PPC_OF
- select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
- help
- This selects the Secure Digital Host Controller Interface (SDHCI)
- found in the "Hollywood" chipset of the Nintendo Wii video game
- console.
-
- If you have a controller with this interface, say Y or M here.
-
- If unsure, say N.
-
-config MMC_SDHCI_CNS3XXX
- tristate "SDHCI support on the Cavium Networks CNS3xxx SoC"
- depends on ARCH_CNS3XXX
- depends on MMC_SDHCI_PLTFM
- help
- This selects the SDHCI support for CNS3xxx System-on-Chip devices.
-
- If you have a controller with this interface, say Y or M here.
-
- If unsure, say N.
-
-config MMC_SDHCI_ESDHC_IMX
- tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller"
- depends on ARCH_MXC
- depends on MMC_SDHCI_PLTFM
- select MMC_SDHCI_IO_ACCESSORS
- help
- This selects the Freescale eSDHC/uSDHC controller support
- found on i.MX25, i.MX35 i.MX5x and i.MX6x.
-
- If you have a controller with this interface, say Y or M here.
-
- If unsure, say N.
-
-config MMC_SDHCI_DOVE
- tristate "SDHCI support on Marvell's Dove SoC"
- depends on ARCH_DOVE
- depends on MMC_SDHCI_PLTFM
- select MMC_SDHCI_IO_ACCESSORS
- help
- This selects the Secure Digital Host Controller Interface in
- Marvell's Dove SoC.
-
- If you have a controller with this interface, say Y or M here.
-
- If unsure, say N.
-
-config MMC_SDHCI_TEGRA
- tristate "SDHCI platform support for the Tegra SD/MMC Controller"
- depends on ARCH_TEGRA
- depends on MMC_SDHCI_PLTFM
- select MMC_SDHCI_IO_ACCESSORS
- help
- This selects the Tegra SD/MMC controller. If you have a Tegra
- platform with SD or MMC devices, say Y or M here.
-
- If unsure, say N.
-
-config MMC_SDHCI_S3C
- tristate "SDHCI support on Samsung S3C SoC"
- depends on MMC_SDHCI && PLAT_SAMSUNG
- help
- This selects the Secure Digital Host Controller Interface (SDHCI)
- often referrered to as the HSMMC block in some of the Samsung S3C
- range of SoC.
-
- Note, due to the problems with DMA, the DMA support is only
- available with CONFIG_EXPERIMENTAL is selected.
-
- If you have a controller with this interface, say Y or M here.
-
- If unsure, say N.
-
-config MMC_SDHCI_PXAV3
- tristate "Marvell MMP2 SD Host Controller support (PXAV3)"
- depends on CLKDEV_LOOKUP
- select MMC_SDHCI
- select MMC_SDHCI_PLTFM
- default CPU_MMP2
- help
- This selects the Marvell(R) PXAV3 SD Host Controller.
- If you have a MMP2 platform with SD Host Controller
- and a card slot, say Y or M here.
-
- If unsure, say N.
-
-config MMC_SDHCI_PXAV2
- tristate "Marvell PXA9XX SD Host Controller support (PXAV2)"
- depends on CLKDEV_LOOKUP
- select MMC_SDHCI
- select MMC_SDHCI_PLTFM
- default CPU_PXA910
- help
- This selects the Marvell(R) PXAV2 SD Host Controller.
- If you have a PXA9XX 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
- help
- This selects the Secure Digital Host Controller Interface (SDHCI)
- often referrered to as the HSMMC block in some of the ST SPEAR range
- of SoC
-
- If you have a controller with this interface, say Y or M here.
-
- If unsure, say N.
-
-config MMC_SDHCI_S3C_DMA
- bool "DMA support on S3C SDHCI"
- depends on MMC_SDHCI_S3C && EXPERIMENTAL
- help
- Enable DMA support on the Samsung S3C SDHCI glue. The DMA
- has proved to be problematic if the controller encounters
- certain errors, and thus should be treated with care.
-
- YMMV.
-
-config MMC_OMAP
- tristate "TI OMAP Multimedia Card Interface support"
- depends on ARCH_OMAP
- select TPS65010 if MACH_OMAP_H2
- help
- This selects the TI OMAP Multimedia card Interface.
- If you have an OMAP board with a Multimedia Card slot,
- say Y or M here.
-
- If unsure, say N.
-
-config MMC_OMAP_HS
- tristate "TI OMAP High Speed Multimedia Card Interface support"
- depends on SOC_OMAP2430 || ARCH_OMAP3 || ARCH_OMAP4
- help
- This selects the TI OMAP High Speed Multimedia card Interface.
- If you have an OMAP2430 or OMAP3 board or OMAP4 board with a
- Multimedia Card slot, say Y or M here.
-
- If unsure, say N.
-
-config MMC_WBSD
- tristate "Winbond W83L51xD SD/MMC Card Interface support"
- depends on ISA_DMA_API
- help
- This selects the Winbond(R) W83L51xD Secure digital and
- Multimedia card Interface.
- If you have a machine with a integrated W83L518D or W83L519D
- SD/MMC card reader, say Y or M here.
-
- If unsure, say N.
-
-config MMC_AU1X
- tristate "Alchemy AU1XX0 MMC Card Interface support"
- depends on MIPS_ALCHEMY
- help
- This selects the AMD Alchemy(R) Multimedia card interface.
- If you have a Alchemy platform with a MMC slot, say Y or M here.
-
- If unsure, say N.
-
-choice
- prompt "Atmel SD/MMC Driver"
- depends on AVR32 || ARCH_AT91
- default MMC_ATMELMCI if AVR32
- help
- Choose which driver to use for the Atmel MCI Silicon
-
-config MMC_AT91
- tristate "AT91 SD/MMC Card Interface support"
- depends on ARCH_AT91
- help
- This selects the AT91 MCI controller.
-
- If unsure, say N.
-
-config MMC_ATMELMCI
- tristate "Atmel Multimedia Card Interface support"
- depends on AVR32 || ARCH_AT91
- help
- This selects the Atmel Multimedia Card Interface driver. If
- you have an AT32 (AVR32) or AT91 platform with a Multimedia
- Card slot, say Y or M here.
-
- If unsure, say N.
-
-endchoice
-
-config MMC_ATMELMCI_DMA
- bool "Atmel MCI DMA support"
- depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE
- help
- Say Y here to have the Atmel MCI driver use a DMA engine to
- do data transfers and thus increase the throughput and
- reduce the CPU utilization.
-
- If unsure, say N.
-
-config MMC_IMX
- tristate "Motorola i.MX Multimedia Card Interface support"
- depends on ARCH_MX1
- help
- This selects the Motorola i.MX Multimedia card Interface.
- If you have a i.MX platform with a Multimedia Card slot,
- say Y or M here.
-
- If unsure, say N.
-
-config MMC_MSM
- tristate "Qualcomm SDCC Controller Support"
- depends on MMC && ARCH_MSM
- help
- This provides support for the SD/MMC cell found in the
- MSM and QSD SOCs from Qualcomm. The controller also has
- support for SDIO devices.
-
-config MMC_MXC
- tristate "Freescale i.MX21/27/31 Multimedia Card Interface support"
- depends on ARCH_MXC
- help
- This selects the Freescale i.MX21, i.MX27 and i.MX31 Multimedia card
- Interface. If you have a i.MX platform with a Multimedia Card slot,
- say Y or M here.
-
- If unsure, say N.
-
-config MMC_MXS
- tristate "Freescale MXS Multimedia Card Interface support"
- depends on ARCH_MXS && MXS_DMA
- help
- This selects the Freescale SSP MMC controller found on MXS based
- platforms like mx23/28.
-
- If unsure, say N.
-
-config MMC_TIFM_SD
- tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PCI
- select TIFM_CORE
- help
- Say Y here if you want to be able to access MMC/SD cards with
- the Texas Instruments(R) Flash Media card reader, found in many
- laptops.
- This option 'selects' (turns on, enables) 'TIFM_CORE', but you
- probably also need appropriate card reader host adapter, such as
- 'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support
- (TIFM_7XX1)'.
-
- To compile this driver as a module, choose M here: the
- module will be called tifm_sd.
-
-config MMC_MVSDIO
- tristate "Marvell MMC/SD/SDIO host driver"
- depends on PLAT_ORION
- ---help---
- This selects the Marvell SDIO host driver.
- SDIO may currently be found on the Kirkwood 88F6281 and 88F6192
- SoC controllers.
-
- To compile this driver as a module, choose M here: the
- module will be called mvsdio.
-
-config MMC_DAVINCI
- tristate "TI DAVINCI Multimedia Card Interface support"
- depends on ARCH_DAVINCI
- help
- This selects the TI DAVINCI Multimedia card Interface.
- If you have an DAVINCI board with a Multimedia Card slot,
- say Y or M here. If unsure, say N.
-
-config MMC_SPI
- tristate "MMC/SD/SDIO over SPI"
- depends on SPI_MASTER && !HIGHMEM && HAS_DMA
- select CRC7
- select CRC_ITU_T
- help
- Some systems access MMC/SD/SDIO cards using a SPI controller
- instead of using a "native" MMC/SD/SDIO controller. This has a
- disadvantage of being relatively high overhead, but a compensating
- advantage of working on many systems without dedicated MMC/SD/SDIO
- controllers.
-
- If unsure, or if your system has no SPI master driver, say N.
-
-config MMC_S3C
- tristate "Samsung S3C SD/MMC Card Interface support"
- depends on ARCH_S3C24XX
- help
- This selects a driver for the MCI interface found in
- Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.
- If you have a board based on one of those and a MMC/SD
- slot, say Y or M here.
-
- If unsure, say N.
-
-config MMC_S3C_HW_SDIO_IRQ
- bool "Hardware support for SDIO IRQ"
- depends on MMC_S3C
- help
- Enable the hardware support for SDIO interrupts instead of using
- the generic polling code.
-
-choice
- prompt "Samsung S3C SD/MMC transfer code"
- depends on MMC_S3C
-
-config MMC_S3C_PIO
- bool "Use PIO transfers only"
- help
- Use PIO to transfer data between memory and the hardware.
-
- PIO is slower than DMA as it requires CPU instructions to
- move the data. This has been the traditional default for
- the S3C MCI driver.
-
-config MMC_S3C_DMA
- bool "Use DMA transfers only (EXPERIMENTAL)"
- depends on EXPERIMENTAL
- help
- Use DMA to transfer data between memory and the hardare.
-
- Currently, the DMA support in this driver seems to not be
- working properly and needs to be debugged before this
- option is useful.
-
-config MMC_S3C_PIODMA
- bool "Support for both PIO and DMA (EXPERIMENTAL)"
- help
- Compile both the PIO and DMA transfer routines into the
- driver and let the platform select at run-time which one
- is best.
-
- See notes for the DMA option.
-
-endchoice
-
-config MMC_SDRICOH_CS
- tristate "MMC/SD driver for Ricoh Bay1Controllers (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PCI && PCMCIA
- help
- Say Y here if your Notebook reports a Ricoh Bay1Controller PCMCIA
- card whenever you insert a MMC or SD card into the card slot.
-
- To compile this driver as a module, choose M here: the
- module will be called sdricoh_cs.
-
-config MMC_TMIO_CORE
- tristate
-
-config MMC_TMIO
- tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support"
- depends on MFD_TMIO || MFD_ASIC3
- select MMC_TMIO_CORE
- help
- This provides support for the SD/MMC cell found in TC6393XB,
- T7L66XB and also HTC ASIC3
-
-config MMC_SDHI
- tristate "SH-Mobile SDHI SD/SDIO controller support"
- depends on SUPERH || ARCH_SHMOBILE
- select MMC_TMIO_CORE
- help
- This provides support for the SDHI SD/SDIO controller found in
- SuperH and ARM SH-Mobile SoCs
-
-config MMC_CB710
- tristate "ENE CB710 MMC/SD Interface support"
- depends on PCI
- select CB710_CORE
- help
- This option enables support for MMC/SD part of ENE CB710/720 Flash
- memory card reader found in some laptops (ie. some versions of
- HP Compaq nx9500).
-
- This driver can also be built as a module. If so, the module
- will be called cb710-mmc.
-
-config MMC_VIA_SDMMC
- tristate "VIA SD/MMC Card Reader Driver"
- depends on PCI
- help
- This selects the VIA SD/MMC Card Reader driver, say Y or M here.
- VIA provides one multi-functional card reader which integrated into
- some motherboards manufactured by VIA. This card reader supports
- SD/MMC/SDHC.
- If you have a controller with this interface, say Y or M here.
-
- If unsure, say N.
-
-config SDH_BFIN
- tristate "Blackfin Secure Digital Host support"
- depends on (BF54x && !BF544) || (BF51x && !BF512)
- help
- If you say yes here you will get support for the Blackfin on-chip
- Secure Digital Host interface. This includes support for MMC and
- SD cards.
-
- To compile this driver as a module, choose M here: the
- module will be called bfin_sdh.
-
- If unsure, say N.
-
-config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
- bool "Blackfin EZkit Missing SDH_CMD Pull Up Resistor Workaround"
- depends on SDH_BFIN
- help
- If you say yes here SD-Cards may work on the EZkit.
-
-config MMC_DW
- tristate "Synopsys DesignWare Memory Card Interface"
- depends on ARM
- help
- This selects support for the Synopsys DesignWare Mobile Storage IP
- block, this provides host support for SD and MMC interfaces, in both
- PIO and external DMA modes.
-
-config MMC_DW_IDMAC
- bool "Internal DMAC interface"
- depends on MMC_DW
- help
- This selects support for the internal DMAC block within the Synopsys
- Designware Mobile Storage IP block. This disables the external DMA
- interface.
-
-config MMC_DW_PLTFM
- tristate "Synopsys Designware MCI Support as platform device"
- depends on MMC_DW
- default y
- help
- This selects the common helper functions support for Host Controller
- Interface based platform driver. Please select this option if the IP
- is present as a platform device. This is the common interface for the
- Synopsys Designware IP.
-
- If you have a controller with this interface, say Y or M here.
-
- If unsure, say Y.
-
-config MMC_DW_PCI
- tristate "Synopsys Designware MCI support on PCI bus"
- depends on MMC_DW && PCI
- help
- This selects the PCI bus for the Synopsys Designware Mobile Storage IP.
- Select this option if the IP is present on PCI platform.
-
- If you have a controller with this interface, say Y or M here.
-
- If unsure, say N.
-
-config MMC_SH_MMCIF
- tristate "SuperH Internal MMCIF support"
- depends on MMC_BLOCK && (SUPERH || ARCH_SHMOBILE)
- help
- This selects the MMC Host Interface controller (MMCIF).
-
- This driver supports MMCIF in sh7724/sh7757/sh7372.
-
-config MMC_JZ4740
- tristate "JZ4740 SD/Multimedia Card Interface support"
- depends on MACH_JZ4740
- help
- This selects support for the SD/MMC controller on Ingenic 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_VUB300
- tristate "VUB300 USB to SDIO/SD/MMC Host Controller support"
- depends on USB
- help
- This selects support for Elan Digital Systems' VUB300 chip.
-
- The VUB300 is a USB-SDIO Host Controller Interface chip
- that enables the host computer to use SDIO/SD/MMC cards
- via a USB 2.0 or USB 1.1 host.
-
- The VUB300 chip will be found in both physically separate
- USB to SDIO/SD/MMC adapters and embedded on some motherboards.
-
- The VUB300 chip supports SD and MMC memory cards in addition
- to single and multifunction SDIO cards.
-
- Some SDIO cards will need a firmware file to be loaded and
- sent to VUB300 chip in order to achieve better data throughput.
- Download these "Offload Pseudocode" from Elan Digital Systems'
- web-site http://www.elandigitalsystems.com/support/downloads.php
- and put them in /lib/firmware. Note that without these additional
- firmware files the VUB300 chip will still function, but not at
- the best obtainable data rate.
-
- To compile this mmc host controller driver as a module,
- choose M here: the module will be called vub300.
-
- If you have a computer with an embedded VUB300 chip
- or if you intend connecting a USB adapter based on a
- VUB300 chip 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.
-
-config MMC_ATSMB
- tristate "WonderMedia ATSMB(AHB To MMC/SD BUS)"
- help
- This selects the WMT Secure digital and Multimedia card Interface.
- If you have a machine with WonderMedia ATSMB, say Y or M here.
-
- If unsure, say N.
-
-config MMC_ATSMB1
- tristate "WonderMedia ATSMB1(AHB To MMC/SD1 BUS)"
- help
- This selects the WMT Secure digital and Multimedia card Interface.
- If you have a machine with WonderMedia ATSMB1, say Y or M here.
-
- If unsure, say N.
-
-config MMC_ATSMB2
- tristate "WonderMedia ATSMB2(AHB To MMC/SD2 BUS)"
- help
- This selects the WMT Secure digital and Multimedia card Interface.
- If you have a machine with WonderMedia ATSMB2, say Y or M here.
-
- If unsure, say N.
-
diff --git a/ANDROID_3.4.5/drivers/mmc/host/Makefile b/ANDROID_3.4.5/drivers/mmc/host/Makefile
deleted file mode 100644
index b46a087b..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/Makefile
+++ /dev/null
@@ -1,63 +0,0 @@
-#
-# Makefile for MMC/SD host controller drivers
-#
-
-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_MXS) += mxs-mmc.o
-obj-$(CONFIG_MMC_SDHCI) += sdhci.o
-obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o
-obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o
-obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o
-obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o
-obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o
-obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o
-obj-$(CONFIG_MMC_WBSD) += wbsd.o
-obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
-obj-$(CONFIG_MMC_OMAP) += omap.o
-obj-$(CONFIG_MMC_OMAP_HS) += omap_hsmmc.o
-obj-$(CONFIG_MMC_AT91) += at91_mci.o
-obj-$(CONFIG_MMC_ATMELMCI) += atmel-mci.o
-obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
-obj-$(CONFIG_MMC_MSM) += msm_sdcc.o
-obj-$(CONFIG_MMC_MVSDIO) += mvsdio.o
-obj-$(CONFIG_MMC_DAVINCI) += davinci_mmc.o
-obj-$(CONFIG_MMC_SPI) += mmc_spi.o
-ifeq ($(CONFIG_OF),y)
-obj-$(CONFIG_MMC_SPI) += of_mmc_spi.o
-endif
-obj-$(CONFIG_MMC_S3C) += s3cmci.o
-obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
-obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o
-obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o
-tmio_mmc_core-y := tmio_mmc_pio.o
-tmio_mmc_core-$(subst m,y,$(CONFIG_MMC_SDHI)) += tmio_mmc_dma.o
-obj-$(CONFIG_MMC_SDHI) += sh_mobile_sdhi.o
-obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
-obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
-obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
-obj-$(CONFIG_MMC_DW) += dw_mmc.o
-obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o
-obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o
-obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
-obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
-obj-$(CONFIG_MMC_VUB300) += vub300.o
-obj-$(CONFIG_MMC_USHC) += ushc.o
-
-obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o
-obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o
-obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o
-obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o
-obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o
-obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
-obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
-
-ifeq ($(CONFIG_CB710_DEBUG),y)
- CFLAGS-cb710-mmc += -DDEBUG
-endif
-
-obj-$(CONFIG_MMC_ATSMB) += mmc_atsmb.o
-obj-$(CONFIG_MMC_ATSMB1) += mmc_atsmb1.o
-obj-$(CONFIG_MMC_ATSMB2) += mmc_atsmb2.o
diff --git a/ANDROID_3.4.5/drivers/mmc/host/at91_mci.c b/ANDROID_3.4.5/drivers/mmc/host/at91_mci.c
deleted file mode 100644
index efdb81d2..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/at91_mci.c
+++ /dev/null
@@ -1,1219 +0,0 @@
-/*
- * linux/drivers/mmc/host/at91_mci.c - ATMEL AT91 MCI Driver
- *
- * Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved
- *
- * Copyright (C) 2006 Malcolm Noyes
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
- This is the AT91 MCI driver that has been tested with both MMC cards
- and SD-cards. Boards that support write protect are now supported.
- The CCAT91SBC001 board does not support SD cards.
-
- The three entry points are at91_mci_request, at91_mci_set_ios
- and at91_mci_get_ro.
-
- SET IOS
- This configures the device to put it into the correct mode and clock speed
- required.
-
- MCI REQUEST
- MCI request processes the commands sent in the mmc_request structure. This
- can consist of a processing command and a stop command in the case of
- multiple block transfers.
-
- There are three main types of request, commands, reads and writes.
-
- Commands are straight forward. The command is submitted to the controller and
- the request function returns. When the controller generates an interrupt to indicate
- the command is finished, the response to the command are read and the mmc_request_done
- function called to end the request.
-
- Reads and writes work in a similar manner to normal commands but involve the PDC (DMA)
- controller to manage the transfers.
-
- A read is done from the controller directly to the scatterlist passed in from the request.
- Due to a bug in the AT91RM9200 controller, when a read is completed, all the words are byte
- swapped in the scatterlist buffers. AT91SAM926x are not affected by this bug.
-
- The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY
-
- A write is slightly different in that the bytes to write are read from the scatterlist
- into a dma memory buffer (this is in case the source buffer should be read only). The
- entire write buffer is then done from this single dma memory buffer.
-
- The sequence of write interrupts is: ENDTX, TXBUFE, NOTBUSY, CMDRDY
-
- GET RO
- Gets the status of the write protect pin, if available.
-*/
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk.h>
-#include <linux/atmel_pdc.h>
-#include <linux/gfp.h>
-#include <linux/highmem.h>
-
-#include <linux/mmc/host.h>
-#include <linux/mmc/sdio.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/gpio.h>
-
-#include <mach/board.h>
-#include <mach/cpu.h>
-
-#include "at91_mci.h"
-
-#define DRIVER_NAME "at91_mci"
-
-static inline int at91mci_is_mci1rev2xx(void)
-{
- return ( cpu_is_at91sam9260()
- || cpu_is_at91sam9263()
- || cpu_is_at91sam9rl()
- || cpu_is_at91sam9g10()
- || cpu_is_at91sam9g20()
- );
-}
-
-#define FL_SENT_COMMAND (1 << 0)
-#define FL_SENT_STOP (1 << 1)
-
-#define AT91_MCI_ERRORS (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE \
- | AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE \
- | AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)
-
-#define at91_mci_read(host, reg) __raw_readl((host)->baseaddr + (reg))
-#define at91_mci_write(host, reg, val) __raw_writel((val), (host)->baseaddr + (reg))
-
-#define MCI_BLKSIZE 512
-#define MCI_MAXBLKSIZE 4095
-#define MCI_BLKATONCE 256
-#define MCI_BUFSIZE (MCI_BLKSIZE * MCI_BLKATONCE)
-
-/*
- * Low level type for this driver
- */
-struct at91mci_host
-{
- struct mmc_host *mmc;
- struct mmc_command *cmd;
- struct mmc_request *request;
-
- void __iomem *baseaddr;
- int irq;
-
- struct at91_mmc_data *board;
- int present;
-
- struct clk *mci_clk;
-
- /*
- * Flag indicating when the command has been sent. This is used to
- * work out whether or not to send the stop
- */
- unsigned int flags;
- /* flag for current bus settings */
- u32 bus_mode;
-
- /* DMA buffer used for transmitting */
- unsigned int* buffer;
- dma_addr_t physical_address;
- unsigned int total_length;
-
- /* Latest in the scatterlist that has been enabled for transfer, but not freed */
- int in_use_index;
-
- /* Latest in the scatterlist that has been enabled for transfer */
- int transfer_index;
-
- /* Timer for timeouts */
- struct timer_list timer;
-};
-
-/*
- * Reset the controller and restore most of the state
- */
-static void at91_reset_host(struct at91mci_host *host)
-{
- unsigned long flags;
- u32 mr;
- u32 sdcr;
- u32 dtor;
- u32 imr;
-
- local_irq_save(flags);
- imr = at91_mci_read(host, AT91_MCI_IMR);
-
- at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
-
- /* save current state */
- mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff;
- sdcr = at91_mci_read(host, AT91_MCI_SDCR);
- dtor = at91_mci_read(host, AT91_MCI_DTOR);
-
- /* reset the controller */
- at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
-
- /* restore state */
- at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
- at91_mci_write(host, AT91_MCI_MR, mr);
- at91_mci_write(host, AT91_MCI_SDCR, sdcr);
- at91_mci_write(host, AT91_MCI_DTOR, dtor);
- at91_mci_write(host, AT91_MCI_IER, imr);
-
- /* make sure sdio interrupts will fire */
- at91_mci_read(host, AT91_MCI_SR);
-
- local_irq_restore(flags);
-}
-
-static void at91_timeout_timer(unsigned long data)
-{
- struct at91mci_host *host;
-
- host = (struct at91mci_host *)data;
-
- if (host->request) {
- dev_err(host->mmc->parent, "Timeout waiting end of packet\n");
-
- if (host->cmd && host->cmd->data) {
- host->cmd->data->error = -ETIMEDOUT;
- } else {
- if (host->cmd)
- host->cmd->error = -ETIMEDOUT;
- else
- host->request->cmd->error = -ETIMEDOUT;
- }
-
- at91_reset_host(host);
- mmc_request_done(host->mmc, host->request);
- }
-}
-
-/*
- * Copy from sg to a dma block - used for transfers
- */
-static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data)
-{
- unsigned int len, i, size;
- unsigned *dmabuf = host->buffer;
-
- size = data->blksz * data->blocks;
- len = data->sg_len;
-
- /* MCI1 rev2xx Data Write Operation and number of bytes erratum */
- if (at91mci_is_mci1rev2xx())
- if (host->total_length == 12)
- memset(dmabuf, 0, 12);
-
- /*
- * Just loop through all entries. Size might not
- * be the entire list though so make sure that
- * we do not transfer too much.
- */
- for (i = 0; i < len; i++) {
- struct scatterlist *sg;
- int amount;
- unsigned int *sgbuffer;
-
- sg = &data->sg[i];
-
- sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset;
- amount = min(size, sg->length);
- size -= amount;
-
- if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */
- int index;
-
- for (index = 0; index < (amount / 4); index++)
- *dmabuf++ = swab32(sgbuffer[index]);
- } else {
- char *tmpv = (char *)dmabuf;
- memcpy(tmpv, sgbuffer, amount);
- tmpv += amount;
- dmabuf = (unsigned *)tmpv;
- }
-
- kunmap_atomic(sgbuffer);
-
- if (size == 0)
- break;
- }
-
- /*
- * Check that we didn't get a request to transfer
- * more data than can fit into the SG list.
- */
- BUG_ON(size != 0);
-}
-
-/*
- * Handle after a dma read
- */
-static void at91_mci_post_dma_read(struct at91mci_host *host)
-{
- struct mmc_command *cmd;
- struct mmc_data *data;
- unsigned int len, i, size;
- unsigned *dmabuf = host->buffer;
-
- pr_debug("post dma read\n");
-
- cmd = host->cmd;
- if (!cmd) {
- pr_debug("no command\n");
- return;
- }
-
- data = cmd->data;
- if (!data) {
- pr_debug("no data\n");
- return;
- }
-
- size = data->blksz * data->blocks;
- len = data->sg_len;
-
- at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_ENDRX);
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF);
-
- for (i = 0; i < len; i++) {
- struct scatterlist *sg;
- int amount;
- unsigned int *sgbuffer;
-
- sg = &data->sg[i];
-
- sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset;
- amount = min(size, sg->length);
- size -= amount;
-
- if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */
- int index;
- for (index = 0; index < (amount / 4); index++)
- sgbuffer[index] = swab32(*dmabuf++);
- } else {
- char *tmpv = (char *)dmabuf;
- memcpy(sgbuffer, tmpv, amount);
- tmpv += amount;
- dmabuf = (unsigned *)tmpv;
- }
-
- flush_kernel_dcache_page(sg_page(sg));
- kunmap_atomic(sgbuffer);
- data->bytes_xfered += amount;
- if (size == 0)
- break;
- }
-
- pr_debug("post dma read done\n");
-}
-
-/*
- * Handle transmitted data
- */
-static void at91_mci_handle_transmitted(struct at91mci_host *host)
-{
- struct mmc_command *cmd;
- struct mmc_data *data;
-
- pr_debug("Handling the transmit\n");
-
- /* Disable the transfer */
- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
-
- /* Now wait for cmd ready */
- at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE);
-
- cmd = host->cmd;
- if (!cmd) return;
-
- data = cmd->data;
- if (!data) return;
-
- if (cmd->data->blocks > 1) {
- pr_debug("multiple write : wait for BLKE...\n");
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE);
- } else
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
-}
-
-/*
- * Update bytes tranfered count during a write operation
- */
-static void at91_mci_update_bytes_xfered(struct at91mci_host *host)
-{
- struct mmc_data *data;
-
- /* always deal with the effective request (and not the current cmd) */
-
- if (host->request->cmd && host->request->cmd->error != 0)
- return;
-
- if (host->request->data) {
- data = host->request->data;
- if (data->flags & MMC_DATA_WRITE) {
- /* card is in IDLE mode now */
- pr_debug("-> bytes_xfered %d, total_length = %d\n",
- data->bytes_xfered, host->total_length);
- data->bytes_xfered = data->blksz * data->blocks;
- }
- }
-}
-
-
-/*Handle after command sent ready*/
-static int at91_mci_handle_cmdrdy(struct at91mci_host *host)
-{
- if (!host->cmd)
- return 1;
- else if (!host->cmd->data) {
- if (host->flags & FL_SENT_STOP) {
- /*After multi block write, we must wait for NOTBUSY*/
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
- } else return 1;
- } else if (host->cmd->data->flags & MMC_DATA_WRITE) {
- /*After sendding multi-block-write command, start DMA transfer*/
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_TXBUFE | AT91_MCI_BLKE);
- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
- }
-
- /* command not completed, have to wait */
- return 0;
-}
-
-
-/*
- * Enable the controller
- */
-static void at91_mci_enable(struct at91mci_host *host)
-{
- unsigned int mr;
-
- at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
- at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
- at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);
- mr = AT91_MCI_PDCMODE | 0x34a;
-
- if (at91mci_is_mci1rev2xx())
- mr |= AT91_MCI_RDPROOF | AT91_MCI_WRPROOF;
-
- at91_mci_write(host, AT91_MCI_MR, mr);
-
- /* use Slot A or B (only one at same time) */
- at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b);
-}
-
-/*
- * Disable the controller
- */
-static void at91_mci_disable(struct at91mci_host *host)
-{
- at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
-}
-
-/*
- * Send a command
- */
-static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd)
-{
- unsigned int cmdr, mr;
- unsigned int block_length;
- struct mmc_data *data = cmd->data;
-
- unsigned int blocks;
- unsigned int ier = 0;
-
- host->cmd = cmd;
-
- /* Needed for leaving busy state before CMD1 */
- if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {
- pr_debug("Clearing timeout\n");
- at91_mci_write(host, AT91_MCI_ARGR, 0);
- at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD);
- while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
- /* spin */
- pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR));
- }
- }
-
- cmdr = cmd->opcode;
-
- if (mmc_resp_type(cmd) == MMC_RSP_NONE)
- cmdr |= AT91_MCI_RSPTYP_NONE;
- else {
- /* if a response is expected then allow maximum response latancy */
- cmdr |= AT91_MCI_MAXLAT;
- /* set 136 bit response for R2, 48 bit response otherwise */
- if (mmc_resp_type(cmd) == MMC_RSP_R2)
- cmdr |= AT91_MCI_RSPTYP_136;
- else
- cmdr |= AT91_MCI_RSPTYP_48;
- }
-
- if (data) {
-
- if (cpu_is_at91rm9200() || cpu_is_at91sam9261()) {
- if (data->blksz & 0x3) {
- pr_debug("Unsupported block size\n");
- cmd->error = -EINVAL;
- mmc_request_done(host->mmc, host->request);
- return;
- }
- if (data->flags & MMC_DATA_STREAM) {
- pr_debug("Stream commands not supported\n");
- cmd->error = -EINVAL;
- mmc_request_done(host->mmc, host->request);
- return;
- }
- }
-
- block_length = data->blksz;
- blocks = data->blocks;
-
- /* always set data start - also set direction flag for read */
- if (data->flags & MMC_DATA_READ)
- cmdr |= (AT91_MCI_TRDIR | AT91_MCI_TRCMD_START);
- else if (data->flags & MMC_DATA_WRITE)
- cmdr |= AT91_MCI_TRCMD_START;
-
- if (cmd->opcode == SD_IO_RW_EXTENDED) {
- cmdr |= AT91_MCI_TRTYP_SDIO_BLOCK;
- } else {
- if (data->flags & MMC_DATA_STREAM)
- cmdr |= AT91_MCI_TRTYP_STREAM;
- if (data->blocks > 1)
- cmdr |= AT91_MCI_TRTYP_MULTIPLE;
- }
- }
- else {
- block_length = 0;
- blocks = 0;
- }
-
- if (host->flags & FL_SENT_STOP)
- cmdr |= AT91_MCI_TRCMD_STOP;
-
- if (host->bus_mode == MMC_BUSMODE_OPENDRAIN)
- cmdr |= AT91_MCI_OPDCMD;
-
- /*
- * Set the arguments and send the command
- */
- pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n",
- cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR));
-
- if (!data) {
- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS);
- at91_mci_write(host, ATMEL_PDC_RPR, 0);
- at91_mci_write(host, ATMEL_PDC_RCR, 0);
- at91_mci_write(host, ATMEL_PDC_RNPR, 0);
- at91_mci_write(host, ATMEL_PDC_RNCR, 0);
- at91_mci_write(host, ATMEL_PDC_TPR, 0);
- at91_mci_write(host, ATMEL_PDC_TCR, 0);
- at91_mci_write(host, ATMEL_PDC_TNPR, 0);
- at91_mci_write(host, ATMEL_PDC_TNCR, 0);
- ier = AT91_MCI_CMDRDY;
- } else {
- /* zero block length and PDC mode */
- mr = at91_mci_read(host, AT91_MCI_MR) & 0x5fff;
- mr |= (data->blksz & 0x3) ? AT91_MCI_PDCFBYTE : 0;
- mr |= (block_length << 16);
- mr |= AT91_MCI_PDCMODE;
- at91_mci_write(host, AT91_MCI_MR, mr);
-
- if (!(cpu_is_at91rm9200() || cpu_is_at91sam9261()))
- at91_mci_write(host, AT91_MCI_BLKR,
- AT91_MCI_BLKR_BCNT(blocks) |
- AT91_MCI_BLKR_BLKLEN(block_length));
-
- /*
- * Disable the PDC controller
- */
- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
-
- if (cmdr & AT91_MCI_TRCMD_START) {
- data->bytes_xfered = 0;
- host->transfer_index = 0;
- host->in_use_index = 0;
- if (cmdr & AT91_MCI_TRDIR) {
- /*
- * Handle a read
- */
- host->total_length = 0;
-
- at91_mci_write(host, ATMEL_PDC_RPR, host->physical_address);
- at91_mci_write(host, ATMEL_PDC_RCR, (data->blksz & 0x3) ?
- (blocks * block_length) : (blocks * block_length) / 4);
- at91_mci_write(host, ATMEL_PDC_RNPR, 0);
- at91_mci_write(host, ATMEL_PDC_RNCR, 0);
-
- ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */;
- }
- else {
- /*
- * Handle a write
- */
- host->total_length = block_length * blocks;
- /*
- * MCI1 rev2xx Data Write Operation and
- * number of bytes erratum
- */
- if (at91mci_is_mci1rev2xx())
- if (host->total_length < 12)
- host->total_length = 12;
-
- at91_mci_sg_to_dma(host, data);
-
- pr_debug("Transmitting %d bytes\n", host->total_length);
-
- at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address);
- at91_mci_write(host, ATMEL_PDC_TCR, (data->blksz & 0x3) ?
- host->total_length : host->total_length / 4);
-
- ier = AT91_MCI_CMDRDY;
- }
- }
- }
-
- /*
- * Send the command and then enable the PDC - not the other way round as
- * the data sheet says
- */
-
- at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
- at91_mci_write(host, AT91_MCI_CMDR, cmdr);
-
- if (cmdr & AT91_MCI_TRCMD_START) {
- if (cmdr & AT91_MCI_TRDIR)
- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);
- }
-
- /* Enable selected interrupts */
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier);
-}
-
-/*
- * Process the next step in the request
- */
-static void at91_mci_process_next(struct at91mci_host *host)
-{
- if (!(host->flags & FL_SENT_COMMAND)) {
- host->flags |= FL_SENT_COMMAND;
- at91_mci_send_command(host, host->request->cmd);
- }
- else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) {
- host->flags |= FL_SENT_STOP;
- at91_mci_send_command(host, host->request->stop);
- } else {
- del_timer(&host->timer);
- /* the at91rm9200 mci controller hangs after some transfers,
- * and the workaround is to reset it after each transfer.
- */
- if (cpu_is_at91rm9200())
- at91_reset_host(host);
- mmc_request_done(host->mmc, host->request);
- }
-}
-
-/*
- * Handle a command that has been completed
- */
-static void at91_mci_completed_command(struct at91mci_host *host, unsigned int status)
-{
- struct mmc_command *cmd = host->cmd;
- struct mmc_data *data = cmd->data;
-
- at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
-
- cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0));
- cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1));
- cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2));
- cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3));
-
- pr_debug("Status = %08X/%08x [%08X %08X %08X %08X]\n",
- status, at91_mci_read(host, AT91_MCI_SR),
- cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
-
- if (status & AT91_MCI_ERRORS) {
- if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) {
- cmd->error = 0;
- }
- else {
- if (status & (AT91_MCI_DTOE | AT91_MCI_DCRCE)) {
- if (data) {
- if (status & AT91_MCI_DTOE)
- data->error = -ETIMEDOUT;
- else if (status & AT91_MCI_DCRCE)
- data->error = -EILSEQ;
- }
- } else {
- if (status & AT91_MCI_RTOE)
- cmd->error = -ETIMEDOUT;
- else if (status & AT91_MCI_RCRCE)
- cmd->error = -EILSEQ;
- else
- cmd->error = -EIO;
- }
-
- pr_debug("Error detected and set to %d/%d (cmd = %d, retries = %d)\n",
- cmd->error, data ? data->error : 0,
- cmd->opcode, cmd->retries);
- }
- }
- else
- cmd->error = 0;
-
- at91_mci_process_next(host);
-}
-
-/*
- * Handle an MMC request
- */
-static void at91_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct at91mci_host *host = mmc_priv(mmc);
- host->request = mrq;
- host->flags = 0;
-
- /* more than 1s timeout needed with slow SD cards */
- mod_timer(&host->timer, jiffies + msecs_to_jiffies(2000));
-
- at91_mci_process_next(host);
-}
-
-/*
- * Set the IOS
- */
-static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- int clkdiv;
- struct at91mci_host *host = mmc_priv(mmc);
- unsigned long at91_master_clock = clk_get_rate(host->mci_clk);
-
- host->bus_mode = ios->bus_mode;
-
- if (ios->clock == 0) {
- /* Disable the MCI controller */
- at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS);
- clkdiv = 0;
- }
- else {
- /* Enable the MCI controller */
- at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
-
- if ((at91_master_clock % (ios->clock * 2)) == 0)
- clkdiv = ((at91_master_clock / ios->clock) / 2) - 1;
- else
- clkdiv = (at91_master_clock / ios->clock) / 2;
-
- pr_debug("clkdiv = %d. mcck = %ld\n", clkdiv,
- at91_master_clock / (2 * (clkdiv + 1)));
- }
- if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) {
- pr_debug("MMC: Setting controller bus width to 4\n");
- at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) | AT91_MCI_SDCBUS);
- }
- else {
- pr_debug("MMC: Setting controller bus width to 1\n");
- at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
- }
-
- /* Set the clock divider */
- at91_mci_write(host, AT91_MCI_MR, (at91_mci_read(host, AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv);
-
- /* maybe switch power to the card */
- if (gpio_is_valid(host->board->vcc_pin)) {
- switch (ios->power_mode) {
- case MMC_POWER_OFF:
- gpio_set_value(host->board->vcc_pin, 0);
- break;
- case MMC_POWER_UP:
- gpio_set_value(host->board->vcc_pin, 1);
- break;
- case MMC_POWER_ON:
- break;
- default:
- WARN_ON(1);
- }
- }
-}
-
-/*
- * Handle an interrupt
- */
-static irqreturn_t at91_mci_irq(int irq, void *devid)
-{
- struct at91mci_host *host = devid;
- int completed = 0;
- unsigned int int_status, int_mask;
-
- int_status = at91_mci_read(host, AT91_MCI_SR);
- int_mask = at91_mci_read(host, AT91_MCI_IMR);
-
- pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask,
- int_status & int_mask);
-
- int_status = int_status & int_mask;
-
- if (int_status & AT91_MCI_ERRORS) {
- completed = 1;
-
- if (int_status & AT91_MCI_UNRE)
- pr_debug("MMC: Underrun error\n");
- if (int_status & AT91_MCI_OVRE)
- pr_debug("MMC: Overrun error\n");
- if (int_status & AT91_MCI_DTOE)
- pr_debug("MMC: Data timeout\n");
- if (int_status & AT91_MCI_DCRCE)
- pr_debug("MMC: CRC error in data\n");
- if (int_status & AT91_MCI_RTOE)
- pr_debug("MMC: Response timeout\n");
- if (int_status & AT91_MCI_RENDE)
- pr_debug("MMC: Response end bit error\n");
- if (int_status & AT91_MCI_RCRCE)
- pr_debug("MMC: Response CRC error\n");
- if (int_status & AT91_MCI_RDIRE)
- pr_debug("MMC: Response direction error\n");
- if (int_status & AT91_MCI_RINDE)
- pr_debug("MMC: Response index error\n");
- } else {
- /* Only continue processing if no errors */
-
- if (int_status & AT91_MCI_TXBUFE) {
- pr_debug("TX buffer empty\n");
- at91_mci_handle_transmitted(host);
- }
-
- if (int_status & AT91_MCI_ENDRX) {
- pr_debug("ENDRX\n");
- at91_mci_post_dma_read(host);
- }
-
- if (int_status & AT91_MCI_RXBUFF) {
- pr_debug("RX buffer full\n");
- at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
- at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_RXBUFF | AT91_MCI_ENDRX);
- completed = 1;
- }
-
- if (int_status & AT91_MCI_ENDTX)
- pr_debug("Transmit has ended\n");
-
- if (int_status & AT91_MCI_NOTBUSY) {
- pr_debug("Card is ready\n");
- at91_mci_update_bytes_xfered(host);
- completed = 1;
- }
-
- if (int_status & AT91_MCI_DTIP)
- pr_debug("Data transfer in progress\n");
-
- if (int_status & AT91_MCI_BLKE) {
- pr_debug("Block transfer has ended\n");
- if (host->request->data && host->request->data->blocks > 1) {
- /* multi block write : complete multi write
- * command and send stop */
- completed = 1;
- } else {
- at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
- }
- }
-
- if (int_status & AT91_MCI_SDIOIRQA)
- mmc_signal_sdio_irq(host->mmc);
-
- if (int_status & AT91_MCI_SDIOIRQB)
- mmc_signal_sdio_irq(host->mmc);
-
- if (int_status & AT91_MCI_TXRDY)
- pr_debug("Ready to transmit\n");
-
- if (int_status & AT91_MCI_RXRDY)
- pr_debug("Ready to receive\n");
-
- if (int_status & AT91_MCI_CMDRDY) {
- pr_debug("Command ready\n");
- completed = at91_mci_handle_cmdrdy(host);
- }
- }
-
- if (completed) {
- pr_debug("Completed command\n");
- at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
- at91_mci_completed_command(host, int_status);
- } else
- at91_mci_write(host, AT91_MCI_IDR, int_status & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB));
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t at91_mmc_det_irq(int irq, void *_host)
-{
- struct at91mci_host *host = _host;
- int present;
-
- /* entering this ISR means that we have configured det_pin:
- * we can use its value in board structure */
- present = !gpio_get_value(host->board->det_pin);
-
- /*
- * we expect this irq on both insert and remove,
- * and use a short delay to debounce.
- */
- if (present != host->present) {
- host->present = present;
- pr_debug("%s: card %s\n", mmc_hostname(host->mmc),
- present ? "insert" : "remove");
- if (!present) {
- pr_debug("****** Resetting SD-card bus width ******\n");
- at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
- }
- /* 0.5s needed because of early card detect switch firing */
- mmc_detect_change(host->mmc, msecs_to_jiffies(500));
- }
- return IRQ_HANDLED;
-}
-
-static int at91_mci_get_ro(struct mmc_host *mmc)
-{
- struct at91mci_host *host = mmc_priv(mmc);
-
- if (gpio_is_valid(host->board->wp_pin))
- return !!gpio_get_value(host->board->wp_pin);
- /*
- * Board doesn't support read only detection; let the mmc core
- * decide what to do.
- */
- return -ENOSYS;
-}
-
-static void at91_mci_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
- struct at91mci_host *host = mmc_priv(mmc);
-
- pr_debug("%s: sdio_irq %c : %s\n", mmc_hostname(host->mmc),
- host->board->slot_b ? 'B':'A', enable ? "enable" : "disable");
- at91_mci_write(host, enable ? AT91_MCI_IER : AT91_MCI_IDR,
- host->board->slot_b ? AT91_MCI_SDIOIRQB : AT91_MCI_SDIOIRQA);
-
-}
-
-static const struct mmc_host_ops at91_mci_ops = {
- .request = at91_mci_request,
- .set_ios = at91_mci_set_ios,
- .get_ro = at91_mci_get_ro,
- .enable_sdio_irq = at91_mci_enable_sdio_irq,
-};
-
-/*
- * Probe for the device
- */
-static int __init at91_mci_probe(struct platform_device *pdev)
-{
- struct mmc_host *mmc;
- struct at91mci_host *host;
- struct resource *res;
- int ret;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENXIO;
-
- if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME))
- return -EBUSY;
-
- mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
- if (!mmc) {
- ret = -ENOMEM;
- dev_dbg(&pdev->dev, "couldn't allocate mmc host\n");
- goto fail6;
- }
-
- mmc->ops = &at91_mci_ops;
- mmc->f_min = 375000;
- mmc->f_max = 25000000;
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps = 0;
-
- mmc->max_blk_size = MCI_MAXBLKSIZE;
- mmc->max_blk_count = MCI_BLKATONCE;
- mmc->max_req_size = MCI_BUFSIZE;
- mmc->max_segs = MCI_BLKATONCE;
- mmc->max_seg_size = MCI_BUFSIZE;
-
- host = mmc_priv(mmc);
- host->mmc = mmc;
- host->bus_mode = 0;
- host->board = pdev->dev.platform_data;
- if (host->board->wire4) {
- if (at91mci_is_mci1rev2xx())
- mmc->caps |= MMC_CAP_4_BIT_DATA;
- else
- dev_warn(&pdev->dev, "4 wire bus mode not supported"
- " - using 1 wire\n");
- }
-
- host->buffer = dma_alloc_coherent(&pdev->dev, MCI_BUFSIZE,
- &host->physical_address, GFP_KERNEL);
- if (!host->buffer) {
- ret = -ENOMEM;
- dev_err(&pdev->dev, "Can't allocate transmit buffer\n");
- goto fail5;
- }
-
- /* Add SDIO capability when available */
- if (at91mci_is_mci1rev2xx()) {
- /* at91mci MCI1 rev2xx sdio interrupt erratum */
- if (host->board->wire4 || !host->board->slot_b)
- mmc->caps |= MMC_CAP_SDIO_IRQ;
- }
-
- /*
- * Reserve GPIOs ... board init code makes sure these pins are set
- * up as GPIOs with the right direction (input, except for vcc)
- */
- if (gpio_is_valid(host->board->det_pin)) {
- ret = gpio_request(host->board->det_pin, "mmc_detect");
- if (ret < 0) {
- dev_dbg(&pdev->dev, "couldn't claim card detect pin\n");
- goto fail4b;
- }
- }
- if (gpio_is_valid(host->board->wp_pin)) {
- ret = gpio_request(host->board->wp_pin, "mmc_wp");
- if (ret < 0) {
- dev_dbg(&pdev->dev, "couldn't claim wp sense pin\n");
- goto fail4;
- }
- }
- if (gpio_is_valid(host->board->vcc_pin)) {
- ret = gpio_request(host->board->vcc_pin, "mmc_vcc");
- if (ret < 0) {
- dev_dbg(&pdev->dev, "couldn't claim vcc switch pin\n");
- goto fail3;
- }
- }
-
- /*
- * Get Clock
- */
- host->mci_clk = clk_get(&pdev->dev, "mci_clk");
- if (IS_ERR(host->mci_clk)) {
- ret = -ENODEV;
- dev_dbg(&pdev->dev, "no mci_clk?\n");
- goto fail2;
- }
-
- /*
- * Map I/O region
- */
- host->baseaddr = ioremap(res->start, resource_size(res));
- if (!host->baseaddr) {
- ret = -ENOMEM;
- goto fail1;
- }
-
- /*
- * Reset hardware
- */
- clk_enable(host->mci_clk); /* Enable the peripheral clock */
- at91_mci_disable(host);
- at91_mci_enable(host);
-
- /*
- * Allocate the MCI interrupt
- */
- host->irq = platform_get_irq(pdev, 0);
- ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED,
- mmc_hostname(mmc), host);
- if (ret) {
- dev_dbg(&pdev->dev, "request MCI interrupt failed\n");
- goto fail0;
- }
-
- setup_timer(&host->timer, at91_timeout_timer, (unsigned long)host);
-
- platform_set_drvdata(pdev, mmc);
-
- /*
- * Add host to MMC layer
- */
- if (gpio_is_valid(host->board->det_pin)) {
- host->present = !gpio_get_value(host->board->det_pin);
- }
- else
- host->present = -1;
-
- mmc_add_host(mmc);
-
- /*
- * monitor card insertion/removal if we can
- */
- if (gpio_is_valid(host->board->det_pin)) {
- ret = request_irq(gpio_to_irq(host->board->det_pin),
- at91_mmc_det_irq, 0, mmc_hostname(mmc), host);
- if (ret)
- dev_warn(&pdev->dev, "request MMC detect irq failed\n");
- else
- device_init_wakeup(&pdev->dev, 1);
- }
-
- pr_debug("Added MCI driver\n");
-
- return 0;
-
-fail0:
- clk_disable(host->mci_clk);
- iounmap(host->baseaddr);
-fail1:
- clk_put(host->mci_clk);
-fail2:
- if (gpio_is_valid(host->board->vcc_pin))
- gpio_free(host->board->vcc_pin);
-fail3:
- if (gpio_is_valid(host->board->wp_pin))
- gpio_free(host->board->wp_pin);
-fail4:
- if (gpio_is_valid(host->board->det_pin))
- gpio_free(host->board->det_pin);
-fail4b:
- if (host->buffer)
- dma_free_coherent(&pdev->dev, MCI_BUFSIZE,
- host->buffer, host->physical_address);
-fail5:
- mmc_free_host(mmc);
-fail6:
- release_mem_region(res->start, resource_size(res));
- dev_err(&pdev->dev, "probe failed, err %d\n", ret);
- return ret;
-}
-
-/*
- * Remove a device
- */
-static int __exit at91_mci_remove(struct platform_device *pdev)
-{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
- struct at91mci_host *host;
- struct resource *res;
-
- if (!mmc)
- return -1;
-
- host = mmc_priv(mmc);
-
- if (host->buffer)
- dma_free_coherent(&pdev->dev, MCI_BUFSIZE,
- host->buffer, host->physical_address);
-
- if (gpio_is_valid(host->board->det_pin)) {
- if (device_can_wakeup(&pdev->dev))
- free_irq(gpio_to_irq(host->board->det_pin), host);
- device_init_wakeup(&pdev->dev, 0);
- gpio_free(host->board->det_pin);
- }
-
- at91_mci_disable(host);
- del_timer_sync(&host->timer);
- mmc_remove_host(mmc);
- free_irq(host->irq, host);
-
- clk_disable(host->mci_clk); /* Disable the peripheral clock */
- clk_put(host->mci_clk);
-
- if (gpio_is_valid(host->board->vcc_pin))
- gpio_free(host->board->vcc_pin);
- if (gpio_is_valid(host->board->wp_pin))
- gpio_free(host->board->wp_pin);
-
- iounmap(host->baseaddr);
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
-
- mmc_free_host(mmc);
- platform_set_drvdata(pdev, NULL);
- pr_debug("MCI Removed\n");
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
- struct at91mci_host *host = mmc_priv(mmc);
- int ret = 0;
-
- if (gpio_is_valid(host->board->det_pin) && device_may_wakeup(&pdev->dev))
- enable_irq_wake(host->board->det_pin);
-
- if (mmc)
- ret = mmc_suspend_host(mmc);
-
- return ret;
-}
-
-static int at91_mci_resume(struct platform_device *pdev)
-{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
- struct at91mci_host *host = mmc_priv(mmc);
- int ret = 0;
-
- if (gpio_is_valid(host->board->det_pin) && device_may_wakeup(&pdev->dev))
- disable_irq_wake(host->board->det_pin);
-
- if (mmc)
- ret = mmc_resume_host(mmc);
-
- return ret;
-}
-#else
-#define at91_mci_suspend NULL
-#define at91_mci_resume NULL
-#endif
-
-static struct platform_driver at91_mci_driver = {
- .remove = __exit_p(at91_mci_remove),
- .suspend = at91_mci_suspend,
- .resume = at91_mci_resume,
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- },
-};
-
-static int __init at91_mci_init(void)
-{
- return platform_driver_probe(&at91_mci_driver, at91_mci_probe);
-}
-
-static void __exit at91_mci_exit(void)
-{
- platform_driver_unregister(&at91_mci_driver);
-}
-
-module_init(at91_mci_init);
-module_exit(at91_mci_exit);
-
-MODULE_DESCRIPTION("AT91 Multimedia Card Interface driver");
-MODULE_AUTHOR("Nick Randell");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:at91_mci");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/at91_mci.h b/ANDROID_3.4.5/drivers/mmc/host/at91_mci.h
deleted file mode 100644
index eec3a6b1..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/at91_mci.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * drivers/mmc/host/at91_mci.h
- *
- * Copyright (C) 2005 Ivan Kokshaysky
- * Copyright (C) SAN People
- *
- * MultiMedia Card Interface (MCI) registers.
- * Based on AT91RM9200 datasheet revision F.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef AT91_MCI_H
-#define AT91_MCI_H
-
-#define AT91_MCI_CR 0x00 /* Control Register */
-#define AT91_MCI_MCIEN (1 << 0) /* Multi-Media Interface Enable */
-#define AT91_MCI_MCIDIS (1 << 1) /* Multi-Media Interface Disable */
-#define AT91_MCI_PWSEN (1 << 2) /* Power Save Mode Enable */
-#define AT91_MCI_PWSDIS (1 << 3) /* Power Save Mode Disable */
-#define AT91_MCI_SWRST (1 << 7) /* Software Reset */
-
-#define AT91_MCI_MR 0x04 /* Mode Register */
-#define AT91_MCI_CLKDIV (0xff << 0) /* Clock Divider */
-#define AT91_MCI_PWSDIV (7 << 8) /* Power Saving Divider */
-#define AT91_MCI_RDPROOF (1 << 11) /* Read Proof Enable [SAM926[03] only] */
-#define AT91_MCI_WRPROOF (1 << 12) /* Write Proof Enable [SAM926[03] only] */
-#define AT91_MCI_PDCFBYTE (1 << 13) /* PDC Force Byte Transfer [SAM926[03] only] */
-#define AT91_MCI_PDCPADV (1 << 14) /* PDC Padding Value */
-#define AT91_MCI_PDCMODE (1 << 15) /* PDC-orientated Mode */
-#define AT91_MCI_BLKLEN (0xfff << 18) /* Data Block Length */
-
-#define AT91_MCI_DTOR 0x08 /* Data Timeout Register */
-#define AT91_MCI_DTOCYC (0xf << 0) /* Data Timeout Cycle Number */
-#define AT91_MCI_DTOMUL (7 << 4) /* Data Timeout Multiplier */
-#define AT91_MCI_DTOMUL_1 (0 << 4)
-#define AT91_MCI_DTOMUL_16 (1 << 4)
-#define AT91_MCI_DTOMUL_128 (2 << 4)
-#define AT91_MCI_DTOMUL_256 (3 << 4)
-#define AT91_MCI_DTOMUL_1K (4 << 4)
-#define AT91_MCI_DTOMUL_4K (5 << 4)
-#define AT91_MCI_DTOMUL_64K (6 << 4)
-#define AT91_MCI_DTOMUL_1M (7 << 4)
-
-#define AT91_MCI_SDCR 0x0c /* SD Card Register */
-#define AT91_MCI_SDCSEL (3 << 0) /* SD Card Selector */
-#define AT91_MCI_SDCBUS (1 << 7) /* 1-bit or 4-bit bus */
-
-#define AT91_MCI_ARGR 0x10 /* Argument Register */
-
-#define AT91_MCI_CMDR 0x14 /* Command Register */
-#define AT91_MCI_CMDNB (0x3f << 0) /* Command Number */
-#define AT91_MCI_RSPTYP (3 << 6) /* Response Type */
-#define AT91_MCI_RSPTYP_NONE (0 << 6)
-#define AT91_MCI_RSPTYP_48 (1 << 6)
-#define AT91_MCI_RSPTYP_136 (2 << 6)
-#define AT91_MCI_SPCMD (7 << 8) /* Special Command */
-#define AT91_MCI_SPCMD_NONE (0 << 8)
-#define AT91_MCI_SPCMD_INIT (1 << 8)
-#define AT91_MCI_SPCMD_SYNC (2 << 8)
-#define AT91_MCI_SPCMD_ICMD (4 << 8)
-#define AT91_MCI_SPCMD_IRESP (5 << 8)
-#define AT91_MCI_OPDCMD (1 << 11) /* Open Drain Command */
-#define AT91_MCI_MAXLAT (1 << 12) /* Max Latency for Command to Response */
-#define AT91_MCI_TRCMD (3 << 16) /* Transfer Command */
-#define AT91_MCI_TRCMD_NONE (0 << 16)
-#define AT91_MCI_TRCMD_START (1 << 16)
-#define AT91_MCI_TRCMD_STOP (2 << 16)
-#define AT91_MCI_TRDIR (1 << 18) /* Transfer Direction */
-#define AT91_MCI_TRTYP (3 << 19) /* Transfer Type */
-#define AT91_MCI_TRTYP_BLOCK (0 << 19)
-#define AT91_MCI_TRTYP_MULTIPLE (1 << 19)
-#define AT91_MCI_TRTYP_STREAM (2 << 19)
-#define AT91_MCI_TRTYP_SDIO_BYTE (4 << 19)
-#define AT91_MCI_TRTYP_SDIO_BLOCK (5 << 19)
-
-#define AT91_MCI_BLKR 0x18 /* Block Register */
-#define AT91_MCI_BLKR_BCNT(n) ((0xffff & (n)) << 0) /* Block count */
-#define AT91_MCI_BLKR_BLKLEN(n) ((0xffff & (n)) << 16) /* Block length */
-
-#define AT91_MCI_RSPR(n) (0x20 + ((n) * 4)) /* Response Registers 0-3 */
-#define AT91_MCR_RDR 0x30 /* Receive Data Register */
-#define AT91_MCR_TDR 0x34 /* Transmit Data Register */
-
-#define AT91_MCI_SR 0x40 /* Status Register */
-#define AT91_MCI_CMDRDY (1 << 0) /* Command Ready */
-#define AT91_MCI_RXRDY (1 << 1) /* Receiver Ready */
-#define AT91_MCI_TXRDY (1 << 2) /* Transmit Ready */
-#define AT91_MCI_BLKE (1 << 3) /* Data Block Ended */
-#define AT91_MCI_DTIP (1 << 4) /* Data Transfer in Progress */
-#define AT91_MCI_NOTBUSY (1 << 5) /* Data Not Busy */
-#define AT91_MCI_ENDRX (1 << 6) /* End of RX Buffer */
-#define AT91_MCI_ENDTX (1 << 7) /* End fo TX Buffer */
-#define AT91_MCI_SDIOIRQA (1 << 8) /* SDIO Interrupt for Slot A */
-#define AT91_MCI_SDIOIRQB (1 << 9) /* SDIO Interrupt for Slot B */
-#define AT91_MCI_RXBUFF (1 << 14) /* RX Buffer Full */
-#define AT91_MCI_TXBUFE (1 << 15) /* TX Buffer Empty */
-#define AT91_MCI_RINDE (1 << 16) /* Response Index Error */
-#define AT91_MCI_RDIRE (1 << 17) /* Response Direction Error */
-#define AT91_MCI_RCRCE (1 << 18) /* Response CRC Error */
-#define AT91_MCI_RENDE (1 << 19) /* Response End Bit Error */
-#define AT91_MCI_RTOE (1 << 20) /* Response Time-out Error */
-#define AT91_MCI_DCRCE (1 << 21) /* Data CRC Error */
-#define AT91_MCI_DTOE (1 << 22) /* Data Time-out Error */
-#define AT91_MCI_OVRE (1 << 30) /* Overrun */
-#define AT91_MCI_UNRE (1 << 31) /* Underrun */
-
-#define AT91_MCI_IER 0x44 /* Interrupt Enable Register */
-#define AT91_MCI_IDR 0x48 /* Interrupt Disable Register */
-#define AT91_MCI_IMR 0x4c /* Interrupt Mask Register */
-
-#endif
diff --git a/ANDROID_3.4.5/drivers/mmc/host/atmel-mci-regs.h b/ANDROID_3.4.5/drivers/mmc/host/atmel-mci-regs.h
deleted file mode 100644
index 787aba16..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/atmel-mci-regs.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Atmel MultiMedia Card Interface driver
- *
- * Copyright (C) 2004-2006 Atmel Corporation
- *
- * 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.
- */
-
-/*
- * Superset of MCI IP registers integrated in Atmel AVR32 and AT91 Processors
- * Registers and bitfields marked with [2] are only available in MCI2
- */
-
-#ifndef __DRIVERS_MMC_ATMEL_MCI_H__
-#define __DRIVERS_MMC_ATMEL_MCI_H__
-
-/* MCI Register Definitions */
-#define ATMCI_CR 0x0000 /* Control */
-# define ATMCI_CR_MCIEN ( 1 << 0) /* MCI Enable */
-# define ATMCI_CR_MCIDIS ( 1 << 1) /* MCI Disable */
-# define ATMCI_CR_PWSEN ( 1 << 2) /* Power Save Enable */
-# define ATMCI_CR_PWSDIS ( 1 << 3) /* Power Save Disable */
-# define ATMCI_CR_SWRST ( 1 << 7) /* Software Reset */
-#define ATMCI_MR 0x0004 /* Mode */
-# define ATMCI_MR_CLKDIV(x) ((x) << 0) /* Clock Divider */
-# define ATMCI_MR_PWSDIV(x) ((x) << 8) /* Power Saving Divider */
-# define ATMCI_MR_RDPROOF ( 1 << 11) /* Read Proof */
-# define ATMCI_MR_WRPROOF ( 1 << 12) /* Write Proof */
-# define ATMCI_MR_PDCFBYTE ( 1 << 13) /* Force Byte Transfer */
-# define ATMCI_MR_PDCPADV ( 1 << 14) /* Padding Value */
-# define ATMCI_MR_PDCMODE ( 1 << 15) /* PDC-oriented Mode */
-# define ATMCI_MR_CLKODD(x) ((x) << 16) /* LSB of Clock Divider */
-#define ATMCI_DTOR 0x0008 /* Data Timeout */
-# define ATMCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */
-# define ATMCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */
-#define ATMCI_SDCR 0x000c /* SD Card / SDIO */
-# define ATMCI_SDCSEL_SLOT_A ( 0 << 0) /* Select SD slot A */
-# define ATMCI_SDCSEL_SLOT_B ( 1 << 0) /* Select SD slot A */
-# define ATMCI_SDCSEL_MASK ( 3 << 0)
-# define ATMCI_SDCBUS_1BIT ( 0 << 6) /* 1-bit data bus */
-# define ATMCI_SDCBUS_4BIT ( 2 << 6) /* 4-bit data bus */
-# define ATMCI_SDCBUS_8BIT ( 3 << 6) /* 8-bit data bus[2] */
-# define ATMCI_SDCBUS_MASK ( 3 << 6)
-#define ATMCI_ARGR 0x0010 /* Command Argument */
-#define ATMCI_CMDR 0x0014 /* Command */
-# define ATMCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */
-# define ATMCI_CMDR_RSPTYP_NONE ( 0 << 6) /* No response */
-# define ATMCI_CMDR_RSPTYP_48BIT ( 1 << 6) /* 48-bit response */
-# define ATMCI_CMDR_RSPTYP_136BIT ( 2 << 6) /* 136-bit response */
-# define ATMCI_CMDR_SPCMD_INIT ( 1 << 8) /* Initialization command */
-# define ATMCI_CMDR_SPCMD_SYNC ( 2 << 8) /* Synchronized command */
-# define ATMCI_CMDR_SPCMD_INT ( 4 << 8) /* Interrupt command */
-# define ATMCI_CMDR_SPCMD_INTRESP ( 5 << 8) /* Interrupt response */
-# define ATMCI_CMDR_OPDCMD ( 1 << 11) /* Open Drain */
-# define ATMCI_CMDR_MAXLAT_5CYC ( 0 << 12) /* Max latency 5 cycles */
-# define ATMCI_CMDR_MAXLAT_64CYC ( 1 << 12) /* Max latency 64 cycles */
-# define ATMCI_CMDR_START_XFER ( 1 << 16) /* Start data transfer */
-# define ATMCI_CMDR_STOP_XFER ( 2 << 16) /* Stop data transfer */
-# define ATMCI_CMDR_TRDIR_WRITE ( 0 << 18) /* Write data */
-# define ATMCI_CMDR_TRDIR_READ ( 1 << 18) /* Read data */
-# define ATMCI_CMDR_BLOCK ( 0 << 19) /* Single-block transfer */
-# define ATMCI_CMDR_MULTI_BLOCK ( 1 << 19) /* Multi-block transfer */
-# define ATMCI_CMDR_STREAM ( 2 << 19) /* MMC Stream transfer */
-# define ATMCI_CMDR_SDIO_BYTE ( 4 << 19) /* SDIO Byte transfer */
-# define ATMCI_CMDR_SDIO_BLOCK ( 5 << 19) /* SDIO Block transfer */
-# define ATMCI_CMDR_SDIO_SUSPEND ( 1 << 24) /* SDIO Suspend Command */
-# define ATMCI_CMDR_SDIO_RESUME ( 2 << 24) /* SDIO Resume Command */
-#define ATMCI_BLKR 0x0018 /* Block */
-# define ATMCI_BCNT(x) ((x) << 0) /* Data Block Count */
-# define ATMCI_BLKLEN(x) ((x) << 16) /* Data Block Length */
-#define ATMCI_CSTOR 0x001c /* Completion Signal Timeout[2] */
-# define ATMCI_CSTOCYC(x) ((x) << 0) /* CST cycles */
-# define ATMCI_CSTOMUL(x) ((x) << 4) /* CST multiplier */
-#define ATMCI_RSPR 0x0020 /* Response 0 */
-#define ATMCI_RSPR1 0x0024 /* Response 1 */
-#define ATMCI_RSPR2 0x0028 /* Response 2 */
-#define ATMCI_RSPR3 0x002c /* Response 3 */
-#define ATMCI_RDR 0x0030 /* Receive Data */
-#define ATMCI_TDR 0x0034 /* Transmit Data */
-#define ATMCI_SR 0x0040 /* Status */
-#define ATMCI_IER 0x0044 /* Interrupt Enable */
-#define ATMCI_IDR 0x0048 /* Interrupt Disable */
-#define ATMCI_IMR 0x004c /* Interrupt Mask */
-# define ATMCI_CMDRDY ( 1 << 0) /* Command Ready */
-# define ATMCI_RXRDY ( 1 << 1) /* Receiver Ready */
-# define ATMCI_TXRDY ( 1 << 2) /* Transmitter Ready */
-# define ATMCI_BLKE ( 1 << 3) /* Data Block Ended */
-# define ATMCI_DTIP ( 1 << 4) /* Data Transfer In Progress */
-# define ATMCI_NOTBUSY ( 1 << 5) /* Data Not Busy */
-# define ATMCI_ENDRX ( 1 << 6) /* End of RX Buffer */
-# define ATMCI_ENDTX ( 1 << 7) /* End of TX Buffer */
-# define ATMCI_SDIOIRQA ( 1 << 8) /* SDIO IRQ in slot A */
-# define ATMCI_SDIOIRQB ( 1 << 9) /* SDIO IRQ in slot B */
-# define ATMCI_SDIOWAIT ( 1 << 12) /* SDIO Read Wait Operation Status */
-# define ATMCI_CSRCV ( 1 << 13) /* CE-ATA Completion Signal Received */
-# define ATMCI_RXBUFF ( 1 << 14) /* RX Buffer Full */
-# define ATMCI_TXBUFE ( 1 << 15) /* TX Buffer Empty */
-# define ATMCI_RINDE ( 1 << 16) /* Response Index Error */
-# define ATMCI_RDIRE ( 1 << 17) /* Response Direction Error */
-# define ATMCI_RCRCE ( 1 << 18) /* Response CRC Error */
-# define ATMCI_RENDE ( 1 << 19) /* Response End Bit Error */
-# define ATMCI_RTOE ( 1 << 20) /* Response Time-Out Error */
-# define ATMCI_DCRCE ( 1 << 21) /* Data CRC Error */
-# define ATMCI_DTOE ( 1 << 22) /* Data Time-Out Error */
-# define ATMCI_CSTOE ( 1 << 23) /* Completion Signal Time-out Error */
-# define ATMCI_BLKOVRE ( 1 << 24) /* DMA Block Overrun Error */
-# define ATMCI_DMADONE ( 1 << 25) /* DMA Transfer Done */
-# define ATMCI_FIFOEMPTY ( 1 << 26) /* FIFO Empty Flag */
-# define ATMCI_XFRDONE ( 1 << 27) /* Transfer Done Flag */
-# define ATMCI_ACKRCV ( 1 << 28) /* Boot Operation Acknowledge Received */
-# define ATMCI_ACKRCVE ( 1 << 29) /* Boot Operation Acknowledge Error */
-# define ATMCI_OVRE ( 1 << 30) /* RX Overrun Error */
-# define ATMCI_UNRE ( 1 << 31) /* TX Underrun Error */
-#define ATMCI_DMA 0x0050 /* DMA Configuration[2] */
-# define ATMCI_DMA_OFFSET(x) ((x) << 0) /* DMA Write Buffer Offset */
-# define ATMCI_DMA_CHKSIZE(x) ((x) << 4) /* DMA Channel Read and Write Chunk Size */
-# define ATMCI_DMAEN ( 1 << 8) /* DMA Hardware Handshaking Enable */
-#define ATMCI_CFG 0x0054 /* Configuration[2] */
-# define ATMCI_CFG_FIFOMODE_1DATA ( 1 << 0) /* MCI Internal FIFO control mode */
-# define ATMCI_CFG_FERRCTRL_COR ( 1 << 4) /* Flow Error flag reset control mode */
-# define ATMCI_CFG_HSMODE ( 1 << 8) /* High Speed Mode */
-# define ATMCI_CFG_LSYNC ( 1 << 12) /* Synchronize on the last block */
-#define ATMCI_WPMR 0x00e4 /* Write Protection Mode[2] */
-# define ATMCI_WP_EN ( 1 << 0) /* WP Enable */
-# define ATMCI_WP_KEY (0x4d4349 << 8) /* WP Key */
-#define ATMCI_WPSR 0x00e8 /* Write Protection Status[2] */
-# define ATMCI_GET_WP_VS(x) ((x) & 0x0f)
-# define ATMCI_GET_WP_VSRC(x) (((x) >> 8) & 0xffff)
-#define ATMCI_VERSION 0x00FC /* Version */
-#define ATMCI_FIFO_APERTURE 0x0200 /* FIFO Aperture[2] */
-
-/* This is not including the FIFO Aperture on MCI2 */
-#define ATMCI_REGS_SIZE 0x100
-
-/* Register access macros */
-#define atmci_readl(port,reg) \
- __raw_readl((port)->regs + reg)
-#define atmci_writel(port,reg,value) \
- __raw_writel((value), (port)->regs + reg)
-
-#endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */
diff --git a/ANDROID_3.4.5/drivers/mmc/host/atmel-mci.c b/ANDROID_3.4.5/drivers/mmc/host/atmel-mci.c
deleted file mode 100644
index e94476be..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/atmel-mci.c
+++ /dev/null
@@ -1,2291 +0,0 @@
-/*
- * Atmel MultiMedia Card Interface driver
- *
- * Copyright (C) 2004-2008 Atmel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/blkdev.h>
-#include <linux/clk.h>
-#include <linux/debugfs.h>
-#include <linux/device.h>
-#include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
-#include <linux/err.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/scatterlist.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/types.h>
-
-#include <linux/mmc/host.h>
-#include <linux/mmc/sdio.h>
-
-#include <mach/atmel-mci.h>
-#include <linux/atmel-mci.h>
-#include <linux/atmel_pdc.h>
-
-#include <asm/io.h>
-#include <asm/unaligned.h>
-
-#include <mach/cpu.h>
-#include <mach/board.h>
-
-#include "atmel-mci-regs.h"
-
-#define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE)
-#define ATMCI_DMA_THRESHOLD 16
-
-enum {
- EVENT_CMD_COMPLETE = 0,
- EVENT_XFER_COMPLETE,
- EVENT_DATA_COMPLETE,
- EVENT_DATA_ERROR,
-};
-
-enum atmel_mci_state {
- STATE_IDLE = 0,
- STATE_SENDING_CMD,
- STATE_SENDING_DATA,
- STATE_DATA_BUSY,
- STATE_SENDING_STOP,
- STATE_DATA_ERROR,
-};
-
-enum atmci_xfer_dir {
- XFER_RECEIVE = 0,
- XFER_TRANSMIT,
-};
-
-enum atmci_pdc_buf {
- PDC_FIRST_BUF = 0,
- PDC_SECOND_BUF,
-};
-
-struct atmel_mci_caps {
- bool has_dma;
- bool has_pdc;
- bool has_cfg_reg;
- bool has_cstor_reg;
- bool has_highspeed;
- bool has_rwproof;
- bool has_odd_clk_div;
-};
-
-struct atmel_mci_dma {
- struct dma_chan *chan;
- struct dma_async_tx_descriptor *data_desc;
-};
-
-/**
- * struct atmel_mci - MMC controller state shared between all slots
- * @lock: Spinlock protecting the queue and associated data.
- * @regs: Pointer to MMIO registers.
- * @sg: Scatterlist entry currently being processed by PIO or PDC code.
- * @pio_offset: Offset into the current scatterlist entry.
- * @cur_slot: The slot which is currently using the controller.
- * @mrq: The request currently being processed on @cur_slot,
- * or NULL if the controller is idle.
- * @cmd: The command currently being sent to the card, or NULL.
- * @data: The data currently being transferred, or NULL if no data
- * transfer is in progress.
- * @data_size: just data->blocks * data->blksz.
- * @dma: DMA client state.
- * @data_chan: DMA channel being used for the current data transfer.
- * @cmd_status: Snapshot of SR taken upon completion of the current
- * command. Only valid when EVENT_CMD_COMPLETE is pending.
- * @data_status: Snapshot of SR taken upon completion of the current
- * data transfer. Only valid when EVENT_DATA_COMPLETE or
- * EVENT_DATA_ERROR is pending.
- * @stop_cmdr: Value to be loaded into CMDR when the stop command is
- * to be sent.
- * @tasklet: Tasklet running the request state machine.
- * @pending_events: Bitmask of events flagged by the interrupt handler
- * to be processed by the tasklet.
- * @completed_events: Bitmask of events which the state machine has
- * processed.
- * @state: Tasklet state.
- * @queue: List of slots waiting for access to the controller.
- * @need_clock_update: Update the clock rate before the next request.
- * @need_reset: Reset controller before next request.
- * @mode_reg: Value of the MR register.
- * @cfg_reg: Value of the CFG register.
- * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus
- * rate and timeout calculations.
- * @mapbase: Physical address of the MMIO registers.
- * @mck: The peripheral bus clock hooked up to the MMC controller.
- * @pdev: Platform device associated with the MMC controller.
- * @slot: Slots sharing this MMC controller.
- * @caps: MCI capabilities depending on MCI version.
- * @prepare_data: function to setup MCI before data transfer which
- * depends on MCI capabilities.
- * @submit_data: function to start data transfer which depends on MCI
- * capabilities.
- * @stop_transfer: function to stop data transfer which depends on MCI
- * capabilities.
- *
- * Locking
- * =======
- *
- * @lock is a softirq-safe spinlock protecting @queue as well as
- * @cur_slot, @mrq and @state. These must always be updated
- * at the same time while holding @lock.
- *
- * @lock also protects mode_reg and need_clock_update since these are
- * used to synchronize mode register updates with the queue
- * processing.
- *
- * The @mrq field of struct atmel_mci_slot is also protected by @lock,
- * and must always be written at the same time as the slot is added to
- * @queue.
- *
- * @pending_events and @completed_events are accessed using atomic bit
- * operations, so they don't need any locking.
- *
- * None of the fields touched by the interrupt handler need any
- * locking. However, ordering is important: Before EVENT_DATA_ERROR or
- * EVENT_DATA_COMPLETE is set in @pending_events, all data-related
- * interrupts must be disabled and @data_status updated with a
- * snapshot of SR. Similarly, before EVENT_CMD_COMPLETE is set, the
- * CMDRDY interrupt must be disabled and @cmd_status updated with a
- * snapshot of SR, and before EVENT_XFER_COMPLETE can be set, the
- * bytes_xfered field of @data must be written. This is ensured by
- * using barriers.
- */
-struct atmel_mci {
- spinlock_t lock;
- void __iomem *regs;
-
- struct scatterlist *sg;
- unsigned int pio_offset;
-
- struct atmel_mci_slot *cur_slot;
- struct mmc_request *mrq;
- struct mmc_command *cmd;
- struct mmc_data *data;
- unsigned int data_size;
-
- struct atmel_mci_dma dma;
- struct dma_chan *data_chan;
- struct dma_slave_config dma_conf;
-
- u32 cmd_status;
- u32 data_status;
- u32 stop_cmdr;
-
- struct tasklet_struct tasklet;
- unsigned long pending_events;
- unsigned long completed_events;
- enum atmel_mci_state state;
- struct list_head queue;
-
- bool need_clock_update;
- bool need_reset;
- u32 mode_reg;
- u32 cfg_reg;
- unsigned long bus_hz;
- unsigned long mapbase;
- struct clk *mck;
- struct platform_device *pdev;
-
- struct atmel_mci_slot *slot[ATMCI_MAX_NR_SLOTS];
-
- struct atmel_mci_caps caps;
-
- u32 (*prepare_data)(struct atmel_mci *host, struct mmc_data *data);
- void (*submit_data)(struct atmel_mci *host, struct mmc_data *data);
- void (*stop_transfer)(struct atmel_mci *host);
-};
-
-/**
- * struct atmel_mci_slot - MMC slot state
- * @mmc: The mmc_host representing this slot.
- * @host: The MMC controller this slot is using.
- * @sdc_reg: Value of SDCR to be written before using this slot.
- * @sdio_irq: SDIO irq mask for this slot.
- * @mrq: mmc_request currently being processed or waiting to be
- * processed, or NULL when the slot is idle.
- * @queue_node: List node for placing this node in the @queue list of
- * &struct atmel_mci.
- * @clock: Clock rate configured by set_ios(). Protected by host->lock.
- * @flags: Random state bits associated with the slot.
- * @detect_pin: GPIO pin used for card detection, or negative if not
- * available.
- * @wp_pin: GPIO pin used for card write protect sending, or negative
- * if not available.
- * @detect_is_active_high: The state of the detect pin when it is active.
- * @detect_timer: Timer used for debouncing @detect_pin interrupts.
- */
-struct atmel_mci_slot {
- struct mmc_host *mmc;
- struct atmel_mci *host;
-
- u32 sdc_reg;
- u32 sdio_irq;
-
- struct mmc_request *mrq;
- struct list_head queue_node;
-
- unsigned int clock;
- unsigned long flags;
-#define ATMCI_CARD_PRESENT 0
-#define ATMCI_CARD_NEED_INIT 1
-#define ATMCI_SHUTDOWN 2
-#define ATMCI_SUSPENDED 3
-
- int detect_pin;
- int wp_pin;
- bool detect_is_active_high;
-
- struct timer_list detect_timer;
-};
-
-#define atmci_test_and_clear_pending(host, event) \
- test_and_clear_bit(event, &host->pending_events)
-#define atmci_set_completed(host, event) \
- set_bit(event, &host->completed_events)
-#define atmci_set_pending(host, event) \
- set_bit(event, &host->pending_events)
-
-/*
- * The debugfs stuff below is mostly optimized away when
- * CONFIG_DEBUG_FS is not set.
- */
-static int atmci_req_show(struct seq_file *s, void *v)
-{
- struct atmel_mci_slot *slot = s->private;
- struct mmc_request *mrq;
- struct mmc_command *cmd;
- struct mmc_command *stop;
- struct mmc_data *data;
-
- /* Make sure we get a consistent snapshot */
- spin_lock_bh(&slot->host->lock);
- mrq = slot->mrq;
-
- if (mrq) {
- cmd = mrq->cmd;
- data = mrq->data;
- stop = mrq->stop;
-
- if (cmd)
- seq_printf(s,
- "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
- cmd->opcode, cmd->arg, cmd->flags,
- cmd->resp[0], cmd->resp[1], cmd->resp[2],
- cmd->resp[3], cmd->error);
- if (data)
- seq_printf(s, "DATA %u / %u * %u flg %x err %d\n",
- data->bytes_xfered, data->blocks,
- data->blksz, data->flags, data->error);
- if (stop)
- seq_printf(s,
- "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
- stop->opcode, stop->arg, stop->flags,
- stop->resp[0], stop->resp[1], stop->resp[2],
- stop->resp[3], stop->error);
- }
-
- spin_unlock_bh(&slot->host->lock);
-
- return 0;
-}
-
-static int atmci_req_open(struct inode *inode, struct file *file)
-{
- return single_open(file, atmci_req_show, inode->i_private);
-}
-
-static const struct file_operations atmci_req_fops = {
- .owner = THIS_MODULE,
- .open = atmci_req_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static void atmci_show_status_reg(struct seq_file *s,
- const char *regname, u32 value)
-{
- static const char *sr_bit[] = {
- [0] = "CMDRDY",
- [1] = "RXRDY",
- [2] = "TXRDY",
- [3] = "BLKE",
- [4] = "DTIP",
- [5] = "NOTBUSY",
- [6] = "ENDRX",
- [7] = "ENDTX",
- [8] = "SDIOIRQA",
- [9] = "SDIOIRQB",
- [12] = "SDIOWAIT",
- [14] = "RXBUFF",
- [15] = "TXBUFE",
- [16] = "RINDE",
- [17] = "RDIRE",
- [18] = "RCRCE",
- [19] = "RENDE",
- [20] = "RTOE",
- [21] = "DCRCE",
- [22] = "DTOE",
- [23] = "CSTOE",
- [24] = "BLKOVRE",
- [25] = "DMADONE",
- [26] = "FIFOEMPTY",
- [27] = "XFRDONE",
- [30] = "OVRE",
- [31] = "UNRE",
- };
- unsigned int i;
-
- seq_printf(s, "%s:\t0x%08x", regname, value);
- for (i = 0; i < ARRAY_SIZE(sr_bit); i++) {
- if (value & (1 << i)) {
- if (sr_bit[i])
- seq_printf(s, " %s", sr_bit[i]);
- else
- seq_puts(s, " UNKNOWN");
- }
- }
- seq_putc(s, '\n');
-}
-
-static int atmci_regs_show(struct seq_file *s, void *v)
-{
- struct atmel_mci *host = s->private;
- u32 *buf;
-
- buf = kmalloc(ATMCI_REGS_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- /*
- * Grab a more or less consistent snapshot. Note that we're
- * not disabling interrupts, so IMR and SR may not be
- * consistent.
- */
- spin_lock_bh(&host->lock);
- clk_enable(host->mck);
- memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE);
- clk_disable(host->mck);
- spin_unlock_bh(&host->lock);
-
- seq_printf(s, "MR:\t0x%08x%s%s CLKDIV=%u\n",
- buf[ATMCI_MR / 4],
- buf[ATMCI_MR / 4] & ATMCI_MR_RDPROOF ? " RDPROOF" : "",
- buf[ATMCI_MR / 4] & ATMCI_MR_WRPROOF ? " WRPROOF" : "",
- buf[ATMCI_MR / 4] & 0xff);
- seq_printf(s, "DTOR:\t0x%08x\n", buf[ATMCI_DTOR / 4]);
- seq_printf(s, "SDCR:\t0x%08x\n", buf[ATMCI_SDCR / 4]);
- seq_printf(s, "ARGR:\t0x%08x\n", buf[ATMCI_ARGR / 4]);
- seq_printf(s, "BLKR:\t0x%08x BCNT=%u BLKLEN=%u\n",
- buf[ATMCI_BLKR / 4],
- buf[ATMCI_BLKR / 4] & 0xffff,
- (buf[ATMCI_BLKR / 4] >> 16) & 0xffff);
- if (host->caps.has_cstor_reg)
- seq_printf(s, "CSTOR:\t0x%08x\n", buf[ATMCI_CSTOR / 4]);
-
- /* Don't read RSPR and RDR; it will consume the data there */
-
- atmci_show_status_reg(s, "SR", buf[ATMCI_SR / 4]);
- atmci_show_status_reg(s, "IMR", buf[ATMCI_IMR / 4]);
-
- if (host->caps.has_dma) {
- u32 val;
-
- val = buf[ATMCI_DMA / 4];
- seq_printf(s, "DMA:\t0x%08x OFFSET=%u CHKSIZE=%u%s\n",
- val, val & 3,
- ((val >> 4) & 3) ?
- 1 << (((val >> 4) & 3) + 1) : 1,
- val & ATMCI_DMAEN ? " DMAEN" : "");
- }
- if (host->caps.has_cfg_reg) {
- u32 val;
-
- val = buf[ATMCI_CFG / 4];
- seq_printf(s, "CFG:\t0x%08x%s%s%s%s\n",
- val,
- val & ATMCI_CFG_FIFOMODE_1DATA ? " FIFOMODE_ONE_DATA" : "",
- val & ATMCI_CFG_FERRCTRL_COR ? " FERRCTRL_CLEAR_ON_READ" : "",
- val & ATMCI_CFG_HSMODE ? " HSMODE" : "",
- val & ATMCI_CFG_LSYNC ? " LSYNC" : "");
- }
-
- kfree(buf);
-
- return 0;
-}
-
-static int atmci_regs_open(struct inode *inode, struct file *file)
-{
- return single_open(file, atmci_regs_show, inode->i_private);
-}
-
-static const struct file_operations atmci_regs_fops = {
- .owner = THIS_MODULE,
- .open = atmci_regs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static void atmci_init_debugfs(struct atmel_mci_slot *slot)
-{
- struct mmc_host *mmc = slot->mmc;
- struct atmel_mci *host = slot->host;
- struct dentry *root;
- struct dentry *node;
-
- root = mmc->debugfs_root;
- if (!root)
- return;
-
- node = debugfs_create_file("regs", S_IRUSR, root, host,
- &atmci_regs_fops);
- if (IS_ERR(node))
- return;
- if (!node)
- goto err;
-
- node = debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops);
- if (!node)
- goto err;
-
- node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
- if (!node)
- goto err;
-
- node = debugfs_create_x32("pending_events", S_IRUSR, root,
- (u32 *)&host->pending_events);
- if (!node)
- goto err;
-
- node = debugfs_create_x32("completed_events", S_IRUSR, root,
- (u32 *)&host->completed_events);
- if (!node)
- goto err;
-
- return;
-
-err:
- dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
-}
-
-static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host,
- unsigned int ns)
-{
- /*
- * It is easier here to use us instead of ns for the timeout,
- * it prevents from overflows during calculation.
- */
- unsigned int us = DIV_ROUND_UP(ns, 1000);
-
- /* Maximum clock frequency is host->bus_hz/2 */
- return us * (DIV_ROUND_UP(host->bus_hz, 2000000));
-}
-
-static void atmci_set_timeout(struct atmel_mci *host,
- struct atmel_mci_slot *slot, struct mmc_data *data)
-{
- static unsigned dtomul_to_shift[] = {
- 0, 4, 7, 8, 10, 12, 16, 20
- };
- unsigned timeout;
- unsigned dtocyc;
- unsigned dtomul;
-
- timeout = atmci_ns_to_clocks(host, data->timeout_ns)
- + data->timeout_clks;
-
- for (dtomul = 0; dtomul < 8; dtomul++) {
- unsigned shift = dtomul_to_shift[dtomul];
- dtocyc = (timeout + (1 << shift) - 1) >> shift;
- if (dtocyc < 15)
- break;
- }
-
- if (dtomul >= 8) {
- dtomul = 7;
- dtocyc = 15;
- }
-
- dev_vdbg(&slot->mmc->class_dev, "setting timeout to %u cycles\n",
- dtocyc << dtomul_to_shift[dtomul]);
- atmci_writel(host, ATMCI_DTOR, (ATMCI_DTOMUL(dtomul) | ATMCI_DTOCYC(dtocyc)));
-}
-
-/*
- * Return mask with command flags to be enabled for this command.
- */
-static u32 atmci_prepare_command(struct mmc_host *mmc,
- struct mmc_command *cmd)
-{
- struct mmc_data *data;
- u32 cmdr;
-
- cmd->error = -EINPROGRESS;
-
- cmdr = ATMCI_CMDR_CMDNB(cmd->opcode);
-
- if (cmd->flags & MMC_RSP_PRESENT) {
- if (cmd->flags & MMC_RSP_136)
- cmdr |= ATMCI_CMDR_RSPTYP_136BIT;
- else
- cmdr |= ATMCI_CMDR_RSPTYP_48BIT;
- }
-
- /*
- * This should really be MAXLAT_5 for CMD2 and ACMD41, but
- * it's too difficult to determine whether this is an ACMD or
- * not. Better make it 64.
- */
- cmdr |= ATMCI_CMDR_MAXLAT_64CYC;
-
- if (mmc->ios.bus_mode == MMC_BUSMODE_OPENDRAIN)
- cmdr |= ATMCI_CMDR_OPDCMD;
-
- data = cmd->data;
- if (data) {
- cmdr |= ATMCI_CMDR_START_XFER;
-
- if (cmd->opcode == SD_IO_RW_EXTENDED) {
- cmdr |= ATMCI_CMDR_SDIO_BLOCK;
- } else {
- if (data->flags & MMC_DATA_STREAM)
- cmdr |= ATMCI_CMDR_STREAM;
- else if (data->blocks > 1)
- cmdr |= ATMCI_CMDR_MULTI_BLOCK;
- else
- cmdr |= ATMCI_CMDR_BLOCK;
- }
-
- if (data->flags & MMC_DATA_READ)
- cmdr |= ATMCI_CMDR_TRDIR_READ;
- }
-
- return cmdr;
-}
-
-static void atmci_send_command(struct atmel_mci *host,
- struct mmc_command *cmd, u32 cmd_flags)
-{
- WARN_ON(host->cmd);
- host->cmd = cmd;
-
- dev_vdbg(&host->pdev->dev,
- "start command: ARGR=0x%08x CMDR=0x%08x\n",
- cmd->arg, cmd_flags);
-
- atmci_writel(host, ATMCI_ARGR, cmd->arg);
- atmci_writel(host, ATMCI_CMDR, cmd_flags);
-}
-
-static void atmci_send_stop_cmd(struct atmel_mci *host, struct mmc_data *data)
-{
- atmci_send_command(host, data->stop, host->stop_cmdr);
- atmci_writel(host, ATMCI_IER, ATMCI_CMDRDY);
-}
-
-/*
- * Configure given PDC buffer taking care of alignement issues.
- * Update host->data_size and host->sg.
- */
-static void atmci_pdc_set_single_buf(struct atmel_mci *host,
- enum atmci_xfer_dir dir, enum atmci_pdc_buf buf_nb)
-{
- u32 pointer_reg, counter_reg;
-
- if (dir == XFER_RECEIVE) {
- pointer_reg = ATMEL_PDC_RPR;
- counter_reg = ATMEL_PDC_RCR;
- } else {
- pointer_reg = ATMEL_PDC_TPR;
- counter_reg = ATMEL_PDC_TCR;
- }
-
- if (buf_nb == PDC_SECOND_BUF) {
- pointer_reg += ATMEL_PDC_SCND_BUF_OFF;
- counter_reg += ATMEL_PDC_SCND_BUF_OFF;
- }
-
- atmci_writel(host, pointer_reg, sg_dma_address(host->sg));
- if (host->data_size <= sg_dma_len(host->sg)) {
- if (host->data_size & 0x3) {
- /* If size is different from modulo 4, transfer bytes */
- atmci_writel(host, counter_reg, host->data_size);
- atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCFBYTE);
- } else {
- /* Else transfer 32-bits words */
- atmci_writel(host, counter_reg, host->data_size / 4);
- }
- host->data_size = 0;
- } else {
- /* We assume the size of a page is 32-bits aligned */
- atmci_writel(host, counter_reg, sg_dma_len(host->sg) / 4);
- host->data_size -= sg_dma_len(host->sg);
- if (host->data_size)
- host->sg = sg_next(host->sg);
- }
-}
-
-/*
- * Configure PDC buffer according to the data size ie configuring one or two
- * buffers. Don't use this function if you want to configure only the second
- * buffer. In this case, use atmci_pdc_set_single_buf.
- */
-static void atmci_pdc_set_both_buf(struct atmel_mci *host, int dir)
-{
- atmci_pdc_set_single_buf(host, dir, PDC_FIRST_BUF);
- if (host->data_size)
- atmci_pdc_set_single_buf(host, dir, PDC_SECOND_BUF);
-}
-
-/*
- * Unmap sg lists, called when transfer is finished.
- */
-static void atmci_pdc_cleanup(struct atmel_mci *host)
-{
- struct mmc_data *data = host->data;
-
- if (data)
- dma_unmap_sg(&host->pdev->dev,
- data->sg, data->sg_len,
- ((data->flags & MMC_DATA_WRITE)
- ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
-}
-
-/*
- * Disable PDC transfers. Update pending flags to EVENT_XFER_COMPLETE after
- * having received ATMCI_TXBUFE or ATMCI_RXBUFF interrupt. Enable ATMCI_NOTBUSY
- * interrupt needed for both transfer directions.
- */
-static void atmci_pdc_complete(struct atmel_mci *host)
-{
- atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
- atmci_pdc_cleanup(host);
-
- /*
- * If the card was removed, data will be NULL. No point trying
- * to send the stop command or waiting for NBUSY in this case.
- */
- if (host->data) {
- atmci_set_pending(host, EVENT_XFER_COMPLETE);
- tasklet_schedule(&host->tasklet);
- atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
- }
-}
-
-static void atmci_dma_cleanup(struct atmel_mci *host)
-{
- struct mmc_data *data = host->data;
-
- if (data)
- dma_unmap_sg(host->dma.chan->device->dev,
- data->sg, data->sg_len,
- ((data->flags & MMC_DATA_WRITE)
- ? DMA_TO_DEVICE : DMA_FROM_DEVICE));
-}
-
-/*
- * This function is called by the DMA driver from tasklet context.
- */
-static void atmci_dma_complete(void *arg)
-{
- struct atmel_mci *host = arg;
- struct mmc_data *data = host->data;
-
- dev_vdbg(&host->pdev->dev, "DMA complete\n");
-
- if (host->caps.has_dma)
- /* Disable DMA hardware handshaking on MCI */
- atmci_writel(host, ATMCI_DMA, atmci_readl(host, ATMCI_DMA) & ~ATMCI_DMAEN);
-
- atmci_dma_cleanup(host);
-
- /*
- * If the card was removed, data will be NULL. No point trying
- * to send the stop command or waiting for NBUSY in this case.
- */
- if (data) {
- atmci_set_pending(host, EVENT_XFER_COMPLETE);
- tasklet_schedule(&host->tasklet);
-
- /*
- * Regardless of what the documentation says, we have
- * to wait for NOTBUSY even after block read
- * operations.
- *
- * When the DMA transfer is complete, the controller
- * may still be reading the CRC from the card, i.e.
- * the data transfer is still in progress and we
- * haven't seen all the potential error bits yet.
- *
- * The interrupt handler will schedule a different
- * tasklet to finish things up when the data transfer
- * is completely done.
- *
- * We may not complete the mmc request here anyway
- * because the mmc layer may call back and cause us to
- * violate the "don't submit new operations from the
- * completion callback" rule of the dma engine
- * framework.
- */
- atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
- }
-}
-
-/*
- * Returns a mask of interrupt flags to be enabled after the whole
- * request has been prepared.
- */
-static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data)
-{
- u32 iflags;
-
- data->error = -EINPROGRESS;
-
- host->sg = data->sg;
- host->data = data;
- host->data_chan = NULL;
-
- iflags = ATMCI_DATA_ERROR_FLAGS;
-
- /*
- * Errata: MMC data write operation with less than 12
- * bytes is impossible.
- *
- * Errata: MCI Transmit Data Register (TDR) FIFO
- * corruption when length is not multiple of 4.
- */
- if (data->blocks * data->blksz < 12
- || (data->blocks * data->blksz) & 3)
- host->need_reset = true;
-
- host->pio_offset = 0;
- if (data->flags & MMC_DATA_READ)
- iflags |= ATMCI_RXRDY;
- else
- iflags |= ATMCI_TXRDY;
-
- return iflags;
-}
-
-/*
- * Set interrupt flags and set block length into the MCI mode register even
- * if this value is also accessible in the MCI block register. It seems to be
- * necessary before the High Speed MCI version. It also map sg and configure
- * PDC registers.
- */
-static u32
-atmci_prepare_data_pdc(struct atmel_mci *host, struct mmc_data *data)
-{
- u32 iflags, tmp;
- unsigned int sg_len;
- enum dma_data_direction dir;
-
- data->error = -EINPROGRESS;
-
- host->data = data;
- host->sg = data->sg;
- iflags = ATMCI_DATA_ERROR_FLAGS;
-
- /* Enable pdc mode */
- atmci_writel(host, ATMCI_MR, host->mode_reg | ATMCI_MR_PDCMODE);
-
- if (data->flags & MMC_DATA_READ) {
- dir = DMA_FROM_DEVICE;
- iflags |= ATMCI_ENDRX | ATMCI_RXBUFF;
- } else {
- dir = DMA_TO_DEVICE;
- iflags |= ATMCI_ENDTX | ATMCI_TXBUFE;
- }
-
- /* Set BLKLEN */
- tmp = atmci_readl(host, ATMCI_MR);
- tmp &= 0x0000ffff;
- tmp |= ATMCI_BLKLEN(data->blksz);
- atmci_writel(host, ATMCI_MR, tmp);
-
- /* Configure PDC */
- host->data_size = data->blocks * data->blksz;
- sg_len = dma_map_sg(&host->pdev->dev, data->sg, data->sg_len, dir);
- if (host->data_size)
- atmci_pdc_set_both_buf(host,
- ((dir == DMA_FROM_DEVICE) ? XFER_RECEIVE : XFER_TRANSMIT));
-
- return iflags;
-}
-
-static u32
-atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
-{
- struct dma_chan *chan;
- struct dma_async_tx_descriptor *desc;
- struct scatterlist *sg;
- unsigned int i;
- enum dma_data_direction direction;
- enum dma_transfer_direction slave_dirn;
- unsigned int sglen;
- u32 iflags;
-
- data->error = -EINPROGRESS;
-
- WARN_ON(host->data);
- host->sg = NULL;
- host->data = data;
-
- iflags = ATMCI_DATA_ERROR_FLAGS;
-
- /*
- * We don't do DMA on "complex" transfers, i.e. with
- * non-word-aligned buffers or lengths. Also, we don't bother
- * with all the DMA setup overhead for short transfers.
- */
- if (data->blocks * data->blksz < ATMCI_DMA_THRESHOLD)
- return atmci_prepare_data(host, data);
- if (data->blksz & 3)
- return atmci_prepare_data(host, data);
-
- for_each_sg(data->sg, sg, data->sg_len, i) {
- if (sg->offset & 3 || sg->length & 3)
- return atmci_prepare_data(host, data);
- }
-
- /* If we don't have a channel, we can't do DMA */
- chan = host->dma.chan;
- if (chan)
- host->data_chan = chan;
-
- if (!chan)
- return -ENODEV;
-
- if (host->caps.has_dma)
- atmci_writel(host, ATMCI_DMA, ATMCI_DMA_CHKSIZE(3) | ATMCI_DMAEN);
-
- if (data->flags & MMC_DATA_READ) {
- direction = DMA_FROM_DEVICE;
- host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM;
- } else {
- direction = DMA_TO_DEVICE;
- host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV;
- }
-
- sglen = dma_map_sg(chan->device->dev, data->sg,
- data->sg_len, direction);
-
- dmaengine_slave_config(chan, &host->dma_conf);
- desc = dmaengine_prep_slave_sg(chan,
- data->sg, sglen, slave_dirn,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc)
- goto unmap_exit;
-
- host->dma.data_desc = desc;
- desc->callback = atmci_dma_complete;
- desc->callback_param = host;
-
- return iflags;
-unmap_exit:
- dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, direction);
- return -ENOMEM;
-}
-
-static void
-atmci_submit_data(struct atmel_mci *host, struct mmc_data *data)
-{
- return;
-}
-
-/*
- * Start PDC according to transfer direction.
- */
-static void
-atmci_submit_data_pdc(struct atmel_mci *host, struct mmc_data *data)
-{
- if (data->flags & MMC_DATA_READ)
- atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);
- else
- atmci_writel(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
-}
-
-static void
-atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data)
-{
- struct dma_chan *chan = host->data_chan;
- struct dma_async_tx_descriptor *desc = host->dma.data_desc;
-
- if (chan) {
- dmaengine_submit(desc);
- dma_async_issue_pending(chan);
- }
-}
-
-static void atmci_stop_transfer(struct atmel_mci *host)
-{
- atmci_set_pending(host, EVENT_XFER_COMPLETE);
- atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
-}
-
-/*
- * Stop data transfer because error(s) occured.
- */
-static void atmci_stop_transfer_pdc(struct atmel_mci *host)
-{
- atmci_set_pending(host, EVENT_XFER_COMPLETE);
- atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
-}
-
-static void atmci_stop_transfer_dma(struct atmel_mci *host)
-{
- struct dma_chan *chan = host->data_chan;
-
- if (chan) {
- dmaengine_terminate_all(chan);
- atmci_dma_cleanup(host);
- } else {
- /* Data transfer was stopped by the interrupt handler */
- atmci_set_pending(host, EVENT_XFER_COMPLETE);
- atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
- }
-}
-
-/*
- * Start a request: prepare data if needed, prepare the command and activate
- * interrupts.
- */
-static void atmci_start_request(struct atmel_mci *host,
- struct atmel_mci_slot *slot)
-{
- struct mmc_request *mrq;
- struct mmc_command *cmd;
- struct mmc_data *data;
- u32 iflags;
- u32 cmdflags;
-
- mrq = slot->mrq;
- host->cur_slot = slot;
- host->mrq = mrq;
-
- host->pending_events = 0;
- host->completed_events = 0;
- host->data_status = 0;
-
- if (host->need_reset) {
- iflags = atmci_readl(host, ATMCI_IMR);
- iflags &= (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB);
- atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
- atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN);
- atmci_writel(host, ATMCI_MR, host->mode_reg);
- if (host->caps.has_cfg_reg)
- atmci_writel(host, ATMCI_CFG, host->cfg_reg);
- atmci_writel(host, ATMCI_IER, iflags);
- host->need_reset = false;
- }
- atmci_writel(host, ATMCI_SDCR, slot->sdc_reg);
-
- iflags = atmci_readl(host, ATMCI_IMR);
- if (iflags & ~(ATMCI_SDIOIRQA | ATMCI_SDIOIRQB))
- dev_warn(&slot->mmc->class_dev, "WARNING: IMR=0x%08x\n",
- iflags);
-
- if (unlikely(test_and_clear_bit(ATMCI_CARD_NEED_INIT, &slot->flags))) {
- /* Send init sequence (74 clock cycles) */
- atmci_writel(host, ATMCI_CMDR, ATMCI_CMDR_SPCMD_INIT);
- while (!(atmci_readl(host, ATMCI_SR) & ATMCI_CMDRDY))
- cpu_relax();
- }
- iflags = 0;
- data = mrq->data;
- if (data) {
- atmci_set_timeout(host, slot, data);
-
- /* Must set block count/size before sending command */
- atmci_writel(host, ATMCI_BLKR, ATMCI_BCNT(data->blocks)
- | ATMCI_BLKLEN(data->blksz));
- dev_vdbg(&slot->mmc->class_dev, "BLKR=0x%08x\n",
- ATMCI_BCNT(data->blocks) | ATMCI_BLKLEN(data->blksz));
-
- iflags |= host->prepare_data(host, data);
- }
-
- iflags |= ATMCI_CMDRDY;
- cmd = mrq->cmd;
- cmdflags = atmci_prepare_command(slot->mmc, cmd);
- atmci_send_command(host, cmd, cmdflags);
-
- if (data)
- host->submit_data(host, data);
-
- if (mrq->stop) {
- host->stop_cmdr = atmci_prepare_command(slot->mmc, mrq->stop);
- host->stop_cmdr |= ATMCI_CMDR_STOP_XFER;
- if (!(data->flags & MMC_DATA_WRITE))
- host->stop_cmdr |= ATMCI_CMDR_TRDIR_READ;
- if (data->flags & MMC_DATA_STREAM)
- host->stop_cmdr |= ATMCI_CMDR_STREAM;
- else
- host->stop_cmdr |= ATMCI_CMDR_MULTI_BLOCK;
- }
-
- /*
- * We could have enabled interrupts earlier, but I suspect
- * that would open up a nice can of interesting race
- * conditions (e.g. command and data complete, but stop not
- * prepared yet.)
- */
- atmci_writel(host, ATMCI_IER, iflags);
-}
-
-static void atmci_queue_request(struct atmel_mci *host,
- struct atmel_mci_slot *slot, struct mmc_request *mrq)
-{
- dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
- host->state);
-
- spin_lock_bh(&host->lock);
- slot->mrq = mrq;
- if (host->state == STATE_IDLE) {
- host->state = STATE_SENDING_CMD;
- atmci_start_request(host, slot);
- } else {
- list_add_tail(&slot->queue_node, &host->queue);
- }
- spin_unlock_bh(&host->lock);
-}
-
-static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct atmel_mci_slot *slot = mmc_priv(mmc);
- struct atmel_mci *host = slot->host;
- struct mmc_data *data;
-
- WARN_ON(slot->mrq);
-
- /*
- * We may "know" the card is gone even though there's still an
- * electrical connection. If so, we really need to communicate
- * this to the MMC core since there won't be any more
- * interrupts as the card is completely removed. Otherwise,
- * the MMC core might believe the card is still there even
- * though the card was just removed very slowly.
- */
- if (!test_bit(ATMCI_CARD_PRESENT, &slot->flags)) {
- mrq->cmd->error = -ENOMEDIUM;
- mmc_request_done(mmc, mrq);
- return;
- }
-
- /* We don't support multiple blocks of weird lengths. */
- data = mrq->data;
- if (data && data->blocks > 1 && data->blksz & 3) {
- mrq->cmd->error = -EINVAL;
- mmc_request_done(mmc, mrq);
- }
-
- atmci_queue_request(host, slot, mrq);
-}
-
-static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct atmel_mci_slot *slot = mmc_priv(mmc);
- struct atmel_mci *host = slot->host;
- unsigned int i;
-
- slot->sdc_reg &= ~ATMCI_SDCBUS_MASK;
- switch (ios->bus_width) {
- case MMC_BUS_WIDTH_1:
- slot->sdc_reg |= ATMCI_SDCBUS_1BIT;
- break;
- case MMC_BUS_WIDTH_4:
- slot->sdc_reg |= ATMCI_SDCBUS_4BIT;
- break;
- }
-
- if (ios->clock) {
- unsigned int clock_min = ~0U;
- u32 clkdiv;
-
- spin_lock_bh(&host->lock);
- if (!host->mode_reg) {
- clk_enable(host->mck);
- atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
- atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN);
- if (host->caps.has_cfg_reg)
- atmci_writel(host, ATMCI_CFG, host->cfg_reg);
- }
-
- /*
- * Use mirror of ios->clock to prevent race with mmc
- * core ios update when finding the minimum.
- */
- slot->clock = ios->clock;
- for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
- if (host->slot[i] && host->slot[i]->clock
- && host->slot[i]->clock < clock_min)
- clock_min = host->slot[i]->clock;
- }
-
- /* Calculate clock divider */
- if (host->caps.has_odd_clk_div) {
- clkdiv = DIV_ROUND_UP(host->bus_hz, clock_min) - 2;
- if (clkdiv > 511) {
- dev_warn(&mmc->class_dev,
- "clock %u too slow; using %lu\n",
- clock_min, host->bus_hz / (511 + 2));
- clkdiv = 511;
- }
- host->mode_reg = ATMCI_MR_CLKDIV(clkdiv >> 1)
- | ATMCI_MR_CLKODD(clkdiv & 1);
- } else {
- clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1;
- if (clkdiv > 255) {
- dev_warn(&mmc->class_dev,
- "clock %u too slow; using %lu\n",
- clock_min, host->bus_hz / (2 * 256));
- clkdiv = 255;
- }
- host->mode_reg = ATMCI_MR_CLKDIV(clkdiv);
- }
-
- /*
- * WRPROOF and RDPROOF prevent overruns/underruns by
- * stopping the clock when the FIFO is full/empty.
- * This state is not expected to last for long.
- */
- if (host->caps.has_rwproof)
- host->mode_reg |= (ATMCI_MR_WRPROOF | ATMCI_MR_RDPROOF);
-
- if (host->caps.has_cfg_reg) {
- /* setup High Speed mode in relation with card capacity */
- if (ios->timing == MMC_TIMING_SD_HS)
- host->cfg_reg |= ATMCI_CFG_HSMODE;
- else
- host->cfg_reg &= ~ATMCI_CFG_HSMODE;
- }
-
- if (list_empty(&host->queue)) {
- atmci_writel(host, ATMCI_MR, host->mode_reg);
- if (host->caps.has_cfg_reg)
- atmci_writel(host, ATMCI_CFG, host->cfg_reg);
- } else {
- host->need_clock_update = true;
- }
-
- spin_unlock_bh(&host->lock);
- } else {
- bool any_slot_active = false;
-
- spin_lock_bh(&host->lock);
- slot->clock = 0;
- for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
- if (host->slot[i] && host->slot[i]->clock) {
- any_slot_active = true;
- break;
- }
- }
- if (!any_slot_active) {
- atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS);
- if (host->mode_reg) {
- atmci_readl(host, ATMCI_MR);
- clk_disable(host->mck);
- }
- host->mode_reg = 0;
- }
- spin_unlock_bh(&host->lock);
- }
-
- switch (ios->power_mode) {
- case MMC_POWER_UP:
- set_bit(ATMCI_CARD_NEED_INIT, &slot->flags);
- break;
- default:
- /*
- * TODO: None of the currently available AVR32-based
- * boards allow MMC power to be turned off. Implement
- * power control when this can be tested properly.
- *
- * We also need to hook this into the clock management
- * somehow so that newly inserted cards aren't
- * subjected to a fast clock before we have a chance
- * to figure out what the maximum rate is. Currently,
- * there's no way to avoid this, and there never will
- * be for boards that don't support power control.
- */
- break;
- }
-}
-
-static int atmci_get_ro(struct mmc_host *mmc)
-{
- int read_only = -ENOSYS;
- struct atmel_mci_slot *slot = mmc_priv(mmc);
-
- if (gpio_is_valid(slot->wp_pin)) {
- read_only = gpio_get_value(slot->wp_pin);
- dev_dbg(&mmc->class_dev, "card is %s\n",
- read_only ? "read-only" : "read-write");
- }
-
- return read_only;
-}
-
-static int atmci_get_cd(struct mmc_host *mmc)
-{
- int present = -ENOSYS;
- struct atmel_mci_slot *slot = mmc_priv(mmc);
-
- if (gpio_is_valid(slot->detect_pin)) {
- present = !(gpio_get_value(slot->detect_pin) ^
- slot->detect_is_active_high);
- dev_dbg(&mmc->class_dev, "card is %spresent\n",
- present ? "" : "not ");
- }
-
- return present;
-}
-
-static void atmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
- struct atmel_mci_slot *slot = mmc_priv(mmc);
- struct atmel_mci *host = slot->host;
-
- if (enable)
- atmci_writel(host, ATMCI_IER, slot->sdio_irq);
- else
- atmci_writel(host, ATMCI_IDR, slot->sdio_irq);
-}
-
-static const struct mmc_host_ops atmci_ops = {
- .request = atmci_request,
- .set_ios = atmci_set_ios,
- .get_ro = atmci_get_ro,
- .get_cd = atmci_get_cd,
- .enable_sdio_irq = atmci_enable_sdio_irq,
-};
-
-/* Called with host->lock held */
-static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
- __releases(&host->lock)
- __acquires(&host->lock)
-{
- struct atmel_mci_slot *slot = NULL;
- struct mmc_host *prev_mmc = host->cur_slot->mmc;
-
- WARN_ON(host->cmd || host->data);
-
- /*
- * Update the MMC clock rate if necessary. This may be
- * necessary if set_ios() is called when a different slot is
- * busy transferring data.
- */
- if (host->need_clock_update) {
- atmci_writel(host, ATMCI_MR, host->mode_reg);
- if (host->caps.has_cfg_reg)
- atmci_writel(host, ATMCI_CFG, host->cfg_reg);
- }
-
- host->cur_slot->mrq = NULL;
- host->mrq = NULL;
- if (!list_empty(&host->queue)) {
- slot = list_entry(host->queue.next,
- struct atmel_mci_slot, queue_node);
- list_del(&slot->queue_node);
- dev_vdbg(&host->pdev->dev, "list not empty: %s is next\n",
- mmc_hostname(slot->mmc));
- host->state = STATE_SENDING_CMD;
- atmci_start_request(host, slot);
- } else {
- dev_vdbg(&host->pdev->dev, "list empty\n");
- host->state = STATE_IDLE;
- }
-
- spin_unlock(&host->lock);
- mmc_request_done(prev_mmc, mrq);
- spin_lock(&host->lock);
-}
-
-static void atmci_command_complete(struct atmel_mci *host,
- struct mmc_command *cmd)
-{
- u32 status = host->cmd_status;
-
- /* Read the response from the card (up to 16 bytes) */
- cmd->resp[0] = atmci_readl(host, ATMCI_RSPR);
- cmd->resp[1] = atmci_readl(host, ATMCI_RSPR);
- cmd->resp[2] = atmci_readl(host, ATMCI_RSPR);
- cmd->resp[3] = atmci_readl(host, ATMCI_RSPR);
-
- if (status & ATMCI_RTOE)
- cmd->error = -ETIMEDOUT;
- else if ((cmd->flags & MMC_RSP_CRC) && (status & ATMCI_RCRCE))
- cmd->error = -EILSEQ;
- else if (status & (ATMCI_RINDE | ATMCI_RDIRE | ATMCI_RENDE))
- cmd->error = -EIO;
- else
- cmd->error = 0;
-
- if (cmd->error) {
- dev_dbg(&host->pdev->dev,
- "command error: status=0x%08x\n", status);
-
- if (cmd->data) {
- host->stop_transfer(host);
- host->data = NULL;
- atmci_writel(host, ATMCI_IDR, ATMCI_NOTBUSY
- | ATMCI_TXRDY | ATMCI_RXRDY
- | ATMCI_DATA_ERROR_FLAGS);
- }
- }
-}
-
-static void atmci_detect_change(unsigned long data)
-{
- struct atmel_mci_slot *slot = (struct atmel_mci_slot *)data;
- bool present;
- bool present_old;
-
- /*
- * atmci_cleanup_slot() sets the ATMCI_SHUTDOWN flag before
- * freeing the interrupt. We must not re-enable the interrupt
- * if it has been freed, and if we're shutting down, it
- * doesn't really matter whether the card is present or not.
- */
- smp_rmb();
- if (test_bit(ATMCI_SHUTDOWN, &slot->flags))
- return;
-
- enable_irq(gpio_to_irq(slot->detect_pin));
- present = !(gpio_get_value(slot->detect_pin) ^
- slot->detect_is_active_high);
- present_old = test_bit(ATMCI_CARD_PRESENT, &slot->flags);
-
- dev_vdbg(&slot->mmc->class_dev, "detect change: %d (was %d)\n",
- present, present_old);
-
- if (present != present_old) {
- struct atmel_mci *host = slot->host;
- struct mmc_request *mrq;
-
- dev_dbg(&slot->mmc->class_dev, "card %s\n",
- present ? "inserted" : "removed");
-
- spin_lock(&host->lock);
-
- if (!present)
- clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
- else
- set_bit(ATMCI_CARD_PRESENT, &slot->flags);
-
- /* Clean up queue if present */
- mrq = slot->mrq;
- if (mrq) {
- if (mrq == host->mrq) {
- /*
- * Reset controller to terminate any ongoing
- * commands or data transfers.
- */
- atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
- atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN);
- atmci_writel(host, ATMCI_MR, host->mode_reg);
- if (host->caps.has_cfg_reg)
- atmci_writel(host, ATMCI_CFG, host->cfg_reg);
-
- host->data = NULL;
- host->cmd = NULL;
-
- switch (host->state) {
- case STATE_IDLE:
- break;
- case STATE_SENDING_CMD:
- mrq->cmd->error = -ENOMEDIUM;
- if (!mrq->data)
- break;
- /* fall through */
- case STATE_SENDING_DATA:
- mrq->data->error = -ENOMEDIUM;
- host->stop_transfer(host);
- break;
- case STATE_DATA_BUSY:
- case STATE_DATA_ERROR:
- if (mrq->data->error == -EINPROGRESS)
- mrq->data->error = -ENOMEDIUM;
- if (!mrq->stop)
- break;
- /* fall through */
- case STATE_SENDING_STOP:
- mrq->stop->error = -ENOMEDIUM;
- break;
- }
-
- atmci_request_end(host, mrq);
- } else {
- list_del(&slot->queue_node);
- mrq->cmd->error = -ENOMEDIUM;
- if (mrq->data)
- mrq->data->error = -ENOMEDIUM;
- if (mrq->stop)
- mrq->stop->error = -ENOMEDIUM;
-
- spin_unlock(&host->lock);
- mmc_request_done(slot->mmc, mrq);
- spin_lock(&host->lock);
- }
- }
- spin_unlock(&host->lock);
-
- mmc_detect_change(slot->mmc, 0);
- }
-}
-
-static void atmci_tasklet_func(unsigned long priv)
-{
- struct atmel_mci *host = (struct atmel_mci *)priv;
- struct mmc_request *mrq = host->mrq;
- struct mmc_data *data = host->data;
- struct mmc_command *cmd = host->cmd;
- enum atmel_mci_state state = host->state;
- enum atmel_mci_state prev_state;
- u32 status;
-
- spin_lock(&host->lock);
-
- state = host->state;
-
- dev_vdbg(&host->pdev->dev,
- "tasklet: state %u pending/completed/mask %lx/%lx/%x\n",
- state, host->pending_events, host->completed_events,
- atmci_readl(host, ATMCI_IMR));
-
- do {
- prev_state = state;
-
- switch (state) {
- case STATE_IDLE:
- break;
-
- case STATE_SENDING_CMD:
- if (!atmci_test_and_clear_pending(host,
- EVENT_CMD_COMPLETE))
- break;
-
- host->cmd = NULL;
- atmci_set_completed(host, EVENT_CMD_COMPLETE);
- atmci_command_complete(host, mrq->cmd);
- if (!mrq->data || cmd->error) {
- atmci_request_end(host, host->mrq);
- goto unlock;
- }
-
- prev_state = state = STATE_SENDING_DATA;
- /* fall through */
-
- case STATE_SENDING_DATA:
- if (atmci_test_and_clear_pending(host,
- EVENT_DATA_ERROR)) {
- host->stop_transfer(host);
- if (data->stop)
- atmci_send_stop_cmd(host, data);
- state = STATE_DATA_ERROR;
- break;
- }
-
- if (!atmci_test_and_clear_pending(host,
- EVENT_XFER_COMPLETE))
- break;
-
- atmci_set_completed(host, EVENT_XFER_COMPLETE);
- prev_state = state = STATE_DATA_BUSY;
- /* fall through */
-
- case STATE_DATA_BUSY:
- if (!atmci_test_and_clear_pending(host,
- EVENT_DATA_COMPLETE))
- break;
-
- host->data = NULL;
- atmci_set_completed(host, EVENT_DATA_COMPLETE);
- status = host->data_status;
- if (unlikely(status & ATMCI_DATA_ERROR_FLAGS)) {
- if (status & ATMCI_DTOE) {
- dev_dbg(&host->pdev->dev,
- "data timeout error\n");
- data->error = -ETIMEDOUT;
- } else if (status & ATMCI_DCRCE) {
- dev_dbg(&host->pdev->dev,
- "data CRC error\n");
- data->error = -EILSEQ;
- } else {
- dev_dbg(&host->pdev->dev,
- "data FIFO error (status=%08x)\n",
- status);
- data->error = -EIO;
- }
- } else {
- data->bytes_xfered = data->blocks * data->blksz;
- data->error = 0;
- atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS);
- }
-
- if (!data->stop) {
- atmci_request_end(host, host->mrq);
- goto unlock;
- }
-
- prev_state = state = STATE_SENDING_STOP;
- if (!data->error)
- atmci_send_stop_cmd(host, data);
- /* fall through */
-
- case STATE_SENDING_STOP:
- if (!atmci_test_and_clear_pending(host,
- EVENT_CMD_COMPLETE))
- break;
-
- host->cmd = NULL;
- atmci_command_complete(host, mrq->stop);
- atmci_request_end(host, host->mrq);
- goto unlock;
-
- case STATE_DATA_ERROR:
- if (!atmci_test_and_clear_pending(host,
- EVENT_XFER_COMPLETE))
- break;
-
- state = STATE_DATA_BUSY;
- break;
- }
- } while (state != prev_state);
-
- host->state = state;
-
-unlock:
- spin_unlock(&host->lock);
-}
-
-static void atmci_read_data_pio(struct atmel_mci *host)
-{
- struct scatterlist *sg = host->sg;
- void *buf = sg_virt(sg);
- unsigned int offset = host->pio_offset;
- struct mmc_data *data = host->data;
- u32 value;
- u32 status;
- unsigned int nbytes = 0;
-
- do {
- value = atmci_readl(host, ATMCI_RDR);
- if (likely(offset + 4 <= sg->length)) {
- put_unaligned(value, (u32 *)(buf + offset));
-
- offset += 4;
- nbytes += 4;
-
- if (offset == sg->length) {
- flush_dcache_page(sg_page(sg));
- host->sg = sg = sg_next(sg);
- if (!sg)
- goto done;
-
- offset = 0;
- buf = sg_virt(sg);
- }
- } else {
- unsigned int remaining = sg->length - offset;
- memcpy(buf + offset, &value, remaining);
- nbytes += remaining;
-
- flush_dcache_page(sg_page(sg));
- host->sg = sg = sg_next(sg);
- if (!sg)
- goto done;
-
- offset = 4 - remaining;
- buf = sg_virt(sg);
- memcpy(buf, (u8 *)&value + remaining, offset);
- nbytes += offset;
- }
-
- status = atmci_readl(host, ATMCI_SR);
- if (status & ATMCI_DATA_ERROR_FLAGS) {
- atmci_writel(host, ATMCI_IDR, (ATMCI_NOTBUSY | ATMCI_RXRDY
- | ATMCI_DATA_ERROR_FLAGS));
- host->data_status = status;
- data->bytes_xfered += nbytes;
- smp_wmb();
- atmci_set_pending(host, EVENT_DATA_ERROR);
- tasklet_schedule(&host->tasklet);
- return;
- }
- } while (status & ATMCI_RXRDY);
-
- host->pio_offset = offset;
- data->bytes_xfered += nbytes;
-
- return;
-
-done:
- atmci_writel(host, ATMCI_IDR, ATMCI_RXRDY);
- atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
- data->bytes_xfered += nbytes;
- smp_wmb();
- atmci_set_pending(host, EVENT_XFER_COMPLETE);
-}
-
-static void atmci_write_data_pio(struct atmel_mci *host)
-{
- struct scatterlist *sg = host->sg;
- void *buf = sg_virt(sg);
- unsigned int offset = host->pio_offset;
- struct mmc_data *data = host->data;
- u32 value;
- u32 status;
- unsigned int nbytes = 0;
-
- do {
- if (likely(offset + 4 <= sg->length)) {
- value = get_unaligned((u32 *)(buf + offset));
- atmci_writel(host, ATMCI_TDR, value);
-
- offset += 4;
- nbytes += 4;
- if (offset == sg->length) {
- host->sg = sg = sg_next(sg);
- if (!sg)
- goto done;
-
- offset = 0;
- buf = sg_virt(sg);
- }
- } else {
- unsigned int remaining = sg->length - offset;
-
- value = 0;
- memcpy(&value, buf + offset, remaining);
- nbytes += remaining;
-
- host->sg = sg = sg_next(sg);
- if (!sg) {
- atmci_writel(host, ATMCI_TDR, value);
- goto done;
- }
-
- offset = 4 - remaining;
- buf = sg_virt(sg);
- memcpy((u8 *)&value + remaining, buf, offset);
- atmci_writel(host, ATMCI_TDR, value);
- nbytes += offset;
- }
-
- status = atmci_readl(host, ATMCI_SR);
- if (status & ATMCI_DATA_ERROR_FLAGS) {
- atmci_writel(host, ATMCI_IDR, (ATMCI_NOTBUSY | ATMCI_TXRDY
- | ATMCI_DATA_ERROR_FLAGS));
- host->data_status = status;
- data->bytes_xfered += nbytes;
- smp_wmb();
- atmci_set_pending(host, EVENT_DATA_ERROR);
- tasklet_schedule(&host->tasklet);
- return;
- }
- } while (status & ATMCI_TXRDY);
-
- host->pio_offset = offset;
- data->bytes_xfered += nbytes;
-
- return;
-
-done:
- atmci_writel(host, ATMCI_IDR, ATMCI_TXRDY);
- atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
- data->bytes_xfered += nbytes;
- smp_wmb();
- atmci_set_pending(host, EVENT_XFER_COMPLETE);
-}
-
-static void atmci_cmd_interrupt(struct atmel_mci *host, u32 status)
-{
- atmci_writel(host, ATMCI_IDR, ATMCI_CMDRDY);
-
- host->cmd_status = status;
- smp_wmb();
- atmci_set_pending(host, EVENT_CMD_COMPLETE);
- tasklet_schedule(&host->tasklet);
-}
-
-static void atmci_sdio_interrupt(struct atmel_mci *host, u32 status)
-{
- int i;
-
- for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
- struct atmel_mci_slot *slot = host->slot[i];
- if (slot && (status & slot->sdio_irq)) {
- mmc_signal_sdio_irq(slot->mmc);
- }
- }
-}
-
-
-static irqreturn_t atmci_interrupt(int irq, void *dev_id)
-{
- struct atmel_mci *host = dev_id;
- u32 status, mask, pending;
- unsigned int pass_count = 0;
-
- do {
- status = atmci_readl(host, ATMCI_SR);
- mask = atmci_readl(host, ATMCI_IMR);
- pending = status & mask;
- if (!pending)
- break;
-
- if (pending & ATMCI_DATA_ERROR_FLAGS) {
- atmci_writel(host, ATMCI_IDR, ATMCI_DATA_ERROR_FLAGS
- | ATMCI_RXRDY | ATMCI_TXRDY);
- pending &= atmci_readl(host, ATMCI_IMR);
-
- host->data_status = status;
- smp_wmb();
- atmci_set_pending(host, EVENT_DATA_ERROR);
- tasklet_schedule(&host->tasklet);
- }
-
- if (pending & ATMCI_TXBUFE) {
- atmci_writel(host, ATMCI_IDR, ATMCI_TXBUFE);
- atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX);
- /*
- * We can receive this interruption before having configured
- * the second pdc buffer, so we need to reconfigure first and
- * second buffers again
- */
- if (host->data_size) {
- atmci_pdc_set_both_buf(host, XFER_TRANSMIT);
- atmci_writel(host, ATMCI_IER, ATMCI_ENDTX);
- atmci_writel(host, ATMCI_IER, ATMCI_TXBUFE);
- } else {
- atmci_pdc_complete(host);
- }
- } else if (pending & ATMCI_ENDTX) {
- atmci_writel(host, ATMCI_IDR, ATMCI_ENDTX);
-
- if (host->data_size) {
- atmci_pdc_set_single_buf(host,
- XFER_TRANSMIT, PDC_SECOND_BUF);
- atmci_writel(host, ATMCI_IER, ATMCI_ENDTX);
- }
- }
-
- if (pending & ATMCI_RXBUFF) {
- atmci_writel(host, ATMCI_IDR, ATMCI_RXBUFF);
- atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX);
- /*
- * We can receive this interruption before having configured
- * the second pdc buffer, so we need to reconfigure first and
- * second buffers again
- */
- if (host->data_size) {
- atmci_pdc_set_both_buf(host, XFER_RECEIVE);
- atmci_writel(host, ATMCI_IER, ATMCI_ENDRX);
- atmci_writel(host, ATMCI_IER, ATMCI_RXBUFF);
- } else {
- atmci_pdc_complete(host);
- }
- } else if (pending & ATMCI_ENDRX) {
- atmci_writel(host, ATMCI_IDR, ATMCI_ENDRX);
-
- if (host->data_size) {
- atmci_pdc_set_single_buf(host,
- XFER_RECEIVE, PDC_SECOND_BUF);
- atmci_writel(host, ATMCI_IER, ATMCI_ENDRX);
- }
- }
-
-
- if (pending & ATMCI_NOTBUSY) {
- atmci_writel(host, ATMCI_IDR,
- ATMCI_DATA_ERROR_FLAGS | ATMCI_NOTBUSY);
- if (!host->data_status)
- host->data_status = status;
- smp_wmb();
- atmci_set_pending(host, EVENT_DATA_COMPLETE);
- tasklet_schedule(&host->tasklet);
- }
- if (pending & ATMCI_RXRDY)
- atmci_read_data_pio(host);
- if (pending & ATMCI_TXRDY)
- atmci_write_data_pio(host);
-
- if (pending & ATMCI_CMDRDY)
- atmci_cmd_interrupt(host, status);
-
- if (pending & (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB))
- atmci_sdio_interrupt(host, status);
-
- } while (pass_count++ < 5);
-
- return pass_count ? IRQ_HANDLED : IRQ_NONE;
-}
-
-static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
-{
- struct atmel_mci_slot *slot = dev_id;
-
- /*
- * Disable interrupts until the pin has stabilized and check
- * the state then. Use mod_timer() since we may be in the
- * middle of the timer routine when this interrupt triggers.
- */
- disable_irq_nosync(irq);
- mod_timer(&slot->detect_timer, jiffies + msecs_to_jiffies(20));
-
- return IRQ_HANDLED;
-}
-
-static int __init atmci_init_slot(struct atmel_mci *host,
- struct mci_slot_pdata *slot_data, unsigned int id,
- u32 sdc_reg, u32 sdio_irq)
-{
- struct mmc_host *mmc;
- struct atmel_mci_slot *slot;
-
- mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev);
- if (!mmc)
- return -ENOMEM;
-
- slot = mmc_priv(mmc);
- slot->mmc = mmc;
- slot->host = host;
- slot->detect_pin = slot_data->detect_pin;
- slot->wp_pin = slot_data->wp_pin;
- slot->detect_is_active_high = slot_data->detect_is_active_high;
- slot->sdc_reg = sdc_reg;
- slot->sdio_irq = sdio_irq;
-
- mmc->ops = &atmci_ops;
- mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
- mmc->f_max = host->bus_hz / 2;
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- if (sdio_irq)
- mmc->caps |= MMC_CAP_SDIO_IRQ;
- if (host->caps.has_highspeed)
- mmc->caps |= MMC_CAP_SD_HIGHSPEED;
- if (slot_data->bus_width >= 4)
- mmc->caps |= MMC_CAP_4_BIT_DATA;
-
- mmc->max_segs = 64;
- mmc->max_req_size = 32768 * 512;
- mmc->max_blk_size = 32768;
- mmc->max_blk_count = 512;
-
- /* Assume card is present initially */
- set_bit(ATMCI_CARD_PRESENT, &slot->flags);
- if (gpio_is_valid(slot->detect_pin)) {
- if (gpio_request(slot->detect_pin, "mmc_detect")) {
- dev_dbg(&mmc->class_dev, "no detect pin available\n");
- slot->detect_pin = -EBUSY;
- } else if (gpio_get_value(slot->detect_pin) ^
- slot->detect_is_active_high) {
- clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
- }
- }
-
- if (!gpio_is_valid(slot->detect_pin))
- mmc->caps |= MMC_CAP_NEEDS_POLL;
-
- if (gpio_is_valid(slot->wp_pin)) {
- if (gpio_request(slot->wp_pin, "mmc_wp")) {
- dev_dbg(&mmc->class_dev, "no WP pin available\n");
- slot->wp_pin = -EBUSY;
- }
- }
-
- host->slot[id] = slot;
- mmc_add_host(mmc);
-
- if (gpio_is_valid(slot->detect_pin)) {
- int ret;
-
- setup_timer(&slot->detect_timer, atmci_detect_change,
- (unsigned long)slot);
-
- ret = request_irq(gpio_to_irq(slot->detect_pin),
- atmci_detect_interrupt,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- "mmc-detect", slot);
- if (ret) {
- dev_dbg(&mmc->class_dev,
- "could not request IRQ %d for detect pin\n",
- gpio_to_irq(slot->detect_pin));
- gpio_free(slot->detect_pin);
- slot->detect_pin = -EBUSY;
- }
- }
-
- atmci_init_debugfs(slot);
-
- return 0;
-}
-
-static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot,
- unsigned int id)
-{
- /* Debugfs stuff is cleaned up by mmc core */
-
- set_bit(ATMCI_SHUTDOWN, &slot->flags);
- smp_wmb();
-
- mmc_remove_host(slot->mmc);
-
- if (gpio_is_valid(slot->detect_pin)) {
- int pin = slot->detect_pin;
-
- free_irq(gpio_to_irq(pin), slot);
- del_timer_sync(&slot->detect_timer);
- gpio_free(pin);
- }
- if (gpio_is_valid(slot->wp_pin))
- gpio_free(slot->wp_pin);
-
- slot->host->slot[id] = NULL;
- mmc_free_host(slot->mmc);
-}
-
-static bool atmci_filter(struct dma_chan *chan, void *slave)
-{
- struct mci_dma_data *sl = slave;
-
- if (sl && find_slave_dev(sl) == chan->device->dev) {
- chan->private = slave_data_ptr(sl);
- return true;
- } else {
- return false;
- }
-}
-
-static bool atmci_configure_dma(struct atmel_mci *host)
-{
- struct mci_platform_data *pdata;
-
- if (host == NULL)
- return false;
-
- pdata = host->pdev->dev.platform_data;
-
- if (pdata && find_slave_dev(pdata->dma_slave)) {
- dma_cap_mask_t mask;
-
- /* Try to grab a DMA channel */
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- host->dma.chan =
- dma_request_channel(mask, atmci_filter, pdata->dma_slave);
- }
- if (!host->dma.chan) {
- dev_warn(&host->pdev->dev, "no DMA channel available\n");
- return false;
- } else {
- dev_info(&host->pdev->dev,
- "using %s for DMA transfers\n",
- dma_chan_name(host->dma.chan));
-
- host->dma_conf.src_addr = host->mapbase + ATMCI_RDR;
- host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- host->dma_conf.src_maxburst = 1;
- host->dma_conf.dst_addr = host->mapbase + ATMCI_TDR;
- host->dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- host->dma_conf.dst_maxburst = 1;
- host->dma_conf.device_fc = false;
- return true;
- }
-}
-
-static inline unsigned int atmci_get_version(struct atmel_mci *host)
-{
- return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
-}
-
-/*
- * HSMCI (High Speed MCI) module is not fully compatible with MCI module.
- * HSMCI provides DMA support and a new config register but no more supports
- * PDC.
- */
-static void __init atmci_get_cap(struct atmel_mci *host)
-{
- unsigned int version;
-
- version = atmci_get_version(host);
- dev_info(&host->pdev->dev,
- "version: 0x%x\n", version);
-
- host->caps.has_dma = 0;
- host->caps.has_pdc = 1;
- host->caps.has_cfg_reg = 0;
- host->caps.has_cstor_reg = 0;
- host->caps.has_highspeed = 0;
- host->caps.has_rwproof = 0;
- host->caps.has_odd_clk_div = 0;
-
- /* keep only major version number */
- switch (version & 0xf00) {
- case 0x500:
- host->caps.has_odd_clk_div = 1;
- case 0x400:
- case 0x300:
-#ifdef CONFIG_AT_HDMAC
- host->caps.has_dma = 1;
-#else
- dev_info(&host->pdev->dev,
- "has dma capability but dma engine is not selected, then use pio\n");
-#endif
- host->caps.has_pdc = 0;
- host->caps.has_cfg_reg = 1;
- host->caps.has_cstor_reg = 1;
- host->caps.has_highspeed = 1;
- case 0x200:
- host->caps.has_rwproof = 1;
- case 0x100:
- break;
- default:
- host->caps.has_pdc = 0;
- dev_warn(&host->pdev->dev,
- "Unmanaged mci version, set minimum capabilities\n");
- break;
- }
-}
-
-static int __init atmci_probe(struct platform_device *pdev)
-{
- struct mci_platform_data *pdata;
- struct atmel_mci *host;
- struct resource *regs;
- unsigned int nr_slots;
- int irq;
- int ret;
-
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!regs)
- return -ENXIO;
- pdata = pdev->dev.platform_data;
- if (!pdata)
- return -ENXIO;
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
- host = kzalloc(sizeof(struct atmel_mci), GFP_KERNEL);
- if (!host)
- return -ENOMEM;
-
- host->pdev = pdev;
- spin_lock_init(&host->lock);
- INIT_LIST_HEAD(&host->queue);
-
- host->mck = clk_get(&pdev->dev, "mci_clk");
- if (IS_ERR(host->mck)) {
- ret = PTR_ERR(host->mck);
- goto err_clk_get;
- }
-
- ret = -ENOMEM;
- host->regs = ioremap(regs->start, resource_size(regs));
- if (!host->regs)
- goto err_ioremap;
-
- clk_enable(host->mck);
- atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
- host->bus_hz = clk_get_rate(host->mck);
- clk_disable(host->mck);
-
- host->mapbase = regs->start;
-
- tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host);
-
- ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host);
- if (ret)
- goto err_request_irq;
-
- /* Get MCI capabilities and set operations according to it */
- atmci_get_cap(host);
- if (host->caps.has_dma && atmci_configure_dma(host)) {
- host->prepare_data = &atmci_prepare_data_dma;
- host->submit_data = &atmci_submit_data_dma;
- host->stop_transfer = &atmci_stop_transfer_dma;
- } else if (host->caps.has_pdc) {
- dev_info(&pdev->dev, "using PDC\n");
- host->prepare_data = &atmci_prepare_data_pdc;
- host->submit_data = &atmci_submit_data_pdc;
- host->stop_transfer = &atmci_stop_transfer_pdc;
- } else {
- dev_info(&pdev->dev, "using PIO\n");
- host->prepare_data = &atmci_prepare_data;
- host->submit_data = &atmci_submit_data;
- host->stop_transfer = &atmci_stop_transfer;
- }
-
- platform_set_drvdata(pdev, host);
-
- /* We need at least one slot to succeed */
- nr_slots = 0;
- ret = -ENODEV;
- if (pdata->slot[0].bus_width) {
- ret = atmci_init_slot(host, &pdata->slot[0],
- 0, ATMCI_SDCSEL_SLOT_A, ATMCI_SDIOIRQA);
- if (!ret)
- nr_slots++;
- }
- if (pdata->slot[1].bus_width) {
- ret = atmci_init_slot(host, &pdata->slot[1],
- 1, ATMCI_SDCSEL_SLOT_B, ATMCI_SDIOIRQB);
- if (!ret)
- nr_slots++;
- }
-
- if (!nr_slots) {
- dev_err(&pdev->dev, "init failed: no slot defined\n");
- goto err_init_slot;
- }
-
- dev_info(&pdev->dev,
- "Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
- host->mapbase, irq, nr_slots);
-
- return 0;
-
-err_init_slot:
- if (host->dma.chan)
- dma_release_channel(host->dma.chan);
- free_irq(irq, host);
-err_request_irq:
- iounmap(host->regs);
-err_ioremap:
- clk_put(host->mck);
-err_clk_get:
- kfree(host);
- return ret;
-}
-
-static int __exit atmci_remove(struct platform_device *pdev)
-{
- struct atmel_mci *host = platform_get_drvdata(pdev);
- unsigned int i;
-
- platform_set_drvdata(pdev, NULL);
-
- for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
- if (host->slot[i])
- atmci_cleanup_slot(host->slot[i], i);
- }
-
- clk_enable(host->mck);
- atmci_writel(host, ATMCI_IDR, ~0UL);
- atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS);
- atmci_readl(host, ATMCI_SR);
- clk_disable(host->mck);
-
-#ifdef CONFIG_MMC_ATMELMCI_DMA
- if (host->dma.chan)
- dma_release_channel(host->dma.chan);
-#endif
-
- free_irq(platform_get_irq(pdev, 0), host);
- iounmap(host->regs);
-
- clk_put(host->mck);
- kfree(host);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int atmci_suspend(struct device *dev)
-{
- struct atmel_mci *host = dev_get_drvdata(dev);
- int i;
-
- for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
- struct atmel_mci_slot *slot = host->slot[i];
- int ret;
-
- if (!slot)
- continue;
- ret = mmc_suspend_host(slot->mmc);
- if (ret < 0) {
- while (--i >= 0) {
- slot = host->slot[i];
- if (slot
- && test_bit(ATMCI_SUSPENDED, &slot->flags)) {
- mmc_resume_host(host->slot[i]->mmc);
- clear_bit(ATMCI_SUSPENDED, &slot->flags);
- }
- }
- return ret;
- } else {
- set_bit(ATMCI_SUSPENDED, &slot->flags);
- }
- }
-
- return 0;
-}
-
-static int atmci_resume(struct device *dev)
-{
- struct atmel_mci *host = dev_get_drvdata(dev);
- int i;
- int ret = 0;
-
- for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
- struct atmel_mci_slot *slot = host->slot[i];
- int err;
-
- slot = host->slot[i];
- if (!slot)
- continue;
- if (!test_bit(ATMCI_SUSPENDED, &slot->flags))
- continue;
- err = mmc_resume_host(slot->mmc);
- if (err < 0)
- ret = err;
- else
- clear_bit(ATMCI_SUSPENDED, &slot->flags);
- }
-
- return ret;
-}
-static SIMPLE_DEV_PM_OPS(atmci_pm, atmci_suspend, atmci_resume);
-#define ATMCI_PM_OPS (&atmci_pm)
-#else
-#define ATMCI_PM_OPS NULL
-#endif
-
-static struct platform_driver atmci_driver = {
- .remove = __exit_p(atmci_remove),
- .driver = {
- .name = "atmel_mci",
- .pm = ATMCI_PM_OPS,
- },
-};
-
-static int __init atmci_init(void)
-{
- return platform_driver_probe(&atmci_driver, atmci_probe);
-}
-
-static void __exit atmci_exit(void)
-{
- platform_driver_unregister(&atmci_driver);
-}
-
-late_initcall(atmci_init); /* try to load after dma driver when built-in */
-module_exit(atmci_exit);
-
-MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver");
-MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
-MODULE_LICENSE("GPL v2");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/au1xmmc.c b/ANDROID_3.4.5/drivers/mmc/host/au1xmmc.c
deleted file mode 100644
index dbd0c8a4..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/au1xmmc.c
+++ /dev/null
@@ -1,1228 +0,0 @@
-/*
- * linux/drivers/mmc/host/au1xmmc.c - AU1XX0 MMC driver
- *
- * Copyright (c) 2005, Advanced Micro Devices, Inc.
- *
- * Developed with help from the 2.4.30 MMC AU1XXX controller including
- * the following copyright notices:
- * Copyright (c) 2003-2004 Embedded Edge, LLC.
- * Portions Copyright (C) 2002 Embedix, Inc
- * Copyright 2002 Hewlett-Packard Company
-
- * 2.6 version of this driver inspired by:
- * (drivers/mmc/wbsd.c) Copyright (C) 2004-2005 Pierre Ossman,
- * All Rights Reserved.
- * (drivers/mmc/pxa.c) Copyright (C) 2003 Russell King,
- * All Rights Reserved.
- *
-
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/* Why don't we use the SD controllers' carddetect feature?
- *
- * From the AU1100 MMC application guide:
- * If the Au1100-based design is intended to support both MultiMediaCards
- * and 1- or 4-data bit SecureDigital cards, then the solution is to
- * connect a weak (560KOhm) pull-up resistor to connector pin 1.
- * In doing so, a MMC card never enters SPI-mode communications,
- * but now the SecureDigital card-detect feature of CD/DAT3 is ineffective
- * (the low to high transition will not occur).
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/scatterlist.h>
-#include <linux/leds.h>
-#include <linux/mmc/host.h>
-#include <linux/slab.h>
-
-#include <asm/io.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-au1x00/au1xxx_dbdma.h>
-#include <asm/mach-au1x00/au1100_mmc.h>
-
-#define DRIVER_NAME "au1xxx-mmc"
-
-/* Set this to enable special debugging macros */
-/* #define DEBUG */
-
-#ifdef DEBUG
-#define DBG(fmt, idx, args...) \
- pr_debug("au1xmmc(%d): DEBUG: " fmt, idx, ##args)
-#else
-#define DBG(fmt, idx, args...) do {} while (0)
-#endif
-
-/* Hardware definitions */
-#define AU1XMMC_DESCRIPTOR_COUNT 1
-
-/* max DMA seg size: 64KB on Au1100, 4MB on Au1200 */
-#define AU1100_MMC_DESCRIPTOR_SIZE 0x0000ffff
-#define AU1200_MMC_DESCRIPTOR_SIZE 0x003fffff
-
-#define AU1XMMC_OCR (MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 | \
- MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | \
- MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36)
-
-/* This gives us a hard value for the stop command that we can write directly
- * to the command register.
- */
-#define STOP_CMD \
- (SD_CMD_RT_1B | SD_CMD_CT_7 | (0xC << SD_CMD_CI_SHIFT) | SD_CMD_GO)
-
-/* This is the set of interrupts that we configure by default. */
-#define AU1XMMC_INTERRUPTS \
- (SD_CONFIG_SC | SD_CONFIG_DT | SD_CONFIG_RAT | \
- SD_CONFIG_CR | SD_CONFIG_I)
-
-/* The poll event (looking for insert/remove events runs twice a second. */
-#define AU1XMMC_DETECT_TIMEOUT (HZ/2)
-
-struct au1xmmc_host {
- struct mmc_host *mmc;
- struct mmc_request *mrq;
-
- u32 flags;
- u32 iobase;
- u32 clock;
- u32 bus_width;
- u32 power_mode;
-
- int status;
-
- struct {
- int len;
- int dir;
- } dma;
-
- struct {
- int index;
- int offset;
- int len;
- } pio;
-
- u32 tx_chan;
- u32 rx_chan;
-
- int irq;
-
- struct tasklet_struct finish_task;
- struct tasklet_struct data_task;
- struct au1xmmc_platform_data *platdata;
- struct platform_device *pdev;
- struct resource *ioarea;
-};
-
-/* Status flags used by the host structure */
-#define HOST_F_XMIT 0x0001
-#define HOST_F_RECV 0x0002
-#define HOST_F_DMA 0x0010
-#define HOST_F_DBDMA 0x0020
-#define HOST_F_ACTIVE 0x0100
-#define HOST_F_STOP 0x1000
-
-#define HOST_S_IDLE 0x0001
-#define HOST_S_CMD 0x0002
-#define HOST_S_DATA 0x0003
-#define HOST_S_STOP 0x0004
-
-/* Easy access macros */
-#define HOST_STATUS(h) ((h)->iobase + SD_STATUS)
-#define HOST_CONFIG(h) ((h)->iobase + SD_CONFIG)
-#define HOST_ENABLE(h) ((h)->iobase + SD_ENABLE)
-#define HOST_TXPORT(h) ((h)->iobase + SD_TXPORT)
-#define HOST_RXPORT(h) ((h)->iobase + SD_RXPORT)
-#define HOST_CMDARG(h) ((h)->iobase + SD_CMDARG)
-#define HOST_BLKSIZE(h) ((h)->iobase + SD_BLKSIZE)
-#define HOST_CMD(h) ((h)->iobase + SD_CMD)
-#define HOST_CONFIG2(h) ((h)->iobase + SD_CONFIG2)
-#define HOST_TIMEOUT(h) ((h)->iobase + SD_TIMEOUT)
-#define HOST_DEBUG(h) ((h)->iobase + SD_DEBUG)
-
-#define DMA_CHANNEL(h) \
- (((h)->flags & HOST_F_XMIT) ? (h)->tx_chan : (h)->rx_chan)
-
-static inline int has_dbdma(void)
-{
- switch (alchemy_get_cputype()) {
- case ALCHEMY_CPU_AU1200:
- case ALCHEMY_CPU_AU1300:
- return 1;
- default:
- return 0;
- }
-}
-
-static inline void IRQ_ON(struct au1xmmc_host *host, u32 mask)
-{
- u32 val = au_readl(HOST_CONFIG(host));
- val |= mask;
- au_writel(val, HOST_CONFIG(host));
- au_sync();
-}
-
-static inline void FLUSH_FIFO(struct au1xmmc_host *host)
-{
- u32 val = au_readl(HOST_CONFIG2(host));
-
- au_writel(val | SD_CONFIG2_FF, HOST_CONFIG2(host));
- au_sync_delay(1);
-
- /* SEND_STOP will turn off clock control - this re-enables it */
- val &= ~SD_CONFIG2_DF;
-
- au_writel(val, HOST_CONFIG2(host));
- au_sync();
-}
-
-static inline void IRQ_OFF(struct au1xmmc_host *host, u32 mask)
-{
- u32 val = au_readl(HOST_CONFIG(host));
- val &= ~mask;
- au_writel(val, HOST_CONFIG(host));
- au_sync();
-}
-
-static inline void SEND_STOP(struct au1xmmc_host *host)
-{
- u32 config2;
-
- WARN_ON(host->status != HOST_S_DATA);
- host->status = HOST_S_STOP;
-
- config2 = au_readl(HOST_CONFIG2(host));
- au_writel(config2 | SD_CONFIG2_DF, HOST_CONFIG2(host));
- au_sync();
-
- /* Send the stop command */
- au_writel(STOP_CMD, HOST_CMD(host));
-}
-
-static void au1xmmc_set_power(struct au1xmmc_host *host, int state)
-{
- if (host->platdata && host->platdata->set_power)
- host->platdata->set_power(host->mmc, state);
-}
-
-static int au1xmmc_card_inserted(struct mmc_host *mmc)
-{
- struct au1xmmc_host *host = mmc_priv(mmc);
-
- if (host->platdata && host->platdata->card_inserted)
- return !!host->platdata->card_inserted(host->mmc);
-
- return -ENOSYS;
-}
-
-static int au1xmmc_card_readonly(struct mmc_host *mmc)
-{
- struct au1xmmc_host *host = mmc_priv(mmc);
-
- if (host->platdata && host->platdata->card_readonly)
- return !!host->platdata->card_readonly(mmc);
-
- return -ENOSYS;
-}
-
-static void au1xmmc_finish_request(struct au1xmmc_host *host)
-{
- struct mmc_request *mrq = host->mrq;
-
- host->mrq = NULL;
- host->flags &= HOST_F_ACTIVE | HOST_F_DMA;
-
- host->dma.len = 0;
- host->dma.dir = 0;
-
- host->pio.index = 0;
- host->pio.offset = 0;
- host->pio.len = 0;
-
- host->status = HOST_S_IDLE;
-
- mmc_request_done(host->mmc, mrq);
-}
-
-static void au1xmmc_tasklet_finish(unsigned long param)
-{
- struct au1xmmc_host *host = (struct au1xmmc_host *) param;
- au1xmmc_finish_request(host);
-}
-
-static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
- struct mmc_command *cmd, struct mmc_data *data)
-{
- u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
-
- switch (mmc_resp_type(cmd)) {
- case MMC_RSP_NONE:
- break;
- case MMC_RSP_R1:
- mmccmd |= SD_CMD_RT_1;
- break;
- case MMC_RSP_R1B:
- mmccmd |= SD_CMD_RT_1B;
- break;
- case MMC_RSP_R2:
- mmccmd |= SD_CMD_RT_2;
- break;
- case MMC_RSP_R3:
- mmccmd |= SD_CMD_RT_3;
- break;
- default:
- pr_info("au1xmmc: unhandled response type %02x\n",
- mmc_resp_type(cmd));
- return -EINVAL;
- }
-
- if (data) {
- if (data->flags & MMC_DATA_READ) {
- if (data->blocks > 1)
- mmccmd |= SD_CMD_CT_4;
- else
- mmccmd |= SD_CMD_CT_2;
- } else if (data->flags & MMC_DATA_WRITE) {
- if (data->blocks > 1)
- mmccmd |= SD_CMD_CT_3;
- else
- mmccmd |= SD_CMD_CT_1;
- }
- }
-
- au_writel(cmd->arg, HOST_CMDARG(host));
- au_sync();
-
- if (wait)
- IRQ_OFF(host, SD_CONFIG_CR);
-
- au_writel((mmccmd | SD_CMD_GO), HOST_CMD(host));
- au_sync();
-
- /* Wait for the command to go on the line */
- while (au_readl(HOST_CMD(host)) & SD_CMD_GO)
- /* nop */;
-
- /* Wait for the command to come back */
- if (wait) {
- u32 status = au_readl(HOST_STATUS(host));
-
- while (!(status & SD_STATUS_CR))
- status = au_readl(HOST_STATUS(host));
-
- /* Clear the CR status */
- au_writel(SD_STATUS_CR, HOST_STATUS(host));
-
- IRQ_ON(host, SD_CONFIG_CR);
- }
-
- return 0;
-}
-
-static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
-{
- struct mmc_request *mrq = host->mrq;
- struct mmc_data *data;
- u32 crc;
-
- WARN_ON((host->status != HOST_S_DATA) && (host->status != HOST_S_STOP));
-
- if (host->mrq == NULL)
- return;
-
- data = mrq->cmd->data;
-
- if (status == 0)
- status = au_readl(HOST_STATUS(host));
-
- /* The transaction is really over when the SD_STATUS_DB bit is clear */
- while ((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB))
- status = au_readl(HOST_STATUS(host));
-
- data->error = 0;
- dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir);
-
- /* Process any errors */
- crc = (status & (SD_STATUS_WC | SD_STATUS_RC));
- if (host->flags & HOST_F_XMIT)
- crc |= ((status & 0x07) == 0x02) ? 0 : 1;
-
- if (crc)
- data->error = -EILSEQ;
-
- /* Clear the CRC bits */
- au_writel(SD_STATUS_WC | SD_STATUS_RC, HOST_STATUS(host));
-
- data->bytes_xfered = 0;
-
- if (!data->error) {
- if (host->flags & (HOST_F_DMA | HOST_F_DBDMA)) {
- u32 chan = DMA_CHANNEL(host);
-
- chan_tab_t *c = *((chan_tab_t **)chan);
- au1x_dma_chan_t *cp = c->chan_ptr;
- data->bytes_xfered = cp->ddma_bytecnt;
- } else
- data->bytes_xfered =
- (data->blocks * data->blksz) - host->pio.len;
- }
-
- au1xmmc_finish_request(host);
-}
-
-static void au1xmmc_tasklet_data(unsigned long param)
-{
- struct au1xmmc_host *host = (struct au1xmmc_host *)param;
-
- u32 status = au_readl(HOST_STATUS(host));
- au1xmmc_data_complete(host, status);
-}
-
-#define AU1XMMC_MAX_TRANSFER 8
-
-static void au1xmmc_send_pio(struct au1xmmc_host *host)
-{
- struct mmc_data *data;
- int sg_len, max, count;
- unsigned char *sg_ptr, val;
- u32 status;
- struct scatterlist *sg;
-
- data = host->mrq->data;
-
- if (!(host->flags & HOST_F_XMIT))
- return;
-
- /* This is the pointer to the data buffer */
- sg = &data->sg[host->pio.index];
- sg_ptr = sg_virt(sg) + host->pio.offset;
-
- /* This is the space left inside the buffer */
- sg_len = data->sg[host->pio.index].length - host->pio.offset;
-
- /* Check if we need less than the size of the sg_buffer */
- max = (sg_len > host->pio.len) ? host->pio.len : sg_len;
- if (max > AU1XMMC_MAX_TRANSFER)
- max = AU1XMMC_MAX_TRANSFER;
-
- for (count = 0; count < max; count++) {
- status = au_readl(HOST_STATUS(host));
-
- if (!(status & SD_STATUS_TH))
- break;
-
- val = *sg_ptr++;
-
- au_writel((unsigned long)val, HOST_TXPORT(host));
- au_sync();
- }
-
- host->pio.len -= count;
- host->pio.offset += count;
-
- if (count == sg_len) {
- host->pio.index++;
- host->pio.offset = 0;
- }
-
- if (host->pio.len == 0) {
- IRQ_OFF(host, SD_CONFIG_TH);
-
- if (host->flags & HOST_F_STOP)
- SEND_STOP(host);
-
- tasklet_schedule(&host->data_task);
- }
-}
-
-static void au1xmmc_receive_pio(struct au1xmmc_host *host)
-{
- struct mmc_data *data;
- int max, count, sg_len = 0;
- unsigned char *sg_ptr = NULL;
- u32 status, val;
- struct scatterlist *sg;
-
- data = host->mrq->data;
-
- if (!(host->flags & HOST_F_RECV))
- return;
-
- max = host->pio.len;
-
- if (host->pio.index < host->dma.len) {
- sg = &data->sg[host->pio.index];
- sg_ptr = sg_virt(sg) + host->pio.offset;
-
- /* This is the space left inside the buffer */
- sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset;
-
- /* Check if we need less than the size of the sg_buffer */
- if (sg_len < max)
- max = sg_len;
- }
-
- if (max > AU1XMMC_MAX_TRANSFER)
- max = AU1XMMC_MAX_TRANSFER;
-
- for (count = 0; count < max; count++) {
- status = au_readl(HOST_STATUS(host));
-
- if (!(status & SD_STATUS_NE))
- break;
-
- if (status & SD_STATUS_RC) {
- DBG("RX CRC Error [%d + %d].\n", host->pdev->id,
- host->pio.len, count);
- break;
- }
-
- if (status & SD_STATUS_RO) {
- DBG("RX Overrun [%d + %d]\n", host->pdev->id,
- host->pio.len, count);
- break;
- }
- else if (status & SD_STATUS_RU) {
- DBG("RX Underrun [%d + %d]\n", host->pdev->id,
- host->pio.len, count);
- break;
- }
-
- val = au_readl(HOST_RXPORT(host));
-
- if (sg_ptr)
- *sg_ptr++ = (unsigned char)(val & 0xFF);
- }
-
- host->pio.len -= count;
- host->pio.offset += count;
-
- if (sg_len && count == sg_len) {
- host->pio.index++;
- host->pio.offset = 0;
- }
-
- if (host->pio.len == 0) {
- /* IRQ_OFF(host, SD_CONFIG_RA | SD_CONFIG_RF); */
- IRQ_OFF(host, SD_CONFIG_NE);
-
- if (host->flags & HOST_F_STOP)
- SEND_STOP(host);
-
- tasklet_schedule(&host->data_task);
- }
-}
-
-/* This is called when a command has been completed - grab the response
- * and check for errors. Then start the data transfer if it is indicated.
- */
-static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
-{
- struct mmc_request *mrq = host->mrq;
- struct mmc_command *cmd;
- u32 r[4];
- int i, trans;
-
- if (!host->mrq)
- return;
-
- cmd = mrq->cmd;
- cmd->error = 0;
-
- if (cmd->flags & MMC_RSP_PRESENT) {
- if (cmd->flags & MMC_RSP_136) {
- r[0] = au_readl(host->iobase + SD_RESP3);
- r[1] = au_readl(host->iobase + SD_RESP2);
- r[2] = au_readl(host->iobase + SD_RESP1);
- r[3] = au_readl(host->iobase + SD_RESP0);
-
- /* The CRC is omitted from the response, so really
- * we only got 120 bytes, but the engine expects
- * 128 bits, so we have to shift things up.
- */
- for (i = 0; i < 4; i++) {
- cmd->resp[i] = (r[i] & 0x00FFFFFF) << 8;
- if (i != 3)
- cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24;
- }
- } else {
- /* Techincally, we should be getting all 48 bits of
- * the response (SD_RESP1 + SD_RESP2), but because
- * our response omits the CRC, our data ends up
- * being shifted 8 bits to the right. In this case,
- * that means that the OSR data starts at bit 31,
- * so we can just read RESP0 and return that.
- */
- cmd->resp[0] = au_readl(host->iobase + SD_RESP0);
- }
- }
-
- /* Figure out errors */
- if (status & (SD_STATUS_SC | SD_STATUS_WC | SD_STATUS_RC))
- cmd->error = -EILSEQ;
-
- trans = host->flags & (HOST_F_XMIT | HOST_F_RECV);
-
- if (!trans || cmd->error) {
- IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA | SD_CONFIG_RF);
- tasklet_schedule(&host->finish_task);
- return;
- }
-
- host->status = HOST_S_DATA;
-
- if ((host->flags & (HOST_F_DMA | HOST_F_DBDMA))) {
- u32 channel = DMA_CHANNEL(host);
-
- /* Start the DBDMA as soon as the buffer gets something in it */
-
- if (host->flags & HOST_F_RECV) {
- u32 mask = SD_STATUS_DB | SD_STATUS_NE;
-
- while((status & mask) != mask)
- status = au_readl(HOST_STATUS(host));
- }
-
- au1xxx_dbdma_start(channel);
- }
-}
-
-static void au1xmmc_set_clock(struct au1xmmc_host *host, int rate)
-{
- unsigned int pbus = get_au1x00_speed();
- unsigned int divisor;
- u32 config;
-
- /* From databook:
- * divisor = ((((cpuclock / sbus_divisor) / 2) / mmcclock) / 2) - 1
- */
- pbus /= ((au_readl(SYS_POWERCTRL) & 0x3) + 2);
- pbus /= 2;
- divisor = ((pbus / rate) / 2) - 1;
-
- config = au_readl(HOST_CONFIG(host));
-
- config &= ~(SD_CONFIG_DIV);
- config |= (divisor & SD_CONFIG_DIV) | SD_CONFIG_DE;
-
- au_writel(config, HOST_CONFIG(host));
- au_sync();
-}
-
-static int au1xmmc_prepare_data(struct au1xmmc_host *host,
- struct mmc_data *data)
-{
- int datalen = data->blocks * data->blksz;
-
- if (data->flags & MMC_DATA_READ)
- host->flags |= HOST_F_RECV;
- else
- host->flags |= HOST_F_XMIT;
-
- if (host->mrq->stop)
- host->flags |= HOST_F_STOP;
-
- host->dma.dir = DMA_BIDIRECTIONAL;
-
- host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, host->dma.dir);
-
- if (host->dma.len == 0)
- return -ETIMEDOUT;
-
- au_writel(data->blksz - 1, HOST_BLKSIZE(host));
-
- if (host->flags & (HOST_F_DMA | HOST_F_DBDMA)) {
- int i;
- u32 channel = DMA_CHANNEL(host);
-
- au1xxx_dbdma_stop(channel);
-
- for (i = 0; i < host->dma.len; i++) {
- u32 ret = 0, flags = DDMA_FLAGS_NOIE;
- struct scatterlist *sg = &data->sg[i];
- int sg_len = sg->length;
-
- int len = (datalen > sg_len) ? sg_len : datalen;
-
- if (i == host->dma.len - 1)
- flags = DDMA_FLAGS_IE;
-
- if (host->flags & HOST_F_XMIT) {
- ret = au1xxx_dbdma_put_source(channel,
- sg_phys(sg), len, flags);
- } else {
- ret = au1xxx_dbdma_put_dest(channel,
- sg_phys(sg), len, flags);
- }
-
- if (!ret)
- goto dataerr;
-
- datalen -= len;
- }
- } else {
- host->pio.index = 0;
- host->pio.offset = 0;
- host->pio.len = datalen;
-
- if (host->flags & HOST_F_XMIT)
- IRQ_ON(host, SD_CONFIG_TH);
- else
- IRQ_ON(host, SD_CONFIG_NE);
- /* IRQ_ON(host, SD_CONFIG_RA | SD_CONFIG_RF); */
- }
-
- return 0;
-
-dataerr:
- dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- host->dma.dir);
- return -ETIMEDOUT;
-}
-
-/* This actually starts a command or data transaction */
-static void au1xmmc_request(struct mmc_host* mmc, struct mmc_request* mrq)
-{
- struct au1xmmc_host *host = mmc_priv(mmc);
- int ret = 0;
-
- WARN_ON(irqs_disabled());
- WARN_ON(host->status != HOST_S_IDLE);
-
- host->mrq = mrq;
- host->status = HOST_S_CMD;
-
- /* fail request immediately if no card is present */
- if (0 == au1xmmc_card_inserted(mmc)) {
- mrq->cmd->error = -ENOMEDIUM;
- au1xmmc_finish_request(host);
- return;
- }
-
- if (mrq->data) {
- FLUSH_FIFO(host);
- ret = au1xmmc_prepare_data(host, mrq->data);
- }
-
- if (!ret)
- ret = au1xmmc_send_command(host, 0, mrq->cmd, mrq->data);
-
- if (ret) {
- mrq->cmd->error = ret;
- au1xmmc_finish_request(host);
- }
-}
-
-static void au1xmmc_reset_controller(struct au1xmmc_host *host)
-{
- /* Apply the clock */
- au_writel(SD_ENABLE_CE, HOST_ENABLE(host));
- au_sync_delay(1);
-
- au_writel(SD_ENABLE_R | SD_ENABLE_CE, HOST_ENABLE(host));
- au_sync_delay(5);
-
- au_writel(~0, HOST_STATUS(host));
- au_sync();
-
- au_writel(0, HOST_BLKSIZE(host));
- au_writel(0x001fffff, HOST_TIMEOUT(host));
- au_sync();
-
- au_writel(SD_CONFIG2_EN, HOST_CONFIG2(host));
- au_sync();
-
- au_writel(SD_CONFIG2_EN | SD_CONFIG2_FF, HOST_CONFIG2(host));
- au_sync_delay(1);
-
- au_writel(SD_CONFIG2_EN, HOST_CONFIG2(host));
- au_sync();
-
- /* Configure interrupts */
- au_writel(AU1XMMC_INTERRUPTS, HOST_CONFIG(host));
- au_sync();
-}
-
-
-static void au1xmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct au1xmmc_host *host = mmc_priv(mmc);
- u32 config2;
-
- if (ios->power_mode == MMC_POWER_OFF)
- au1xmmc_set_power(host, 0);
- else if (ios->power_mode == MMC_POWER_ON) {
- au1xmmc_set_power(host, 1);
- }
-
- if (ios->clock && ios->clock != host->clock) {
- au1xmmc_set_clock(host, ios->clock);
- host->clock = ios->clock;
- }
-
- config2 = au_readl(HOST_CONFIG2(host));
- switch (ios->bus_width) {
- case MMC_BUS_WIDTH_8:
- config2 |= SD_CONFIG2_BB;
- break;
- case MMC_BUS_WIDTH_4:
- config2 &= ~SD_CONFIG2_BB;
- config2 |= SD_CONFIG2_WB;
- break;
- case MMC_BUS_WIDTH_1:
- config2 &= ~(SD_CONFIG2_WB | SD_CONFIG2_BB);
- break;
- }
- au_writel(config2, HOST_CONFIG2(host));
- au_sync();
-}
-
-#define STATUS_TIMEOUT (SD_STATUS_RAT | SD_STATUS_DT)
-#define STATUS_DATA_IN (SD_STATUS_NE)
-#define STATUS_DATA_OUT (SD_STATUS_TH)
-
-static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
-{
- struct au1xmmc_host *host = dev_id;
- u32 status;
-
- status = au_readl(HOST_STATUS(host));
-
- if (!(status & SD_STATUS_I))
- return IRQ_NONE; /* not ours */
-
- if (status & SD_STATUS_SI) /* SDIO */
- mmc_signal_sdio_irq(host->mmc);
-
- if (host->mrq && (status & STATUS_TIMEOUT)) {
- if (status & SD_STATUS_RAT)
- host->mrq->cmd->error = -ETIMEDOUT;
- else if (status & SD_STATUS_DT)
- host->mrq->data->error = -ETIMEDOUT;
-
- /* In PIO mode, interrupts might still be enabled */
- IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH);
-
- /* IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA | SD_CONFIG_RF); */
- tasklet_schedule(&host->finish_task);
- }
-#if 0
- else if (status & SD_STATUS_DD) {
- /* Sometimes we get a DD before a NE in PIO mode */
- if (!(host->flags & HOST_F_DMA) && (status & SD_STATUS_NE))
- au1xmmc_receive_pio(host);
- else {
- au1xmmc_data_complete(host, status);
- /* tasklet_schedule(&host->data_task); */
- }
- }
-#endif
- else if (status & SD_STATUS_CR) {
- if (host->status == HOST_S_CMD)
- au1xmmc_cmd_complete(host, status);
-
- } else if (!(host->flags & HOST_F_DMA)) {
- if ((host->flags & HOST_F_XMIT) && (status & STATUS_DATA_OUT))
- au1xmmc_send_pio(host);
- else if ((host->flags & HOST_F_RECV) && (status & STATUS_DATA_IN))
- au1xmmc_receive_pio(host);
-
- } else if (status & 0x203F3C70) {
- DBG("Unhandled status %8.8x\n", host->pdev->id,
- status);
- }
-
- au_writel(status, HOST_STATUS(host));
- au_sync();
-
- return IRQ_HANDLED;
-}
-
-/* 8bit memory DMA device */
-static dbdev_tab_t au1xmmc_mem_dbdev = {
- .dev_id = DSCR_CMD0_ALWAYS,
- .dev_flags = DEV_FLAGS_ANYUSE,
- .dev_tsize = 0,
- .dev_devwidth = 8,
- .dev_physaddr = 0x00000000,
- .dev_intlevel = 0,
- .dev_intpolarity = 0,
-};
-static int memid;
-
-static void au1xmmc_dbdma_callback(int irq, void *dev_id)
-{
- struct au1xmmc_host *host = (struct au1xmmc_host *)dev_id;
-
- /* Avoid spurious interrupts */
- if (!host->mrq)
- return;
-
- if (host->flags & HOST_F_STOP)
- SEND_STOP(host);
-
- tasklet_schedule(&host->data_task);
-}
-
-static int au1xmmc_dbdma_init(struct au1xmmc_host *host)
-{
- struct resource *res;
- int txid, rxid;
-
- res = platform_get_resource(host->pdev, IORESOURCE_DMA, 0);
- if (!res)
- return -ENODEV;
- txid = res->start;
-
- res = platform_get_resource(host->pdev, IORESOURCE_DMA, 1);
- if (!res)
- return -ENODEV;
- rxid = res->start;
-
- if (!memid)
- return -ENODEV;
-
- host->tx_chan = au1xxx_dbdma_chan_alloc(memid, txid,
- au1xmmc_dbdma_callback, (void *)host);
- if (!host->tx_chan) {
- dev_err(&host->pdev->dev, "cannot allocate TX DMA\n");
- return -ENODEV;
- }
-
- host->rx_chan = au1xxx_dbdma_chan_alloc(rxid, memid,
- au1xmmc_dbdma_callback, (void *)host);
- if (!host->rx_chan) {
- dev_err(&host->pdev->dev, "cannot allocate RX DMA\n");
- au1xxx_dbdma_chan_free(host->tx_chan);
- return -ENODEV;
- }
-
- au1xxx_dbdma_set_devwidth(host->tx_chan, 8);
- au1xxx_dbdma_set_devwidth(host->rx_chan, 8);
-
- au1xxx_dbdma_ring_alloc(host->tx_chan, AU1XMMC_DESCRIPTOR_COUNT);
- au1xxx_dbdma_ring_alloc(host->rx_chan, AU1XMMC_DESCRIPTOR_COUNT);
-
- /* DBDMA is good to go */
- host->flags |= HOST_F_DMA | HOST_F_DBDMA;
-
- return 0;
-}
-
-static void au1xmmc_dbdma_shutdown(struct au1xmmc_host *host)
-{
- if (host->flags & HOST_F_DMA) {
- host->flags &= ~HOST_F_DMA;
- au1xxx_dbdma_chan_free(host->tx_chan);
- au1xxx_dbdma_chan_free(host->rx_chan);
- }
-}
-
-static void au1xmmc_enable_sdio_irq(struct mmc_host *mmc, int en)
-{
- struct au1xmmc_host *host = mmc_priv(mmc);
-
- if (en)
- IRQ_ON(host, SD_CONFIG_SI);
- else
- IRQ_OFF(host, SD_CONFIG_SI);
-}
-
-static const struct mmc_host_ops au1xmmc_ops = {
- .request = au1xmmc_request,
- .set_ios = au1xmmc_set_ios,
- .get_ro = au1xmmc_card_readonly,
- .get_cd = au1xmmc_card_inserted,
- .enable_sdio_irq = au1xmmc_enable_sdio_irq,
-};
-
-static int __devinit au1xmmc_probe(struct platform_device *pdev)
-{
- struct mmc_host *mmc;
- struct au1xmmc_host *host;
- struct resource *r;
- int ret, iflag;
-
- mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev);
- if (!mmc) {
- dev_err(&pdev->dev, "no memory for mmc_host\n");
- ret = -ENOMEM;
- goto out0;
- }
-
- host = mmc_priv(mmc);
- host->mmc = mmc;
- host->platdata = pdev->dev.platform_data;
- host->pdev = pdev;
-
- ret = -ENODEV;
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- dev_err(&pdev->dev, "no mmio defined\n");
- goto out1;
- }
-
- host->ioarea = request_mem_region(r->start, resource_size(r),
- pdev->name);
- if (!host->ioarea) {
- dev_err(&pdev->dev, "mmio already in use\n");
- goto out1;
- }
-
- host->iobase = (unsigned long)ioremap(r->start, 0x3c);
- if (!host->iobase) {
- dev_err(&pdev->dev, "cannot remap mmio\n");
- goto out2;
- }
-
- r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!r) {
- dev_err(&pdev->dev, "no IRQ defined\n");
- goto out3;
- }
- host->irq = r->start;
-
- mmc->ops = &au1xmmc_ops;
-
- mmc->f_min = 450000;
- mmc->f_max = 24000000;
-
- mmc->max_blk_size = 2048;
- mmc->max_blk_count = 512;
-
- mmc->ocr_avail = AU1XMMC_OCR;
- mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
- mmc->max_segs = AU1XMMC_DESCRIPTOR_COUNT;
-
- iflag = IRQF_SHARED; /* Au1100/Au1200: one int for both ctrls */
-
- switch (alchemy_get_cputype()) {
- case ALCHEMY_CPU_AU1100:
- mmc->max_seg_size = AU1100_MMC_DESCRIPTOR_SIZE;
- break;
- case ALCHEMY_CPU_AU1200:
- mmc->max_seg_size = AU1200_MMC_DESCRIPTOR_SIZE;
- break;
- case ALCHEMY_CPU_AU1300:
- iflag = 0; /* nothing is shared */
- mmc->max_seg_size = AU1200_MMC_DESCRIPTOR_SIZE;
- mmc->f_max = 52000000;
- if (host->ioarea->start == AU1100_SD0_PHYS_ADDR)
- mmc->caps |= MMC_CAP_8_BIT_DATA;
- break;
- }
-
- ret = request_irq(host->irq, au1xmmc_irq, iflag, DRIVER_NAME, host);
- if (ret) {
- dev_err(&pdev->dev, "cannot grab IRQ\n");
- goto out3;
- }
-
- host->status = HOST_S_IDLE;
-
- /* board-specific carddetect setup, if any */
- if (host->platdata && host->platdata->cd_setup) {
- ret = host->platdata->cd_setup(mmc, 1);
- if (ret) {
- dev_warn(&pdev->dev, "board CD setup failed\n");
- mmc->caps |= MMC_CAP_NEEDS_POLL;
- }
- } else
- mmc->caps |= MMC_CAP_NEEDS_POLL;
-
- /* platform may not be able to use all advertised caps */
- if (host->platdata)
- mmc->caps &= ~(host->platdata->mask_host_caps);
-
- tasklet_init(&host->data_task, au1xmmc_tasklet_data,
- (unsigned long)host);
-
- tasklet_init(&host->finish_task, au1xmmc_tasklet_finish,
- (unsigned long)host);
-
- if (has_dbdma()) {
- ret = au1xmmc_dbdma_init(host);
- if (ret)
- pr_info(DRIVER_NAME ": DBDMA init failed; using PIO\n");
- }
-
-#ifdef CONFIG_LEDS_CLASS
- if (host->platdata && host->platdata->led) {
- struct led_classdev *led = host->platdata->led;
- led->name = mmc_hostname(mmc);
- led->brightness = LED_OFF;
- led->default_trigger = mmc_hostname(mmc);
- ret = led_classdev_register(mmc_dev(mmc), led);
- if (ret)
- goto out5;
- }
-#endif
-
- au1xmmc_reset_controller(host);
-
- ret = mmc_add_host(mmc);
- if (ret) {
- dev_err(&pdev->dev, "cannot add mmc host\n");
- goto out6;
- }
-
- platform_set_drvdata(pdev, host);
-
- pr_info(DRIVER_NAME ": MMC Controller %d set up at %8.8X"
- " (mode=%s)\n", pdev->id, host->iobase,
- host->flags & HOST_F_DMA ? "dma" : "pio");
-
- return 0; /* all ok */
-
-out6:
-#ifdef CONFIG_LEDS_CLASS
- if (host->platdata && host->platdata->led)
- led_classdev_unregister(host->platdata->led);
-out5:
-#endif
- au_writel(0, HOST_ENABLE(host));
- au_writel(0, HOST_CONFIG(host));
- au_writel(0, HOST_CONFIG2(host));
- au_sync();
-
- if (host->flags & HOST_F_DBDMA)
- au1xmmc_dbdma_shutdown(host);
-
- tasklet_kill(&host->data_task);
- tasklet_kill(&host->finish_task);
-
- if (host->platdata && host->platdata->cd_setup &&
- !(mmc->caps & MMC_CAP_NEEDS_POLL))
- host->platdata->cd_setup(mmc, 0);
-
- free_irq(host->irq, host);
-out3:
- iounmap((void *)host->iobase);
-out2:
- release_resource(host->ioarea);
- kfree(host->ioarea);
-out1:
- mmc_free_host(mmc);
-out0:
- return ret;
-}
-
-static int __devexit au1xmmc_remove(struct platform_device *pdev)
-{
- struct au1xmmc_host *host = platform_get_drvdata(pdev);
-
- if (host) {
- mmc_remove_host(host->mmc);
-
-#ifdef CONFIG_LEDS_CLASS
- if (host->platdata && host->platdata->led)
- led_classdev_unregister(host->platdata->led);
-#endif
-
- if (host->platdata && host->platdata->cd_setup &&
- !(host->mmc->caps & MMC_CAP_NEEDS_POLL))
- host->platdata->cd_setup(host->mmc, 0);
-
- au_writel(0, HOST_ENABLE(host));
- au_writel(0, HOST_CONFIG(host));
- au_writel(0, HOST_CONFIG2(host));
- au_sync();
-
- tasklet_kill(&host->data_task);
- tasklet_kill(&host->finish_task);
-
- if (host->flags & HOST_F_DBDMA)
- au1xmmc_dbdma_shutdown(host);
-
- au1xmmc_set_power(host, 0);
-
- free_irq(host->irq, host);
- iounmap((void *)host->iobase);
- release_resource(host->ioarea);
- kfree(host->ioarea);
-
- mmc_free_host(host->mmc);
- platform_set_drvdata(pdev, NULL);
- }
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int au1xmmc_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct au1xmmc_host *host = platform_get_drvdata(pdev);
- int ret;
-
- ret = mmc_suspend_host(host->mmc);
- if (ret)
- return ret;
-
- au_writel(0, HOST_CONFIG2(host));
- au_writel(0, HOST_CONFIG(host));
- au_writel(0xffffffff, HOST_STATUS(host));
- au_writel(0, HOST_ENABLE(host));
- au_sync();
-
- return 0;
-}
-
-static int au1xmmc_resume(struct platform_device *pdev)
-{
- struct au1xmmc_host *host = platform_get_drvdata(pdev);
-
- au1xmmc_reset_controller(host);
-
- return mmc_resume_host(host->mmc);
-}
-#else
-#define au1xmmc_suspend NULL
-#define au1xmmc_resume NULL
-#endif
-
-static struct platform_driver au1xmmc_driver = {
- .probe = au1xmmc_probe,
- .remove = au1xmmc_remove,
- .suspend = au1xmmc_suspend,
- .resume = au1xmmc_resume,
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- },
-};
-
-static int __init au1xmmc_init(void)
-{
- if (has_dbdma()) {
- /* DSCR_CMD0_ALWAYS has a stride of 32 bits, we need a stride
- * of 8 bits. And since devices are shared, we need to create
- * our own to avoid freaking out other devices.
- */
- memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev);
- if (!memid)
- pr_err("au1xmmc: cannot add memory dbdma\n");
- }
- return platform_driver_register(&au1xmmc_driver);
-}
-
-static void __exit au1xmmc_exit(void)
-{
- if (has_dbdma() && memid)
- au1xxx_ddma_del_device(memid);
-
- platform_driver_unregister(&au1xmmc_driver);
-}
-
-module_init(au1xmmc_init);
-module_exit(au1xmmc_exit);
-
-MODULE_AUTHOR("Advanced Micro Devices, Inc");
-MODULE_DESCRIPTION("MMC/SD driver for the Alchemy Au1XXX");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:au1xxx-mmc");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/bfin_sdh.c b/ANDROID_3.4.5/drivers/mmc/host/bfin_sdh.c
deleted file mode 100644
index 03666174..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/bfin_sdh.c
+++ /dev/null
@@ -1,634 +0,0 @@
-/*
- * bfin_sdh.c - Analog Devices Blackfin SDH Controller
- *
- * Copyright (C) 2007-2009 Analog Device Inc.
- *
- * Licensed under the GPL-2 or later.
- */
-
-#define DRIVER_NAME "bfin-sdh"
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/mmc/host.h>
-#include <linux/proc_fs.h>
-#include <linux/gfp.h>
-
-#include <asm/cacheflush.h>
-#include <asm/dma.h>
-#include <asm/portmux.h>
-#include <asm/bfin_sdh.h>
-
-#if defined(CONFIG_BF51x)
-#define bfin_read_SDH_PWR_CTL bfin_read_RSI_PWR_CTL
-#define bfin_write_SDH_PWR_CTL bfin_write_RSI_PWR_CTL
-#define bfin_read_SDH_CLK_CTL bfin_read_RSI_CLK_CTL
-#define bfin_write_SDH_CLK_CTL bfin_write_RSI_CLK_CTL
-#define bfin_write_SDH_ARGUMENT bfin_write_RSI_ARGUMENT
-#define bfin_write_SDH_COMMAND bfin_write_RSI_COMMAND
-#define bfin_write_SDH_DATA_TIMER bfin_write_RSI_DATA_TIMER
-#define bfin_read_SDH_RESPONSE0 bfin_read_RSI_RESPONSE0
-#define bfin_read_SDH_RESPONSE1 bfin_read_RSI_RESPONSE1
-#define bfin_read_SDH_RESPONSE2 bfin_read_RSI_RESPONSE2
-#define bfin_read_SDH_RESPONSE3 bfin_read_RSI_RESPONSE3
-#define bfin_write_SDH_DATA_LGTH bfin_write_RSI_DATA_LGTH
-#define bfin_read_SDH_DATA_CTL bfin_read_RSI_DATA_CTL
-#define bfin_write_SDH_DATA_CTL bfin_write_RSI_DATA_CTL
-#define bfin_read_SDH_DATA_CNT bfin_read_RSI_DATA_CNT
-#define bfin_write_SDH_STATUS_CLR bfin_write_RSI_STATUS_CLR
-#define bfin_read_SDH_E_STATUS bfin_read_RSI_E_STATUS
-#define bfin_write_SDH_E_STATUS bfin_write_RSI_E_STATUS
-#define bfin_read_SDH_STATUS bfin_read_RSI_STATUS
-#define bfin_write_SDH_MASK0 bfin_write_RSI_MASK0
-#define bfin_read_SDH_CFG bfin_read_RSI_CFG
-#define bfin_write_SDH_CFG bfin_write_RSI_CFG
-#endif
-
-struct dma_desc_array {
- unsigned long start_addr;
- unsigned short cfg;
- unsigned short x_count;
- short x_modify;
-} __packed;
-
-struct sdh_host {
- struct mmc_host *mmc;
- spinlock_t lock;
- struct resource *res;
- void __iomem *base;
- int irq;
- int stat_irq;
- int dma_ch;
- int dma_dir;
- struct dma_desc_array *sg_cpu;
- dma_addr_t sg_dma;
- int dma_len;
-
- unsigned int imask;
- unsigned int power_mode;
- unsigned int clk_div;
-
- struct mmc_request *mrq;
- struct mmc_command *cmd;
- struct mmc_data *data;
-};
-
-static struct bfin_sd_host *get_sdh_data(struct platform_device *pdev)
-{
- return pdev->dev.platform_data;
-}
-
-static void sdh_stop_clock(struct sdh_host *host)
-{
- bfin_write_SDH_CLK_CTL(bfin_read_SDH_CLK_CTL() & ~CLK_E);
- SSYNC();
-}
-
-static void sdh_enable_stat_irq(struct sdh_host *host, unsigned int mask)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- host->imask |= mask;
- bfin_write_SDH_MASK0(mask);
- SSYNC();
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void sdh_disable_stat_irq(struct sdh_host *host, unsigned int mask)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- host->imask &= ~mask;
- bfin_write_SDH_MASK0(host->imask);
- SSYNC();
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data)
-{
- unsigned int length;
- unsigned int data_ctl;
- unsigned int dma_cfg;
- unsigned int cycle_ns, timeout;
-
- dev_dbg(mmc_dev(host->mmc), "%s enter flags: 0x%x\n", __func__, data->flags);
- host->data = data;
- data_ctl = 0;
- dma_cfg = 0;
-
- length = data->blksz * data->blocks;
- bfin_write_SDH_DATA_LGTH(length);
-
- if (data->flags & MMC_DATA_STREAM)
- data_ctl |= DTX_MODE;
-
- if (data->flags & MMC_DATA_READ)
- data_ctl |= DTX_DIR;
- /* Only supports power-of-2 block size */
- if (data->blksz & (data->blksz - 1))
- return -EINVAL;
- data_ctl |= ((ffs(data->blksz) - 1) << 4);
-
- bfin_write_SDH_DATA_CTL(data_ctl);
- /* the time of a host clock period in ns */
- cycle_ns = 1000000000 / (get_sclk() / (2 * (host->clk_div + 1)));
- timeout = data->timeout_ns / cycle_ns;
- timeout += data->timeout_clks;
- bfin_write_SDH_DATA_TIMER(timeout);
- SSYNC();
-
- if (data->flags & MMC_DATA_READ) {
- host->dma_dir = DMA_FROM_DEVICE;
- dma_cfg |= WNR;
- } else
- host->dma_dir = DMA_TO_DEVICE;
-
- sdh_enable_stat_irq(host, (DAT_CRC_FAIL | DAT_TIME_OUT | DAT_END));
- host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma_dir);
-#if defined(CONFIG_BF54x)
- dma_cfg |= DMAFLOW_ARRAY | NDSIZE_5 | RESTART | WDSIZE_32 | DMAEN;
- {
- struct scatterlist *sg;
- int i;
- for_each_sg(data->sg, sg, host->dma_len, i) {
- host->sg_cpu[i].start_addr = sg_dma_address(sg);
- host->sg_cpu[i].cfg = dma_cfg;
- host->sg_cpu[i].x_count = sg_dma_len(sg) / 4;
- host->sg_cpu[i].x_modify = 4;
- dev_dbg(mmc_dev(host->mmc), "%d: start_addr:0x%lx, "
- "cfg:0x%x, x_count:0x%x, x_modify:0x%x\n",
- i, host->sg_cpu[i].start_addr,
- host->sg_cpu[i].cfg, host->sg_cpu[i].x_count,
- host->sg_cpu[i].x_modify);
- }
- }
- flush_dcache_range((unsigned int)host->sg_cpu,
- (unsigned int)host->sg_cpu +
- host->dma_len * sizeof(struct dma_desc_array));
- /* Set the last descriptor to stop mode */
- host->sg_cpu[host->dma_len - 1].cfg &= ~(DMAFLOW | NDSIZE);
- host->sg_cpu[host->dma_len - 1].cfg |= DI_EN;
-
- set_dma_curr_desc_addr(host->dma_ch, (unsigned long *)host->sg_dma);
- set_dma_x_count(host->dma_ch, 0);
- set_dma_x_modify(host->dma_ch, 0);
- set_dma_config(host->dma_ch, dma_cfg);
-#elif defined(CONFIG_BF51x)
- /* RSI DMA doesn't work in array mode */
- dma_cfg |= WDSIZE_32 | DMAEN;
- set_dma_start_addr(host->dma_ch, sg_dma_address(&data->sg[0]));
- set_dma_x_count(host->dma_ch, length / 4);
- set_dma_x_modify(host->dma_ch, 4);
- set_dma_config(host->dma_ch, dma_cfg);
-#endif
- bfin_write_SDH_DATA_CTL(bfin_read_SDH_DATA_CTL() | DTX_DMA_E | DTX_E);
-
- SSYNC();
-
- dev_dbg(mmc_dev(host->mmc), "%s exit\n", __func__);
- return 0;
-}
-
-static void sdh_start_cmd(struct sdh_host *host, struct mmc_command *cmd)
-{
- unsigned int sdh_cmd;
- unsigned int stat_mask;
-
- dev_dbg(mmc_dev(host->mmc), "%s enter cmd: 0x%p\n", __func__, cmd);
- WARN_ON(host->cmd != NULL);
- host->cmd = cmd;
-
- sdh_cmd = 0;
- stat_mask = 0;
-
- sdh_cmd |= cmd->opcode;
-
- if (cmd->flags & MMC_RSP_PRESENT) {
- sdh_cmd |= CMD_RSP;
- stat_mask |= CMD_RESP_END;
- } else {
- stat_mask |= CMD_SENT;
- }
-
- if (cmd->flags & MMC_RSP_136)
- sdh_cmd |= CMD_L_RSP;
-
- stat_mask |= CMD_CRC_FAIL | CMD_TIME_OUT;
-
- sdh_enable_stat_irq(host, stat_mask);
-
- bfin_write_SDH_ARGUMENT(cmd->arg);
- bfin_write_SDH_COMMAND(sdh_cmd | CMD_E);
- bfin_write_SDH_CLK_CTL(bfin_read_SDH_CLK_CTL() | CLK_E);
- SSYNC();
-}
-
-static void sdh_finish_request(struct sdh_host *host, struct mmc_request *mrq)
-{
- dev_dbg(mmc_dev(host->mmc), "%s enter\n", __func__);
- host->mrq = NULL;
- host->cmd = NULL;
- host->data = NULL;
- mmc_request_done(host->mmc, mrq);
-}
-
-static int sdh_cmd_done(struct sdh_host *host, unsigned int stat)
-{
- struct mmc_command *cmd = host->cmd;
- int ret = 0;
-
- dev_dbg(mmc_dev(host->mmc), "%s enter cmd: %p\n", __func__, cmd);
- if (!cmd)
- return 0;
-
- host->cmd = NULL;
-
- if (cmd->flags & MMC_RSP_PRESENT) {
- cmd->resp[0] = bfin_read_SDH_RESPONSE0();
- if (cmd->flags & MMC_RSP_136) {
- cmd->resp[1] = bfin_read_SDH_RESPONSE1();
- cmd->resp[2] = bfin_read_SDH_RESPONSE2();
- cmd->resp[3] = bfin_read_SDH_RESPONSE3();
- }
- }
- if (stat & CMD_TIME_OUT)
- cmd->error = -ETIMEDOUT;
- else if (stat & CMD_CRC_FAIL && cmd->flags & MMC_RSP_CRC)
- cmd->error = -EILSEQ;
-
- sdh_disable_stat_irq(host, (CMD_SENT | CMD_RESP_END | CMD_TIME_OUT | CMD_CRC_FAIL));
-
- if (host->data && !cmd->error) {
- if (host->data->flags & MMC_DATA_WRITE) {
- ret = sdh_setup_data(host, host->data);
- if (ret)
- return 0;
- }
-
- sdh_enable_stat_irq(host, DAT_END | RX_OVERRUN | TX_UNDERRUN | DAT_TIME_OUT);
- } else
- sdh_finish_request(host, host->mrq);
-
- return 1;
-}
-
-static int sdh_data_done(struct sdh_host *host, unsigned int stat)
-{
- struct mmc_data *data = host->data;
-
- dev_dbg(mmc_dev(host->mmc), "%s enter stat: 0x%x\n", __func__, stat);
- if (!data)
- return 0;
-
- disable_dma(host->dma_ch);
- dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- host->dma_dir);
-
- if (stat & DAT_TIME_OUT)
- data->error = -ETIMEDOUT;
- else if (stat & DAT_CRC_FAIL)
- data->error = -EILSEQ;
- else if (stat & (RX_OVERRUN | TX_UNDERRUN))
- data->error = -EIO;
-
- if (!data->error)
- data->bytes_xfered = data->blocks * data->blksz;
- else
- data->bytes_xfered = 0;
-
- sdh_disable_stat_irq(host, DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL | RX_OVERRUN | TX_UNDERRUN);
- bfin_write_SDH_STATUS_CLR(DAT_END_STAT | DAT_TIMEOUT_STAT | \
- DAT_CRC_FAIL_STAT | DAT_BLK_END_STAT | RX_OVERRUN | TX_UNDERRUN);
- bfin_write_SDH_DATA_CTL(0);
- SSYNC();
-
- host->data = NULL;
- if (host->mrq->stop) {
- sdh_stop_clock(host);
- sdh_start_cmd(host, host->mrq->stop);
- } else {
- sdh_finish_request(host, host->mrq);
- }
-
- return 1;
-}
-
-static void sdh_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct sdh_host *host = mmc_priv(mmc);
- int ret = 0;
-
- dev_dbg(mmc_dev(host->mmc), "%s enter, mrp:%p, cmd:%p\n", __func__, mrq, mrq->cmd);
- WARN_ON(host->mrq != NULL);
-
- host->mrq = mrq;
- host->data = mrq->data;
-
- if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
- ret = sdh_setup_data(host, mrq->data);
- if (ret)
- return;
- }
-
- sdh_start_cmd(host, mrq->cmd);
-}
-
-static void sdh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct sdh_host *host;
- unsigned long flags;
- u16 clk_ctl = 0;
- u16 pwr_ctl = 0;
- u16 cfg;
- host = mmc_priv(mmc);
-
- spin_lock_irqsave(&host->lock, flags);
- if (ios->clock) {
- unsigned long sys_clk, ios_clk;
- unsigned char clk_div;
- ios_clk = 2 * ios->clock;
- sys_clk = get_sclk();
- clk_div = sys_clk / ios_clk;
- if (sys_clk % ios_clk == 0)
- clk_div -= 1;
- clk_div = min_t(unsigned char, clk_div, 0xFF);
- clk_ctl |= clk_div;
- clk_ctl |= CLK_E;
- host->clk_div = clk_div;
- } else
- sdh_stop_clock(host);
-
- if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
-#ifdef CONFIG_SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
- pwr_ctl |= ROD_CTL;
-#else
- pwr_ctl |= SD_CMD_OD | ROD_CTL;
-#endif
-
- if (ios->bus_width == MMC_BUS_WIDTH_4) {
- cfg = bfin_read_SDH_CFG();
- cfg &= ~PD_SDDAT3;
- cfg |= PUP_SDDAT3;
- /* Enable 4 bit SDIO */
- cfg |= (SD4E | MWE);
- bfin_write_SDH_CFG(cfg);
- clk_ctl |= WIDE_BUS;
- } else {
- cfg = bfin_read_SDH_CFG();
- cfg |= MWE;
- bfin_write_SDH_CFG(cfg);
- }
-
- bfin_write_SDH_CLK_CTL(clk_ctl);
-
- host->power_mode = ios->power_mode;
- if (ios->power_mode == MMC_POWER_ON)
- pwr_ctl |= PWR_ON;
-
- bfin_write_SDH_PWR_CTL(pwr_ctl);
- SSYNC();
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- dev_dbg(mmc_dev(host->mmc), "SDH: clk_div = 0x%x actual clock:%ld expected clock:%d\n",
- host->clk_div,
- host->clk_div ? get_sclk() / (2 * (host->clk_div + 1)) : 0,
- ios->clock);
-}
-
-static const struct mmc_host_ops sdh_ops = {
- .request = sdh_request,
- .set_ios = sdh_set_ios,
-};
-
-static irqreturn_t sdh_dma_irq(int irq, void *devid)
-{
- struct sdh_host *host = devid;
-
- dev_dbg(mmc_dev(host->mmc), "%s enter, irq_stat: 0x%04x\n", __func__,
- get_dma_curr_irqstat(host->dma_ch));
- clear_dma_irqstat(host->dma_ch);
- SSYNC();
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t sdh_stat_irq(int irq, void *devid)
-{
- struct sdh_host *host = devid;
- unsigned int status;
- int handled = 0;
-
- dev_dbg(mmc_dev(host->mmc), "%s enter\n", __func__);
- status = bfin_read_SDH_E_STATUS();
- if (status & SD_CARD_DET) {
- mmc_detect_change(host->mmc, 0);
- bfin_write_SDH_E_STATUS(SD_CARD_DET);
- }
- status = bfin_read_SDH_STATUS();
- if (status & (CMD_SENT | CMD_RESP_END | CMD_TIME_OUT | CMD_CRC_FAIL)) {
- handled |= sdh_cmd_done(host, status);
- bfin_write_SDH_STATUS_CLR(CMD_SENT_STAT | CMD_RESP_END_STAT | \
- CMD_TIMEOUT_STAT | CMD_CRC_FAIL_STAT);
- SSYNC();
- }
-
- status = bfin_read_SDH_STATUS();
- if (status & (DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL | RX_OVERRUN | TX_UNDERRUN))
- handled |= sdh_data_done(host, status);
-
- dev_dbg(mmc_dev(host->mmc), "%s exit\n\n", __func__);
-
- return IRQ_RETVAL(handled);
-}
-
-static int __devinit sdh_probe(struct platform_device *pdev)
-{
- struct mmc_host *mmc;
- struct sdh_host *host;
- struct bfin_sd_host *drv_data = get_sdh_data(pdev);
- int ret;
-
- if (!drv_data) {
- dev_err(&pdev->dev, "missing platform driver data\n");
- ret = -EINVAL;
- goto out;
- }
-
- mmc = mmc_alloc_host(sizeof(struct sdh_host), &pdev->dev);
- if (!mmc) {
- ret = -ENOMEM;
- goto out;
- }
-
- mmc->ops = &sdh_ops;
- mmc->max_segs = 32;
- mmc->max_seg_size = 1 << 16;
- mmc->max_blk_size = 1 << 11;
- mmc->max_blk_count = 1 << 11;
- mmc->max_req_size = PAGE_SIZE;
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->f_max = get_sclk();
- mmc->f_min = mmc->f_max >> 9;
- mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_NEEDS_POLL;
- host = mmc_priv(mmc);
- host->mmc = mmc;
-
- spin_lock_init(&host->lock);
- host->irq = drv_data->irq_int0;
- host->dma_ch = drv_data->dma_chan;
-
- ret = request_dma(host->dma_ch, DRIVER_NAME "DMA");
- if (ret) {
- dev_err(&pdev->dev, "unable to request DMA channel\n");
- goto out1;
- }
-
- ret = set_dma_callback(host->dma_ch, sdh_dma_irq, host);
- if (ret) {
- dev_err(&pdev->dev, "unable to request DMA irq\n");
- goto out2;
- }
-
- host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
- if (host->sg_cpu == NULL) {
- ret = -ENOMEM;
- goto out2;
- }
-
- platform_set_drvdata(pdev, mmc);
- mmc_add_host(mmc);
-
- ret = request_irq(host->irq, sdh_stat_irq, 0, "SDH Status IRQ", host);
- if (ret) {
- dev_err(&pdev->dev, "unable to request status irq\n");
- goto out3;
- }
-
- ret = peripheral_request_list(drv_data->pin_req, DRIVER_NAME);
- if (ret) {
- dev_err(&pdev->dev, "unable to request peripheral pins\n");
- goto out4;
- }
-#if defined(CONFIG_BF54x)
- /* Secure Digital Host shares DMA with Nand controller */
- bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1);
-#endif
-
- bfin_write_SDH_CFG(bfin_read_SDH_CFG() | CLKS_EN);
- SSYNC();
-
- /* Disable card inserting detection pin. set MMC_CAP_NEES_POLL, and
- * mmc stack will do the detection.
- */
- bfin_write_SDH_CFG((bfin_read_SDH_CFG() & 0x1F) | (PUP_SDDAT | PUP_SDDAT3));
- SSYNC();
-
- return 0;
-
-out4:
- free_irq(host->irq, host);
-out3:
- mmc_remove_host(mmc);
- dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
-out2:
- free_dma(host->dma_ch);
-out1:
- mmc_free_host(mmc);
- out:
- return ret;
-}
-
-static int __devexit sdh_remove(struct platform_device *pdev)
-{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
-
- platform_set_drvdata(pdev, NULL);
-
- if (mmc) {
- struct sdh_host *host = mmc_priv(mmc);
-
- mmc_remove_host(mmc);
-
- sdh_stop_clock(host);
- free_irq(host->irq, host);
- free_dma(host->dma_ch);
- dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
-
- mmc_free_host(mmc);
- }
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int sdh_suspend(struct platform_device *dev, pm_message_t state)
-{
- struct mmc_host *mmc = platform_get_drvdata(dev);
- struct bfin_sd_host *drv_data = get_sdh_data(dev);
- int ret = 0;
-
- if (mmc)
- ret = mmc_suspend_host(mmc);
-
- bfin_write_SDH_PWR_CTL(bfin_read_SDH_PWR_CTL() & ~PWR_ON);
- peripheral_free_list(drv_data->pin_req);
-
- return ret;
-}
-
-static int sdh_resume(struct platform_device *dev)
-{
- struct mmc_host *mmc = platform_get_drvdata(dev);
- struct bfin_sd_host *drv_data = get_sdh_data(dev);
- int ret = 0;
-
- ret = peripheral_request_list(drv_data->pin_req, DRIVER_NAME);
- if (ret) {
- dev_err(&dev->dev, "unable to request peripheral pins\n");
- return ret;
- }
-
- bfin_write_SDH_PWR_CTL(bfin_read_SDH_PWR_CTL() | PWR_ON);
-#if defined(CONFIG_BF54x)
- /* Secure Digital Host shares DMA with Nand controller */
- bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1);
-#endif
- bfin_write_SDH_CFG(bfin_read_SDH_CFG() | CLKS_EN);
- SSYNC();
-
- bfin_write_SDH_CFG((bfin_read_SDH_CFG() & 0x1F) | (PUP_SDDAT | PUP_SDDAT3));
- SSYNC();
-
- if (mmc)
- ret = mmc_resume_host(mmc);
-
- return ret;
-}
-#else
-# define sdh_suspend NULL
-# define sdh_resume NULL
-#endif
-
-static struct platform_driver sdh_driver = {
- .probe = sdh_probe,
- .remove = __devexit_p(sdh_remove),
- .suspend = sdh_suspend,
- .resume = sdh_resume,
- .driver = {
- .name = DRIVER_NAME,
- },
-};
-
-module_platform_driver(sdh_driver);
-
-MODULE_DESCRIPTION("Blackfin Secure Digital Host Driver");
-MODULE_AUTHOR("Cliff Cai, Roy Huang");
-MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/cb710-mmc.c b/ANDROID_3.4.5/drivers/mmc/host/cb710-mmc.c
deleted file mode 100644
index 83693fd7..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/cb710-mmc.c
+++ /dev/null
@@ -1,788 +0,0 @@
-/*
- * cb710/mmc.c
- *
- * Copyright by Michał Mirosław, 2008-2009
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include "cb710-mmc.h"
-
-static const u8 cb710_clock_divider_log2[8] = {
-/* 1, 2, 4, 8, 16, 32, 128, 512 */
- 0, 1, 2, 3, 4, 5, 7, 9
-};
-#define CB710_MAX_DIVIDER_IDX \
- (ARRAY_SIZE(cb710_clock_divider_log2) - 1)
-
-static const u8 cb710_src_freq_mhz[16] = {
- 33, 10, 20, 25, 30, 35, 40, 45,
- 50, 55, 60, 65, 70, 75, 80, 85
-};
-
-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;
- u32 src_freq_idx;
- u32 divider_idx;
- int src_hz;
-
- /* 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;
-
- for (divider_idx = 0; divider_idx < CB710_MAX_DIVIDER_IDX; ++divider_idx) {
- if (hz >= src_hz >> cb710_clock_divider_log2[divider_idx])
- break;
- }
-
- 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; src_freq_idx = %d, divider_idx = %d|%d\n",
- src_hz >> cb710_clock_divider_log2[divider_idx & 7],
- hz, src_freq_idx, divider_idx & 7, divider_idx & 8);
-}
-
-static void __cb710_mmc_enable_irq(struct cb710_slot *slot,
- unsigned short enable, unsigned short mask)
-{
- /* clear global IE
- * - it gets set later if any interrupt sources are enabled */
- mask |= CB710_MMC_IE_IRQ_ENABLE;
-
- /* look like interrupt is fired whenever
- * WORD[0x0C] & WORD[0x10] != 0;
- * -> bit 15 port 0x0C seems to be global interrupt enable
- */
-
- enable = (cb710_read_port_16(slot, CB710_MMC_IRQ_ENABLE_PORT)
- & ~mask) | enable;
-
- if (enable)
- enable |= CB710_MMC_IE_IRQ_ENABLE;
-
- cb710_write_port_16(slot, CB710_MMC_IRQ_ENABLE_PORT, enable);
-}
-
-static void cb710_mmc_enable_irq(struct cb710_slot *slot,
- unsigned short enable, unsigned short mask)
-{
- struct cb710_mmc_reader *reader = mmc_priv(cb710_slot_to_mmc(slot));
- unsigned long flags;
-
- spin_lock_irqsave(&reader->irq_lock, flags);
- /* this is the only thing irq_lock protects */
- __cb710_mmc_enable_irq(slot, enable, mask);
- spin_unlock_irqrestore(&reader->irq_lock, flags);
-}
-
-static void cb710_mmc_reset_events(struct cb710_slot *slot)
-{
- cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT, 0xFF);
- cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT, 0xFF);
- cb710_write_port_8(slot, CB710_MMC_STATUS2_PORT, 0xFF);
-}
-
-static void cb710_mmc_enable_4bit_data(struct cb710_slot *slot, int enable)
-{
- if (enable)
- cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT,
- CB710_MMC_C1_4BIT_DATA_BUS, 0);
- else
- cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT,
- 0, CB710_MMC_C1_4BIT_DATA_BUS);
-}
-
-static int cb710_check_event(struct cb710_slot *slot, u8 what)
-{
- u16 status;
-
- status = cb710_read_port_16(slot, CB710_MMC_STATUS_PORT);
-
- if (status & CB710_MMC_S0_FIFO_UNDERFLOW) {
- /* it is just a guess, so log it */
- dev_dbg(cb710_slot_dev(slot),
- "CHECK : ignoring bit 6 in status %04X\n", status);
- cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT,
- CB710_MMC_S0_FIFO_UNDERFLOW);
- status &= ~CB710_MMC_S0_FIFO_UNDERFLOW;
- }
-
- if (status & CB710_MMC_STATUS_ERROR_EVENTS) {
- dev_dbg(cb710_slot_dev(slot),
- "CHECK : returning EIO on status %04X\n", status);
- cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT, status & 0xFF);
- cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT,
- CB710_MMC_S1_RESET);
- return -EIO;
- }
-
- /* 'what' is a bit in MMC_STATUS1 */
- if ((status >> 8) & what) {
- cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT, what);
- return 1;
- }
-
- return 0;
-}
-
-static int cb710_wait_for_event(struct cb710_slot *slot, u8 what)
-{
- int err = 0;
- unsigned limit = 2000000; /* FIXME: real timeout */
-
-#ifdef CONFIG_CB710_DEBUG
- u32 e, x;
- e = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT);
-#endif
-
- while (!(err = cb710_check_event(slot, what))) {
- if (!--limit) {
- cb710_dump_regs(cb710_slot_to_chip(slot),
- CB710_DUMP_REGS_MMC);
- err = -ETIMEDOUT;
- break;
- }
- udelay(1);
- }
-
-#ifdef CONFIG_CB710_DEBUG
- x = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT);
-
- limit = 2000000 - limit;
- if (limit > 100)
- dev_dbg(cb710_slot_dev(slot),
- "WAIT10: waited %d loops, what %d, entry val %08X, exit val %08X\n",
- limit, what, e, x);
-#endif
- return err < 0 ? err : 0;
-}
-
-
-static int cb710_wait_while_busy(struct cb710_slot *slot, uint8_t mask)
-{
- unsigned limit = 500000; /* FIXME: real timeout */
- int err = 0;
-
-#ifdef CONFIG_CB710_DEBUG
- u32 e, x;
- e = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT);
-#endif
-
- while (cb710_read_port_8(slot, CB710_MMC_STATUS2_PORT) & mask) {
- if (!--limit) {
- cb710_dump_regs(cb710_slot_to_chip(slot),
- CB710_DUMP_REGS_MMC);
- err = -ETIMEDOUT;
- break;
- }
- udelay(1);
- }
-
-#ifdef CONFIG_CB710_DEBUG
- x = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT);
-
- limit = 500000 - limit;
- if (limit > 100)
- dev_dbg(cb710_slot_dev(slot),
- "WAIT12: waited %d loops, mask %02X, entry val %08X, exit val %08X\n",
- limit, mask, e, x);
-#endif
- return err;
-}
-
-static void cb710_mmc_set_transfer_size(struct cb710_slot *slot,
- size_t count, size_t blocksize)
-{
- cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
- cb710_write_port_32(slot, CB710_MMC_TRANSFER_SIZE_PORT,
- ((count - 1) << 16)|(blocksize - 1));
-
- dev_vdbg(cb710_slot_dev(slot), "set up for %zu block%s of %zu bytes\n",
- count, count == 1 ? "" : "s", blocksize);
-}
-
-static void cb710_mmc_fifo_hack(struct cb710_slot *slot)
-{
- /* without this, received data is prepended with 8-bytes of zeroes */
- u32 r1, r2;
- int ok = 0;
-
- r1 = cb710_read_port_32(slot, CB710_MMC_DATA_PORT);
- r2 = cb710_read_port_32(slot, CB710_MMC_DATA_PORT);
- if (cb710_read_port_8(slot, CB710_MMC_STATUS0_PORT)
- & CB710_MMC_S0_FIFO_UNDERFLOW) {
- cb710_write_port_8(slot, CB710_MMC_STATUS0_PORT,
- CB710_MMC_S0_FIFO_UNDERFLOW);
- ok = 1;
- }
-
- dev_dbg(cb710_slot_dev(slot),
- "FIFO-read-hack: expected STATUS0 bit was %s\n",
- ok ? "set." : "NOT SET!");
- dev_dbg(cb710_slot_dev(slot),
- "FIFO-read-hack: dwords ignored: %08X %08X - %s\n",
- r1, r2, (r1|r2) ? "BAD (NOT ZERO)!" : "ok");
-}
-
-static int cb710_mmc_receive_pio(struct cb710_slot *slot,
- struct sg_mapping_iter *miter, size_t dw_count)
-{
- if (!(cb710_read_port_8(slot, CB710_MMC_STATUS2_PORT) & CB710_MMC_S2_FIFO_READY)) {
- int err = cb710_wait_for_event(slot,
- CB710_MMC_S1_PIO_TRANSFER_DONE);
- if (err)
- return err;
- }
-
- cb710_sg_dwiter_write_from_io(miter,
- slot->iobase + CB710_MMC_DATA_PORT, dw_count);
-
- return 0;
-}
-
-static bool cb710_is_transfer_size_supported(struct mmc_data *data)
-{
- return !(data->blksz & 15 && (data->blocks != 1 || data->blksz != 8));
-}
-
-static int cb710_mmc_receive(struct cb710_slot *slot, struct mmc_data *data)
-{
- struct sg_mapping_iter miter;
- size_t len, blocks = data->blocks;
- int err = 0;
-
- /* TODO: I don't know how/if the hardware handles non-16B-boundary blocks
- * except single 8B block */
- if (unlikely(data->blksz & 15 && (data->blocks != 1 || data->blksz != 8)))
- return -EINVAL;
-
- sg_miter_start(&miter, data->sg, data->sg_len, SG_MITER_TO_SG);
-
- cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT,
- 15, CB710_MMC_C2_READ_PIO_SIZE_MASK);
-
- cb710_mmc_fifo_hack(slot);
-
- while (blocks-- > 0) {
- len = data->blksz;
-
- while (len >= 16) {
- err = cb710_mmc_receive_pio(slot, &miter, 4);
- if (err)
- goto out;
- len -= 16;
- }
-
- if (!len)
- continue;
-
- cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT,
- len - 1, CB710_MMC_C2_READ_PIO_SIZE_MASK);
-
- len = (len >= 8) ? 4 : 2;
- err = cb710_mmc_receive_pio(slot, &miter, len);
- if (err)
- goto out;
- }
-out:
- sg_miter_stop(&miter);
- return err;
-}
-
-static int cb710_mmc_send(struct cb710_slot *slot, struct mmc_data *data)
-{
- struct sg_mapping_iter miter;
- size_t len, blocks = data->blocks;
- int err = 0;
-
- /* TODO: I don't know how/if the hardware handles multiple
- * non-16B-boundary blocks */
- if (unlikely(data->blocks > 1 && data->blksz & 15))
- return -EINVAL;
-
- sg_miter_start(&miter, data->sg, data->sg_len, SG_MITER_FROM_SG);
-
- cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT,
- 0, CB710_MMC_C2_READ_PIO_SIZE_MASK);
-
- while (blocks-- > 0) {
- len = (data->blksz + 15) >> 4;
- do {
- if (!(cb710_read_port_8(slot, CB710_MMC_STATUS2_PORT)
- & CB710_MMC_S2_FIFO_EMPTY)) {
- err = cb710_wait_for_event(slot,
- CB710_MMC_S1_PIO_TRANSFER_DONE);
- if (err)
- goto out;
- }
- cb710_sg_dwiter_read_to_io(&miter,
- slot->iobase + CB710_MMC_DATA_PORT, 4);
- } while (--len);
- }
-out:
- sg_miter_stop(&miter);
- return err;
-}
-
-static u16 cb710_encode_cmd_flags(struct cb710_mmc_reader *reader,
- struct mmc_command *cmd)
-{
- unsigned int flags = cmd->flags;
- u16 cb_flags = 0;
-
- /* Windows driver returned 0 for commands for which no response
- * is expected. It happened that there were only two such commands
- * used: MMC_GO_IDLE_STATE and MMC_GO_INACTIVE_STATE so it might
- * as well be a bug in that driver.
- *
- * Original driver set bit 14 for MMC/SD application
- * commands. There's no difference 'on the wire' and
- * it apparently works without it anyway.
- */
-
- switch (flags & MMC_CMD_MASK) {
- case MMC_CMD_AC: cb_flags = CB710_MMC_CMD_AC; break;
- case MMC_CMD_ADTC: cb_flags = CB710_MMC_CMD_ADTC; break;
- case MMC_CMD_BC: cb_flags = CB710_MMC_CMD_BC; break;
- case MMC_CMD_BCR: cb_flags = CB710_MMC_CMD_BCR; break;
- }
-
- if (flags & MMC_RSP_BUSY)
- cb_flags |= CB710_MMC_RSP_BUSY;
-
- cb_flags |= cmd->opcode << CB710_MMC_CMD_CODE_SHIFT;
-
- if (cmd->data && (cmd->data->flags & MMC_DATA_READ))
- cb_flags |= CB710_MMC_DATA_READ;
-
- if (flags & MMC_RSP_PRESENT) {
- /* Windows driver set 01 at bits 4,3 except for
- * MMC_SET_BLOCKLEN where it set 10. Maybe the
- * hardware can do something special about this
- * command? The original driver looks buggy/incomplete
- * anyway so we ignore this for now.
- *
- * I assume that 00 here means no response is expected.
- */
- cb_flags |= CB710_MMC_RSP_PRESENT;
-
- if (flags & MMC_RSP_136)
- cb_flags |= CB710_MMC_RSP_136;
- if (!(flags & MMC_RSP_CRC))
- cb_flags |= CB710_MMC_RSP_NO_CRC;
- }
-
- return cb_flags;
-}
-
-static void cb710_receive_response(struct cb710_slot *slot,
- struct mmc_command *cmd)
-{
- unsigned rsp_opcode, wanted_opcode;
-
- /* Looks like final byte with CRC is always stripped (same as SDHCI) */
- if (cmd->flags & MMC_RSP_136) {
- u32 resp[4];
-
- resp[0] = cb710_read_port_32(slot, CB710_MMC_RESPONSE3_PORT);
- resp[1] = cb710_read_port_32(slot, CB710_MMC_RESPONSE2_PORT);
- resp[2] = cb710_read_port_32(slot, CB710_MMC_RESPONSE1_PORT);
- resp[3] = cb710_read_port_32(slot, CB710_MMC_RESPONSE0_PORT);
- rsp_opcode = resp[0] >> 24;
-
- cmd->resp[0] = (resp[0] << 8)|(resp[1] >> 24);
- cmd->resp[1] = (resp[1] << 8)|(resp[2] >> 24);
- cmd->resp[2] = (resp[2] << 8)|(resp[3] >> 24);
- cmd->resp[3] = (resp[3] << 8);
- } else {
- rsp_opcode = cb710_read_port_32(slot, CB710_MMC_RESPONSE1_PORT) & 0x3F;
- cmd->resp[0] = cb710_read_port_32(slot, CB710_MMC_RESPONSE0_PORT);
- }
-
- wanted_opcode = (cmd->flags & MMC_RSP_OPCODE) ? cmd->opcode : 0x3F;
- if (rsp_opcode != wanted_opcode)
- cmd->error = -EILSEQ;
-}
-
-static int cb710_mmc_transfer_data(struct cb710_slot *slot,
- struct mmc_data *data)
-{
- int error, to;
-
- if (data->flags & MMC_DATA_READ)
- error = cb710_mmc_receive(slot, data);
- else
- error = cb710_mmc_send(slot, data);
-
- to = cb710_wait_for_event(slot, CB710_MMC_S1_DATA_TRANSFER_DONE);
- if (!error)
- error = to;
-
- if (!error)
- data->bytes_xfered = data->blksz * data->blocks;
- return error;
-}
-
-static int cb710_mmc_command(struct mmc_host *mmc, struct mmc_command *cmd)
-{
- struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
- struct cb710_mmc_reader *reader = mmc_priv(mmc);
- struct mmc_data *data = cmd->data;
-
- u16 cb_cmd = cb710_encode_cmd_flags(reader, cmd);
- dev_dbg(cb710_slot_dev(slot), "cmd request: 0x%04X\n", cb_cmd);
-
- if (data) {
- if (!cb710_is_transfer_size_supported(data)) {
- data->error = -EINVAL;
- return -1;
- }
- cb710_mmc_set_transfer_size(slot, data->blocks, data->blksz);
- }
-
- cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20|CB710_MMC_S2_BUSY_10);
- cb710_write_port_16(slot, CB710_MMC_CMD_TYPE_PORT, cb_cmd);
- cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
- cb710_write_port_32(slot, CB710_MMC_CMD_PARAM_PORT, cmd->arg);
- cb710_mmc_reset_events(slot);
- cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
- cb710_modify_port_8(slot, CB710_MMC_CONFIG0_PORT, 0x01, 0);
-
- cmd->error = cb710_wait_for_event(slot, CB710_MMC_S1_COMMAND_SENT);
- if (cmd->error)
- return -1;
-
- if (cmd->flags & MMC_RSP_PRESENT) {
- cb710_receive_response(slot, cmd);
- if (cmd->error)
- return -1;
- }
-
- if (data)
- data->error = cb710_mmc_transfer_data(slot, data);
- return 0;
-}
-
-static void cb710_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
- struct cb710_mmc_reader *reader = mmc_priv(mmc);
-
- WARN_ON(reader->mrq != NULL);
-
- reader->mrq = mrq;
- cb710_mmc_enable_irq(slot, CB710_MMC_IE_TEST_MASK, 0);
-
- if (!cb710_mmc_command(mmc, mrq->cmd) && mrq->stop)
- cb710_mmc_command(mmc, mrq->stop);
-
- tasklet_schedule(&reader->finish_req_tasklet);
-}
-
-static int cb710_mmc_powerup(struct cb710_slot *slot)
-{
-#ifdef CONFIG_CB710_DEBUG
- struct cb710_chip *chip = cb710_slot_to_chip(slot);
-#endif
- int err;
-
- /* 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);
- if (unlikely(err))
- return err;
- cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0x80, 0);
- cb710_modify_port_8(slot, CB710_MMC_CONFIG3_PORT, 0x80, 0);
- cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
- mdelay(1);
- dev_dbg(cb710_slot_dev(slot), "after delay 1\n");
- cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
- err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
- if (unlikely(err))
- return err;
- cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0x09, 0);
- cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
- mdelay(1);
- dev_dbg(cb710_slot_dev(slot), "after delay 2\n");
- cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
- err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
- if (unlikely(err))
- return err;
- cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0, 0x08);
- cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
- mdelay(2);
- dev_dbg(cb710_slot_dev(slot), "after delay 3\n");
- cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
- cb710_modify_port_8(slot, CB710_MMC_CONFIG0_PORT, 0x06, 0);
- cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0x70, 0);
- cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT, 0x80, 0);
- cb710_modify_port_8(slot, CB710_MMC_CONFIG3_PORT, 0x03, 0);
- cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
- err = cb710_wait_while_busy(slot, CB710_MMC_S2_BUSY_20);
- if (unlikely(err))
- return err;
- /* This port behaves weird: quick byte reads of 0x08,0x09 return
- * 0xFF,0x00 after writing 0xFFFF to 0x08; it works correctly when
- * read/written from userspace... What am I missing here?
- * (it doesn't depend on write-to-read delay) */
- cb710_write_port_16(slot, CB710_MMC_CONFIGB_PORT, 0xFFFF);
- cb710_modify_port_8(slot, CB710_MMC_CONFIG0_PORT, 0x06, 0);
- cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
- dev_dbg(cb710_slot_dev(slot), "bus powerup finished\n");
-
- return cb710_check_event(slot, 0);
-}
-
-static void cb710_mmc_powerdown(struct cb710_slot *slot)
-{
- cb710_modify_port_8(slot, CB710_MMC_CONFIG1_PORT, 0, 0x81);
- cb710_modify_port_8(slot, CB710_MMC_CONFIG3_PORT, 0, 0x80);
-}
-
-static void cb710_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct cb710_slot *slot = cb710_mmc_to_slot(mmc);
- struct cb710_mmc_reader *reader = mmc_priv(mmc);
- int err;
-
- cb710_mmc_select_clock_divider(mmc, ios->clock);
-
- if (ios->power_mode != reader->last_power_mode)
- switch (ios->power_mode) {
- case MMC_POWER_ON:
- err = cb710_mmc_powerup(slot);
- if (err) {
- dev_warn(cb710_slot_dev(slot),
- "powerup failed (%d)- retrying\n", err);
- cb710_mmc_powerdown(slot);
- udelay(1);
- err = cb710_mmc_powerup(slot);
- if (err)
- dev_warn(cb710_slot_dev(slot),
- "powerup retry failed (%d) - expect errors\n",
- err);
- }
- reader->last_power_mode = MMC_POWER_ON;
- break;
- case MMC_POWER_OFF:
- cb710_mmc_powerdown(slot);
- reader->last_power_mode = MMC_POWER_OFF;
- break;
- case MMC_POWER_UP:
- default:
- /* ignore */;
- }
-
- cb710_mmc_enable_4bit_data(slot, ios->bus_width != MMC_BUS_WIDTH_1);
-
- cb710_mmc_enable_irq(slot, CB710_MMC_IE_TEST_MASK, 0);
-}
-
-static int cb710_mmc_get_ro(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_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);
- struct cb710_mmc_reader *reader = mmc_priv(mmc);
- u32 status, config1, config2, irqen;
-
- status = cb710_read_port_32(slot, CB710_MMC_STATUS_PORT);
- irqen = cb710_read_port_32(slot, CB710_MMC_IRQ_ENABLE_PORT);
- config2 = cb710_read_port_32(slot, CB710_MMC_CONFIGB_PORT);
- config1 = cb710_read_port_32(slot, CB710_MMC_CONFIG_PORT);
-
- dev_dbg(cb710_slot_dev(slot), "interrupt; status: %08X, "
- "ie: %08X, c2: %08X, c1: %08X\n",
- status, irqen, config2, config1);
-
- if (status & (CB710_MMC_S1_CARD_CHANGED << 8)) {
- /* ack the event */
- cb710_write_port_8(slot, CB710_MMC_STATUS1_PORT,
- CB710_MMC_S1_CARD_CHANGED);
- if ((irqen & CB710_MMC_IE_CISTATUS_MASK)
- == CB710_MMC_IE_CISTATUS_MASK)
- mmc_detect_change(mmc, HZ/5);
- } else {
- dev_dbg(cb710_slot_dev(slot), "unknown interrupt (test)\n");
- spin_lock(&reader->irq_lock);
- __cb710_mmc_enable_irq(slot, 0, CB710_MMC_IE_TEST_MASK);
- spin_unlock(&reader->irq_lock);
- }
-
- return 1;
-}
-
-static void cb710_mmc_finish_request_tasklet(unsigned long data)
-{
- struct mmc_host *mmc = (void *)data;
- struct cb710_mmc_reader *reader = mmc_priv(mmc);
- struct mmc_request *mrq = reader->mrq;
-
- reader->mrq = NULL;
- mmc_request_done(mmc, mrq);
-}
-
-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_cd = cb710_mmc_get_cd,
-};
-
-#ifdef CONFIG_PM
-
-static int cb710_mmc_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct cb710_slot *slot = cb710_pdev_to_slot(pdev);
- struct mmc_host *mmc = cb710_slot_to_mmc(slot);
- int err;
-
- err = mmc_suspend_host(mmc);
- if (err)
- return err;
-
- cb710_mmc_enable_irq(slot, 0, ~0);
- return 0;
-}
-
-static int cb710_mmc_resume(struct platform_device *pdev)
-{
- struct cb710_slot *slot = cb710_pdev_to_slot(pdev);
- struct mmc_host *mmc = cb710_slot_to_mmc(slot);
-
- cb710_mmc_enable_irq(slot, 0, ~0);
-
- return mmc_resume_host(mmc);
-}
-
-#endif /* CONFIG_PM */
-
-static int __devinit cb710_mmc_init(struct platform_device *pdev)
-{
- struct cb710_slot *slot = cb710_pdev_to_slot(pdev);
- struct cb710_chip *chip = cb710_slot_to_chip(slot);
- struct mmc_host *mmc;
- struct cb710_mmc_reader *reader;
- int err;
- u32 val;
-
- mmc = mmc_alloc_host(sizeof(*reader), cb710_slot_dev(slot));
- if (!mmc)
- return -ENOMEM;
-
- dev_set_drvdata(&pdev->dev, mmc);
-
- /* harmless (maybe) magic */
- pci_read_config_dword(chip->pdev, 0x48, &val);
- val = cb710_src_freq_mhz[(val >> 16) & 0xF];
- dev_dbg(cb710_slot_dev(slot), "source frequency: %dMHz\n", val);
- val *= 1000000;
-
- mmc->ops = &cb710_mmc_host;
- mmc->f_max = val;
- mmc->f_min = val >> cb710_clock_divider_log2[CB710_MAX_DIVIDER_IDX];
- mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
- mmc->caps = MMC_CAP_4_BIT_DATA;
-
- reader = mmc_priv(mmc);
-
- tasklet_init(&reader->finish_req_tasklet,
- cb710_mmc_finish_request_tasklet, (unsigned long)mmc);
- spin_lock_init(&reader->irq_lock);
- cb710_dump_regs(chip, CB710_DUMP_REGS_MMC);
-
- cb710_mmc_enable_irq(slot, 0, ~0);
- cb710_set_irq_handler(slot, cb710_mmc_irq_handler);
-
- err = mmc_add_host(mmc);
- if (unlikely(err))
- goto err_free_mmc;
-
- dev_dbg(cb710_slot_dev(slot), "mmc_hostname is %s\n",
- mmc_hostname(mmc));
-
- cb710_mmc_enable_irq(slot, CB710_MMC_IE_CARD_INSERTION_STATUS, 0);
-
- return 0;
-
-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;
-}
-
-static int __devexit cb710_mmc_exit(struct platform_device *pdev)
-{
- struct cb710_slot *slot = cb710_pdev_to_slot(pdev);
- struct mmc_host *mmc = cb710_slot_to_mmc(slot);
- struct cb710_mmc_reader *reader = mmc_priv(mmc);
-
- cb710_mmc_enable_irq(slot, 0, CB710_MMC_IE_CARD_INSERTION_STATUS);
-
- mmc_remove_host(mmc);
-
- /* IRQs should be disabled now, but let's stay on the safe side */
- cb710_mmc_enable_irq(slot, 0, ~0);
- cb710_set_irq_handler(slot, NULL);
-
- /* clear config ports - just in case */
- cb710_write_port_32(slot, CB710_MMC_CONFIG_PORT, 0);
- cb710_write_port_16(slot, CB710_MMC_CONFIGB_PORT, 0);
-
- tasklet_kill(&reader->finish_req_tasklet);
-
- mmc_free_host(mmc);
- return 0;
-}
-
-static struct platform_driver cb710_mmc_driver = {
- .driver.name = "cb710-mmc",
- .probe = cb710_mmc_init,
- .remove = __devexit_p(cb710_mmc_exit),
-#ifdef CONFIG_PM
- .suspend = cb710_mmc_suspend,
- .resume = cb710_mmc_resume,
-#endif
-};
-
-module_platform_driver(cb710_mmc_driver);
-
-MODULE_AUTHOR("Michał Mirosław <mirq-linux@rere.qmqm.pl>");
-MODULE_DESCRIPTION("ENE CB710 memory card reader driver - MMC/SD part");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:cb710-mmc");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/cb710-mmc.h b/ANDROID_3.4.5/drivers/mmc/host/cb710-mmc.h
deleted file mode 100644
index e845c776..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/cb710-mmc.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * cb710/cb710-mmc.h
- *
- * Copyright by Michał Mirosław, 2008-2009
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#ifndef LINUX_CB710_MMC_H
-#define LINUX_CB710_MMC_H
-
-#include <linux/cb710.h>
-
-/* per-MMC-reader structure */
-struct cb710_mmc_reader {
- struct tasklet_struct finish_req_tasklet;
- struct mmc_request *mrq;
- spinlock_t irq_lock;
- unsigned char last_power_mode;
-};
-
-/* some device struct walking */
-
-static inline struct mmc_host *cb710_slot_to_mmc(struct cb710_slot *slot)
-{
- return dev_get_drvdata(&slot->pdev.dev);
-}
-
-static inline struct cb710_slot *cb710_mmc_to_slot(struct mmc_host *mmc)
-{
- struct platform_device *pdev = container_of(mmc_dev(mmc),
- struct platform_device, dev);
- return cb710_pdev_to_slot(pdev);
-}
-
-/* registers (this might be all wrong ;) */
-
-#define CB710_MMC_DATA_PORT 0x00
-
-#define CB710_MMC_CONFIG_PORT 0x04
-#define CB710_MMC_CONFIG0_PORT 0x04
-#define CB710_MMC_CONFIG1_PORT 0x05
-#define CB710_MMC_C1_4BIT_DATA_BUS 0x40
-#define CB710_MMC_CONFIG2_PORT 0x06
-#define CB710_MMC_C2_READ_PIO_SIZE_MASK 0x0F /* N-1 */
-#define CB710_MMC_CONFIG3_PORT 0x07
-
-#define CB710_MMC_CONFIGB_PORT 0x08
-
-#define CB710_MMC_IRQ_ENABLE_PORT 0x0C
-#define CB710_MMC_IE_TEST_MASK 0x00BF
-#define CB710_MMC_IE_CARD_INSERTION_STATUS 0x1000
-#define CB710_MMC_IE_IRQ_ENABLE 0x8000
-#define CB710_MMC_IE_CISTATUS_MASK \
- (CB710_MMC_IE_CARD_INSERTION_STATUS|CB710_MMC_IE_IRQ_ENABLE)
-
-#define CB710_MMC_STATUS_PORT 0x10
-#define CB710_MMC_STATUS_ERROR_EVENTS 0x60FF
-#define CB710_MMC_STATUS0_PORT 0x10
-#define CB710_MMC_S0_FIFO_UNDERFLOW 0x40
-#define CB710_MMC_STATUS1_PORT 0x11
-#define CB710_MMC_S1_COMMAND_SENT 0x01
-#define CB710_MMC_S1_DATA_TRANSFER_DONE 0x02
-#define CB710_MMC_S1_PIO_TRANSFER_DONE 0x04
-#define CB710_MMC_S1_CARD_CHANGED 0x10
-#define CB710_MMC_S1_RESET 0x20
-#define CB710_MMC_STATUS2_PORT 0x12
-#define CB710_MMC_S2_FIFO_READY 0x01
-#define CB710_MMC_S2_FIFO_EMPTY 0x02
-#define CB710_MMC_S2_BUSY_10 0x10
-#define CB710_MMC_S2_BUSY_20 0x20
-#define CB710_MMC_STATUS3_PORT 0x13
-#define CB710_MMC_S3_CARD_DETECTED 0x02
-#define CB710_MMC_S3_WRITE_PROTECTED 0x04
-
-#define CB710_MMC_CMD_TYPE_PORT 0x14
-#define CB710_MMC_RSP_TYPE_MASK 0x0007
-#define CB710_MMC_RSP_R1 (0)
-#define CB710_MMC_RSP_136 (5)
-#define CB710_MMC_RSP_NO_CRC (2)
-#define CB710_MMC_RSP_PRESENT_MASK 0x0018
-#define CB710_MMC_RSP_NONE (0 << 3)
-#define CB710_MMC_RSP_PRESENT (1 << 3)
-#define CB710_MMC_RSP_PRESENT_X (2 << 3)
-#define CB710_MMC_CMD_TYPE_MASK 0x0060
-#define CB710_MMC_CMD_BC (0 << 5)
-#define CB710_MMC_CMD_BCR (1 << 5)
-#define CB710_MMC_CMD_AC (2 << 5)
-#define CB710_MMC_CMD_ADTC (3 << 5)
-#define CB710_MMC_DATA_READ 0x0080
-#define CB710_MMC_CMD_CODE_MASK 0x3F00
-#define CB710_MMC_CMD_CODE_SHIFT 8
-#define CB710_MMC_IS_APP_CMD 0x4000
-#define CB710_MMC_RSP_BUSY 0x8000
-
-#define CB710_MMC_CMD_PARAM_PORT 0x18
-#define CB710_MMC_TRANSFER_SIZE_PORT 0x1C
-#define CB710_MMC_RESPONSE0_PORT 0x20
-#define CB710_MMC_RESPONSE1_PORT 0x24
-#define CB710_MMC_RESPONSE2_PORT 0x28
-#define CB710_MMC_RESPONSE3_PORT 0x2C
-
-#endif /* LINUX_CB710_MMC_H */
diff --git a/ANDROID_3.4.5/drivers/mmc/host/davinci_mmc.c b/ANDROID_3.4.5/drivers/mmc/host/davinci_mmc.c
deleted file mode 100644
index c1f3673a..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/davinci_mmc.c
+++ /dev/null
@@ -1,1536 +0,0 @@
-/*
- * davinci_mmc.c - TI DaVinci MMC/SD/SDIO driver
- *
- * Copyright (C) 2006 Texas Instruments.
- * Original author: Purushotam Kumar
- * Copyright (C) 2009 David Brownell
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/cpufreq.h>
-#include <linux/mmc/host.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/mmc/mmc.h>
-
-#include <mach/mmc.h>
-#include <mach/edma.h>
-
-/*
- * Register Definitions
- */
-#define DAVINCI_MMCCTL 0x00 /* Control Register */
-#define DAVINCI_MMCCLK 0x04 /* Memory Clock Control Register */
-#define DAVINCI_MMCST0 0x08 /* Status Register 0 */
-#define DAVINCI_MMCST1 0x0C /* Status Register 1 */
-#define DAVINCI_MMCIM 0x10 /* Interrupt Mask Register */
-#define DAVINCI_MMCTOR 0x14 /* Response Time-Out Register */
-#define DAVINCI_MMCTOD 0x18 /* Data Read Time-Out Register */
-#define DAVINCI_MMCBLEN 0x1C /* Block Length Register */
-#define DAVINCI_MMCNBLK 0x20 /* Number of Blocks Register */
-#define DAVINCI_MMCNBLC 0x24 /* Number of Blocks Counter Register */
-#define DAVINCI_MMCDRR 0x28 /* Data Receive Register */
-#define DAVINCI_MMCDXR 0x2C /* Data Transmit Register */
-#define DAVINCI_MMCCMD 0x30 /* Command Register */
-#define DAVINCI_MMCARGHL 0x34 /* Argument Register */
-#define DAVINCI_MMCRSP01 0x38 /* Response Register 0 and 1 */
-#define DAVINCI_MMCRSP23 0x3C /* Response Register 0 and 1 */
-#define DAVINCI_MMCRSP45 0x40 /* Response Register 0 and 1 */
-#define DAVINCI_MMCRSP67 0x44 /* Response Register 0 and 1 */
-#define DAVINCI_MMCDRSP 0x48 /* Data Response Register */
-#define DAVINCI_MMCETOK 0x4C
-#define DAVINCI_MMCCIDX 0x50 /* Command Index Register */
-#define DAVINCI_MMCCKC 0x54
-#define DAVINCI_MMCTORC 0x58
-#define DAVINCI_MMCTODC 0x5C
-#define DAVINCI_MMCBLNC 0x60
-#define DAVINCI_SDIOCTL 0x64
-#define DAVINCI_SDIOST0 0x68
-#define DAVINCI_SDIOIEN 0x6C
-#define DAVINCI_SDIOIST 0x70
-#define DAVINCI_MMCFIFOCTL 0x74 /* FIFO Control Register */
-
-/* DAVINCI_MMCCTL definitions */
-#define MMCCTL_DATRST (1 << 0)
-#define MMCCTL_CMDRST (1 << 1)
-#define MMCCTL_WIDTH_8_BIT (1 << 8)
-#define MMCCTL_WIDTH_4_BIT (1 << 2)
-#define MMCCTL_DATEG_DISABLED (0 << 6)
-#define MMCCTL_DATEG_RISING (1 << 6)
-#define MMCCTL_DATEG_FALLING (2 << 6)
-#define MMCCTL_DATEG_BOTH (3 << 6)
-#define MMCCTL_PERMDR_LE (0 << 9)
-#define MMCCTL_PERMDR_BE (1 << 9)
-#define MMCCTL_PERMDX_LE (0 << 10)
-#define MMCCTL_PERMDX_BE (1 << 10)
-
-/* DAVINCI_MMCCLK definitions */
-#define MMCCLK_CLKEN (1 << 8)
-#define MMCCLK_CLKRT_MASK (0xFF << 0)
-
-/* IRQ bit definitions, for DAVINCI_MMCST0 and DAVINCI_MMCIM */
-#define MMCST0_DATDNE BIT(0) /* data done */
-#define MMCST0_BSYDNE BIT(1) /* busy done */
-#define MMCST0_RSPDNE BIT(2) /* command done */
-#define MMCST0_TOUTRD BIT(3) /* data read timeout */
-#define MMCST0_TOUTRS BIT(4) /* command response timeout */
-#define MMCST0_CRCWR BIT(5) /* data write CRC error */
-#define MMCST0_CRCRD BIT(6) /* data read CRC error */
-#define MMCST0_CRCRS BIT(7) /* command response CRC error */
-#define MMCST0_DXRDY BIT(9) /* data transmit ready (fifo empty) */
-#define MMCST0_DRRDY BIT(10) /* data receive ready (data in fifo)*/
-#define MMCST0_DATED BIT(11) /* DAT3 edge detect */
-#define MMCST0_TRNDNE BIT(12) /* transfer done */
-
-/* DAVINCI_MMCST1 definitions */
-#define MMCST1_BUSY (1 << 0)
-
-/* DAVINCI_MMCCMD definitions */
-#define MMCCMD_CMD_MASK (0x3F << 0)
-#define MMCCMD_PPLEN (1 << 7)
-#define MMCCMD_BSYEXP (1 << 8)
-#define MMCCMD_RSPFMT_MASK (3 << 9)
-#define MMCCMD_RSPFMT_NONE (0 << 9)
-#define MMCCMD_RSPFMT_R1456 (1 << 9)
-#define MMCCMD_RSPFMT_R2 (2 << 9)
-#define MMCCMD_RSPFMT_R3 (3 << 9)
-#define MMCCMD_DTRW (1 << 11)
-#define MMCCMD_STRMTP (1 << 12)
-#define MMCCMD_WDATX (1 << 13)
-#define MMCCMD_INITCK (1 << 14)
-#define MMCCMD_DCLR (1 << 15)
-#define MMCCMD_DMATRIG (1 << 16)
-
-/* DAVINCI_MMCFIFOCTL definitions */
-#define MMCFIFOCTL_FIFORST (1 << 0)
-#define MMCFIFOCTL_FIFODIR_WR (1 << 1)
-#define MMCFIFOCTL_FIFODIR_RD (0 << 1)
-#define MMCFIFOCTL_FIFOLEV (1 << 2) /* 0 = 128 bits, 1 = 256 bits */
-#define MMCFIFOCTL_ACCWD_4 (0 << 3) /* access width of 4 bytes */
-#define MMCFIFOCTL_ACCWD_3 (1 << 3) /* access width of 3 bytes */
-#define MMCFIFOCTL_ACCWD_2 (2 << 3) /* access width of 2 bytes */
-#define MMCFIFOCTL_ACCWD_1 (3 << 3) /* access width of 1 byte */
-
-/* DAVINCI_SDIOST0 definitions */
-#define SDIOST0_DAT1_HI BIT(0)
-
-/* DAVINCI_SDIOIEN definitions */
-#define SDIOIEN_IOINTEN BIT(0)
-
-/* DAVINCI_SDIOIST definitions */
-#define SDIOIST_IOINT BIT(0)
-
-/* MMCSD Init clock in Hz in opendrain mode */
-#define MMCSD_INIT_CLOCK 200000
-
-/*
- * 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_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.
- */
-#define MAX_CCNT ((1 << 16) - 1)
-
-#define MAX_NR_SG 16
-
-static unsigned rw_threshold = 32;
-module_param(rw_threshold, uint, S_IRUGO);
-MODULE_PARM_DESC(rw_threshold,
- "Read/Write threshold. Default = 32");
-
-static unsigned poll_threshold = 128;
-module_param(poll_threshold, uint, S_IRUGO);
-MODULE_PARM_DESC(poll_threshold,
- "Polling transaction size threshold. Default = 128");
-
-static unsigned poll_loopcount = 32;
-module_param(poll_loopcount, uint, S_IRUGO);
-MODULE_PARM_DESC(poll_loopcount,
- "Maximum polling loop count. Default = 32");
-
-static unsigned __initdata use_dma = 1;
-module_param(use_dma, uint, 0);
-MODULE_PARM_DESC(use_dma, "Whether to use DMA or not. Default = 1");
-
-struct mmc_davinci_host {
- struct mmc_command *cmd;
- struct mmc_data *data;
- struct mmc_host *mmc;
- struct clk *clk;
- unsigned int mmc_input_clk;
- void __iomem *base;
- struct resource *mem_res;
- int mmc_irq, sdio_irq;
- unsigned char bus_mode;
-
-#define DAVINCI_MMC_DATADIR_NONE 0
-#define DAVINCI_MMC_DATADIR_READ 1
-#define DAVINCI_MMC_DATADIR_WRITE 2
- unsigned char data_dir;
- unsigned char suspended;
-
- /* buffer is used during PIO of one scatterlist segment, and
- * is updated along with buffer_bytes_left. bytes_left applies
- * to all N blocks of the PIO transfer.
- */
- u8 *buffer;
- u32 buffer_bytes_left;
- u32 bytes_left;
-
- u32 rxdma, txdma;
- bool use_dma;
- bool do_dma;
- bool sdio_int;
- bool active_request;
-
- /* Scatterlist DMA uses one or more parameter RAM entries:
- * the main one (associated with rxdma or txdma) plus zero or
- * more links. The entries for a given transfer differ only
- * by memory buffer (address, length) and link field.
- */
- struct edmacc_param tx_template;
- struct edmacc_param rx_template;
- unsigned n_link;
- u32 links[MAX_NR_SG - 1];
-
- /* For PIO we walk scatterlists one segment at a time. */
- unsigned int sg_len;
- struct scatterlist *sg;
-
- /* Version of the MMC/SD controller */
- u8 version;
- /* for ns in one cycle calculation */
- unsigned ns_in_one_cycle;
- /* Number of sg segments */
- u8 nr_sg;
-#ifdef CONFIG_CPU_FREQ
- struct notifier_block freq_transition;
-#endif
-};
-
-static irqreturn_t mmc_davinci_irq(int irq, void *dev_id);
-
-/* PIO only */
-static void mmc_davinci_sg_to_buf(struct mmc_davinci_host *host)
-{
- host->buffer_bytes_left = sg_dma_len(host->sg);
- host->buffer = sg_virt(host->sg);
- if (host->buffer_bytes_left > host->bytes_left)
- host->buffer_bytes_left = host->bytes_left;
-}
-
-static void davinci_fifo_data_trans(struct mmc_davinci_host *host,
- unsigned int n)
-{
- u8 *p;
- unsigned int i;
-
- if (host->buffer_bytes_left == 0) {
- host->sg = sg_next(host->data->sg);
- mmc_davinci_sg_to_buf(host);
- }
-
- p = host->buffer;
- if (n > host->buffer_bytes_left)
- n = host->buffer_bytes_left;
- host->buffer_bytes_left -= n;
- host->bytes_left -= n;
-
- /* NOTE: we never transfer more than rw_threshold bytes
- * to/from the fifo here; there's no I/O overlap.
- * This also assumes that access width( i.e. ACCWD) is 4 bytes
- */
- if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) {
- for (i = 0; i < (n >> 2); i++) {
- writel(*((u32 *)p), host->base + DAVINCI_MMCDXR);
- p = p + 4;
- }
- if (n & 3) {
- iowrite8_rep(host->base + DAVINCI_MMCDXR, p, (n & 3));
- p = p + (n & 3);
- }
- } else {
- for (i = 0; i < (n >> 2); i++) {
- *((u32 *)p) = readl(host->base + DAVINCI_MMCDRR);
- p = p + 4;
- }
- if (n & 3) {
- ioread8_rep(host->base + DAVINCI_MMCDRR, p, (n & 3));
- p = p + (n & 3);
- }
- }
- host->buffer = p;
-}
-
-static void mmc_davinci_start_command(struct mmc_davinci_host *host,
- struct mmc_command *cmd)
-{
- u32 cmd_reg = 0;
- u32 im_val;
-
- dev_dbg(mmc_dev(host->mmc), "CMD%d, arg 0x%08x%s\n",
- cmd->opcode, cmd->arg,
- ({ char *s;
- switch (mmc_resp_type(cmd)) {
- case MMC_RSP_R1:
- s = ", R1/R5/R6/R7 response";
- break;
- case MMC_RSP_R1B:
- s = ", R1b response";
- break;
- case MMC_RSP_R2:
- s = ", R2 response";
- break;
- case MMC_RSP_R3:
- s = ", R3/R4 response";
- break;
- default:
- s = ", (R? response)";
- break;
- }; s; }));
- host->cmd = cmd;
-
- switch (mmc_resp_type(cmd)) {
- case MMC_RSP_R1B:
- /* There's some spec confusion about when R1B is
- * allowed, but if the card doesn't issue a BUSY
- * then it's harmless for us to allow it.
- */
- cmd_reg |= MMCCMD_BSYEXP;
- /* FALLTHROUGH */
- case MMC_RSP_R1: /* 48 bits, CRC */
- cmd_reg |= MMCCMD_RSPFMT_R1456;
- break;
- case MMC_RSP_R2: /* 136 bits, CRC */
- cmd_reg |= MMCCMD_RSPFMT_R2;
- break;
- case MMC_RSP_R3: /* 48 bits, no CRC */
- cmd_reg |= MMCCMD_RSPFMT_R3;
- break;
- default:
- cmd_reg |= MMCCMD_RSPFMT_NONE;
- dev_dbg(mmc_dev(host->mmc), "unknown resp_type %04x\n",
- mmc_resp_type(cmd));
- break;
- }
-
- /* Set command index */
- cmd_reg |= cmd->opcode;
-
- /* Enable EDMA transfer triggers */
- if (host->do_dma)
- cmd_reg |= MMCCMD_DMATRIG;
-
- if (host->version == MMC_CTLR_VERSION_2 && host->data != NULL &&
- host->data_dir == DAVINCI_MMC_DATADIR_READ)
- cmd_reg |= MMCCMD_DMATRIG;
-
- /* Setting whether command involves data transfer or not */
- if (cmd->data)
- cmd_reg |= MMCCMD_WDATX;
-
- /* Setting whether stream or block transfer */
- if (cmd->flags & MMC_DATA_STREAM)
- cmd_reg |= MMCCMD_STRMTP;
-
- /* Setting whether data read or write */
- if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE)
- cmd_reg |= MMCCMD_DTRW;
-
- if (host->bus_mode == MMC_BUSMODE_PUSHPULL)
- cmd_reg |= MMCCMD_PPLEN;
-
- /* set Command timeout */
- writel(0x1FFF, host->base + DAVINCI_MMCTOR);
-
- /* Enable interrupt (calculate here, defer until FIFO is stuffed). */
- im_val = MMCST0_RSPDNE | MMCST0_CRCRS | MMCST0_TOUTRS;
- if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) {
- im_val |= MMCST0_DATDNE | MMCST0_CRCWR;
-
- if (!host->do_dma)
- im_val |= MMCST0_DXRDY;
- } else if (host->data_dir == DAVINCI_MMC_DATADIR_READ) {
- im_val |= MMCST0_DATDNE | MMCST0_CRCRD | MMCST0_TOUTRD;
-
- if (!host->do_dma)
- im_val |= MMCST0_DRRDY;
- }
-
- /*
- * Before non-DMA WRITE commands the controller needs priming:
- * FIFO should be populated with 32 bytes i.e. whatever is the FIFO size
- */
- if (!host->do_dma && (host->data_dir == DAVINCI_MMC_DATADIR_WRITE))
- davinci_fifo_data_trans(host, rw_threshold);
-
- writel(cmd->arg, host->base + DAVINCI_MMCARGHL);
- writel(cmd_reg, host->base + DAVINCI_MMCCMD);
-
- host->active_request = true;
-
- if (!host->do_dma && host->bytes_left <= poll_threshold) {
- u32 count = poll_loopcount;
-
- while (host->active_request && count--) {
- mmc_davinci_irq(0, host);
- cpu_relax();
- }
- }
-
- if (host->active_request)
- writel(im_val, host->base + DAVINCI_MMCIM);
-}
-
-/*----------------------------------------------------------------------*/
-
-/* DMA infrastructure */
-
-static void davinci_abort_dma(struct mmc_davinci_host *host)
-{
- int sync_dev;
-
- if (host->data_dir == DAVINCI_MMC_DATADIR_READ)
- sync_dev = host->rxdma;
- else
- sync_dev = host->txdma;
-
- edma_stop(sync_dev);
- edma_clean_channel(sync_dev);
-}
-
-static void
-mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data);
-
-static void mmc_davinci_dma_cb(unsigned channel, u16 ch_status, void *data)
-{
- if (DMA_COMPLETE != ch_status) {
- struct mmc_davinci_host *host = data;
-
- /* Currently means: DMA Event Missed, or "null" transfer
- * request was seen. In the future, TC errors (like bad
- * addresses) might be presented too.
- */
- dev_warn(mmc_dev(host->mmc), "DMA %s error\n",
- (host->data->flags & MMC_DATA_WRITE)
- ? "write" : "read");
- host->data->error = -EIO;
- mmc_davinci_xfer_done(host, host->data);
- }
-}
-
-/* Set up tx or rx template, to be modified and updated later */
-static void __init mmc_davinci_dma_setup(struct mmc_davinci_host *host,
- bool tx, struct edmacc_param *template)
-{
- unsigned sync_dev;
- const u16 acnt = 4;
- const u16 bcnt = rw_threshold >> 2;
- const u16 ccnt = 0;
- u32 src_port = 0;
- u32 dst_port = 0;
- s16 src_bidx, dst_bidx;
- s16 src_cidx, dst_cidx;
-
- /*
- * A-B Sync transfer: each DMA request is for one "frame" of
- * rw_threshold bytes, broken into "acnt"-size chunks repeated
- * "bcnt" times. Each segment needs "ccnt" such frames; since
- * we tell the block layer our mmc->max_seg_size limit, we can
- * trust (later) that it's within bounds.
- *
- * The FIFOs are read/written in 4-byte chunks (acnt == 4) and
- * EDMA will optimize memory operations to use larger bursts.
- */
- if (tx) {
- sync_dev = host->txdma;
-
- /* src_prt, ccnt, and link to be set up later */
- src_bidx = acnt;
- src_cidx = acnt * bcnt;
-
- dst_port = host->mem_res->start + DAVINCI_MMCDXR;
- dst_bidx = 0;
- dst_cidx = 0;
- } else {
- sync_dev = host->rxdma;
-
- src_port = host->mem_res->start + DAVINCI_MMCDRR;
- src_bidx = 0;
- src_cidx = 0;
-
- /* dst_prt, ccnt, and link to be set up later */
- dst_bidx = acnt;
- dst_cidx = acnt * bcnt;
- }
-
- /*
- * We can't use FIFO mode for the FIFOs because MMC FIFO addresses
- * are not 256-bit (32-byte) aligned. So we use INCR, and the W8BIT
- * parameter is ignored.
- */
- edma_set_src(sync_dev, src_port, INCR, W8BIT);
- edma_set_dest(sync_dev, dst_port, INCR, W8BIT);
-
- edma_set_src_index(sync_dev, src_bidx, src_cidx);
- edma_set_dest_index(sync_dev, dst_bidx, dst_cidx);
-
- edma_set_transfer_params(sync_dev, acnt, bcnt, ccnt, 8, ABSYNC);
-
- edma_read_slot(sync_dev, template);
-
- /* don't bother with irqs or chaining */
- template->opt |= EDMA_CHAN_SLOT(sync_dev) << 12;
-}
-
-static void mmc_davinci_send_dma_request(struct mmc_davinci_host *host,
- struct mmc_data *data)
-{
- struct edmacc_param *template;
- int channel, slot;
- unsigned link;
- struct scatterlist *sg;
- unsigned sg_len;
- unsigned bytes_left = host->bytes_left;
- const unsigned shift = ffs(rw_threshold) - 1;
-
- if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE) {
- template = &host->tx_template;
- channel = host->txdma;
- } else {
- template = &host->rx_template;
- channel = host->rxdma;
- }
-
- /* We know sg_len and ccnt will never be out of range because
- * we told the mmc layer which in turn tells the block layer
- * to ensure that it only hands us one scatterlist segment
- * per EDMA PARAM entry. Update the PARAM
- * entries needed for each segment of this scatterlist.
- */
- for (slot = channel, link = 0, sg = data->sg, sg_len = host->sg_len;
- sg_len-- != 0 && bytes_left;
- sg = sg_next(sg), slot = host->links[link++]) {
- u32 buf = sg_dma_address(sg);
- unsigned count = sg_dma_len(sg);
-
- template->link_bcntrld = sg_len
- ? (EDMA_CHAN_SLOT(host->links[link]) << 5)
- : 0xffff;
-
- if (count > bytes_left)
- count = bytes_left;
- bytes_left -= count;
-
- if (host->data_dir == DAVINCI_MMC_DATADIR_WRITE)
- template->src = buf;
- else
- template->dst = buf;
- template->ccnt = count >> shift;
-
- edma_write_slot(slot, template);
- }
-
- if (host->version == MMC_CTLR_VERSION_2)
- edma_clear_event(channel);
-
- edma_start(channel);
-}
-
-static int mmc_davinci_start_dma_transfer(struct mmc_davinci_host *host,
- struct mmc_data *data)
-{
- int i;
- int mask = rw_threshold - 1;
-
- host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- ((data->flags & MMC_DATA_WRITE)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE));
-
- /* no individual DMA segment should need a partial FIFO */
- for (i = 0; i < host->sg_len; i++) {
- if (sg_dma_len(data->sg + i) & mask) {
- dma_unmap_sg(mmc_dev(host->mmc),
- data->sg, data->sg_len,
- (data->flags & MMC_DATA_WRITE)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- return -1;
- }
- }
-
- host->do_dma = 1;
- mmc_davinci_send_dma_request(host, data);
-
- return 0;
-}
-
-static void __init_or_module
-davinci_release_dma_channels(struct mmc_davinci_host *host)
-{
- unsigned i;
-
- if (!host->use_dma)
- return;
-
- for (i = 0; i < host->n_link; i++)
- edma_free_slot(host->links[i]);
-
- edma_free_channel(host->txdma);
- edma_free_channel(host->rxdma);
-}
-
-static int __init davinci_acquire_dma_channels(struct mmc_davinci_host *host)
-{
- u32 link_size;
- int r, i;
-
- /* Acquire master DMA write channel */
- r = edma_alloc_channel(host->txdma, mmc_davinci_dma_cb, host,
- EVENTQ_DEFAULT);
- if (r < 0) {
- dev_warn(mmc_dev(host->mmc), "alloc %s channel err %d\n",
- "tx", r);
- return r;
- }
- mmc_davinci_dma_setup(host, true, &host->tx_template);
-
- /* Acquire master DMA read channel */
- r = edma_alloc_channel(host->rxdma, mmc_davinci_dma_cb, host,
- EVENTQ_DEFAULT);
- if (r < 0) {
- dev_warn(mmc_dev(host->mmc), "alloc %s channel err %d\n",
- "rx", r);
- goto free_master_write;
- }
- mmc_davinci_dma_setup(host, false, &host->rx_template);
-
- /* Allocate parameter RAM slots, which will later be bound to a
- * channel as needed to handle a scatterlist.
- */
- link_size = min_t(unsigned, host->nr_sg, ARRAY_SIZE(host->links));
- for (i = 0; i < link_size; i++) {
- r = edma_alloc_slot(EDMA_CTLR(host->txdma), EDMA_SLOT_ANY);
- if (r < 0) {
- dev_dbg(mmc_dev(host->mmc), "dma PaRAM alloc --> %d\n",
- r);
- break;
- }
- host->links[i] = r;
- }
- host->n_link = i;
-
- return 0;
-
-free_master_write:
- edma_free_channel(host->txdma);
-
- return r;
-}
-
-/*----------------------------------------------------------------------*/
-
-static void
-mmc_davinci_prepare_data(struct mmc_davinci_host *host, struct mmc_request *req)
-{
- int fifo_lev = (rw_threshold == 32) ? MMCFIFOCTL_FIFOLEV : 0;
- int timeout;
- struct mmc_data *data = req->data;
-
- if (host->version == MMC_CTLR_VERSION_2)
- fifo_lev = (rw_threshold == 64) ? MMCFIFOCTL_FIFOLEV : 0;
-
- host->data = data;
- if (data == NULL) {
- host->data_dir = DAVINCI_MMC_DATADIR_NONE;
- writel(0, host->base + DAVINCI_MMCBLEN);
- writel(0, host->base + DAVINCI_MMCNBLK);
- return;
- }
-
- dev_dbg(mmc_dev(host->mmc), "%s %s, %d blocks of %d bytes\n",
- (data->flags & MMC_DATA_STREAM) ? "stream" : "block",
- (data->flags & MMC_DATA_WRITE) ? "write" : "read",
- data->blocks, data->blksz);
- dev_dbg(mmc_dev(host->mmc), " DTO %d cycles + %d ns\n",
- data->timeout_clks, data->timeout_ns);
- timeout = data->timeout_clks +
- (data->timeout_ns / host->ns_in_one_cycle);
- if (timeout > 0xffff)
- timeout = 0xffff;
-
- writel(timeout, host->base + DAVINCI_MMCTOD);
- writel(data->blocks, host->base + DAVINCI_MMCNBLK);
- writel(data->blksz, host->base + DAVINCI_MMCBLEN);
-
- /* Configure the FIFO */
- switch (data->flags & MMC_DATA_WRITE) {
- case MMC_DATA_WRITE:
- host->data_dir = DAVINCI_MMC_DATADIR_WRITE;
- writel(fifo_lev | MMCFIFOCTL_FIFODIR_WR | MMCFIFOCTL_FIFORST,
- host->base + DAVINCI_MMCFIFOCTL);
- writel(fifo_lev | MMCFIFOCTL_FIFODIR_WR,
- host->base + DAVINCI_MMCFIFOCTL);
- break;
-
- default:
- host->data_dir = DAVINCI_MMC_DATADIR_READ;
- writel(fifo_lev | MMCFIFOCTL_FIFODIR_RD | MMCFIFOCTL_FIFORST,
- host->base + DAVINCI_MMCFIFOCTL);
- writel(fifo_lev | MMCFIFOCTL_FIFODIR_RD,
- host->base + DAVINCI_MMCFIFOCTL);
- break;
- }
-
- host->buffer = NULL;
- host->bytes_left = data->blocks * data->blksz;
-
- /* For now we try to use DMA whenever we won't need partial FIFO
- * reads or writes, either for the whole transfer (as tested here)
- * or for any individual scatterlist segment (tested when we call
- * start_dma_transfer).
- *
- * While we *could* change that, unusual block sizes are rarely
- * used. The occasional fallback to PIO should't hurt.
- */
- if (host->use_dma && (host->bytes_left & (rw_threshold - 1)) == 0
- && mmc_davinci_start_dma_transfer(host, data) == 0) {
- /* zero this to ensure we take no PIO paths */
- host->bytes_left = 0;
- } else {
- /* Revert to CPU Copy */
- host->sg_len = data->sg_len;
- host->sg = host->data->sg;
- mmc_davinci_sg_to_buf(host);
- }
-}
-
-static void mmc_davinci_request(struct mmc_host *mmc, struct mmc_request *req)
-{
- struct mmc_davinci_host *host = mmc_priv(mmc);
- unsigned long timeout = jiffies + msecs_to_jiffies(900);
- u32 mmcst1 = 0;
-
- /* Card may still be sending BUSY after a previous operation,
- * typically some kind of write. If so, we can't proceed yet.
- */
- while (time_before(jiffies, timeout)) {
- mmcst1 = readl(host->base + DAVINCI_MMCST1);
- if (!(mmcst1 & MMCST1_BUSY))
- break;
- cpu_relax();
- }
- if (mmcst1 & MMCST1_BUSY) {
- dev_err(mmc_dev(host->mmc), "still BUSY? bad ... \n");
- req->cmd->error = -ETIMEDOUT;
- mmc_request_done(mmc, req);
- return;
- }
-
- host->do_dma = 0;
- mmc_davinci_prepare_data(host, req);
- mmc_davinci_start_command(host, req->cmd);
-}
-
-static unsigned int calculate_freq_for_card(struct mmc_davinci_host *host,
- unsigned int mmc_req_freq)
-{
- unsigned int mmc_freq = 0, mmc_pclk = 0, mmc_push_pull_divisor = 0;
-
- mmc_pclk = host->mmc_input_clk;
- if (mmc_req_freq && mmc_pclk > (2 * mmc_req_freq))
- mmc_push_pull_divisor = ((unsigned int)mmc_pclk
- / (2 * mmc_req_freq)) - 1;
- else
- mmc_push_pull_divisor = 0;
-
- mmc_freq = (unsigned int)mmc_pclk
- / (2 * (mmc_push_pull_divisor + 1));
-
- if (mmc_freq > mmc_req_freq)
- mmc_push_pull_divisor = mmc_push_pull_divisor + 1;
- /* Convert ns to clock cycles */
- if (mmc_req_freq <= 400000)
- host->ns_in_one_cycle = (1000000) / (((mmc_pclk
- / (2 * (mmc_push_pull_divisor + 1)))/1000));
- else
- host->ns_in_one_cycle = (1000000) / (((mmc_pclk
- / (2 * (mmc_push_pull_divisor + 1)))/1000000));
-
- return mmc_push_pull_divisor;
-}
-
-static void calculate_clk_divider(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- unsigned int open_drain_freq = 0, mmc_pclk = 0;
- unsigned int mmc_push_pull_freq = 0;
- struct mmc_davinci_host *host = mmc_priv(mmc);
-
- if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) {
- u32 temp;
-
- /* Ignoring the init clock value passed for fixing the inter
- * operability with different cards.
- */
- open_drain_freq = ((unsigned int)mmc_pclk
- / (2 * MMCSD_INIT_CLOCK)) - 1;
-
- if (open_drain_freq > 0xFF)
- open_drain_freq = 0xFF;
-
- temp = readl(host->base + DAVINCI_MMCCLK) & ~MMCCLK_CLKRT_MASK;
- temp |= open_drain_freq;
- writel(temp, host->base + DAVINCI_MMCCLK);
-
- /* Convert ns to clock cycles */
- host->ns_in_one_cycle = (1000000) / (MMCSD_INIT_CLOCK/1000);
- } else {
- u32 temp;
- mmc_push_pull_freq = calculate_freq_for_card(host, ios->clock);
-
- if (mmc_push_pull_freq > 0xFF)
- mmc_push_pull_freq = 0xFF;
-
- temp = readl(host->base + DAVINCI_MMCCLK) & ~MMCCLK_CLKEN;
- writel(temp, host->base + DAVINCI_MMCCLK);
-
- udelay(10);
-
- temp = readl(host->base + DAVINCI_MMCCLK) & ~MMCCLK_CLKRT_MASK;
- temp |= mmc_push_pull_freq;
- writel(temp, host->base + DAVINCI_MMCCLK);
-
- writel(temp | MMCCLK_CLKEN, host->base + DAVINCI_MMCCLK);
-
- udelay(10);
- }
-}
-
-static void mmc_davinci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct mmc_davinci_host *host = mmc_priv(mmc);
- struct platform_device *pdev = to_platform_device(mmc->parent);
- struct davinci_mmc_config *config = pdev->dev.platform_data;
-
- dev_dbg(mmc_dev(host->mmc),
- "clock %dHz busmode %d powermode %d Vdd %04x\n",
- ios->clock, ios->bus_mode, ios->power_mode,
- ios->vdd);
-
- switch (ios->power_mode) {
- case MMC_POWER_OFF:
- if (config && config->set_power)
- config->set_power(pdev->id, false);
- break;
- case MMC_POWER_UP:
- if (config && config->set_power)
- config->set_power(pdev->id, true);
- break;
- }
-
- switch (ios->bus_width) {
- case MMC_BUS_WIDTH_8:
- dev_dbg(mmc_dev(host->mmc), "Enabling 8 bit mode\n");
- writel((readl(host->base + DAVINCI_MMCCTL) &
- ~MMCCTL_WIDTH_4_BIT) | MMCCTL_WIDTH_8_BIT,
- host->base + DAVINCI_MMCCTL);
- break;
- case MMC_BUS_WIDTH_4:
- dev_dbg(mmc_dev(host->mmc), "Enabling 4 bit mode\n");
- if (host->version == MMC_CTLR_VERSION_2)
- writel((readl(host->base + DAVINCI_MMCCTL) &
- ~MMCCTL_WIDTH_8_BIT) | MMCCTL_WIDTH_4_BIT,
- host->base + DAVINCI_MMCCTL);
- else
- writel(readl(host->base + DAVINCI_MMCCTL) |
- MMCCTL_WIDTH_4_BIT,
- host->base + DAVINCI_MMCCTL);
- break;
- case MMC_BUS_WIDTH_1:
- dev_dbg(mmc_dev(host->mmc), "Enabling 1 bit mode\n");
- if (host->version == MMC_CTLR_VERSION_2)
- writel(readl(host->base + DAVINCI_MMCCTL) &
- ~(MMCCTL_WIDTH_8_BIT | MMCCTL_WIDTH_4_BIT),
- host->base + DAVINCI_MMCCTL);
- else
- writel(readl(host->base + DAVINCI_MMCCTL) &
- ~MMCCTL_WIDTH_4_BIT,
- host->base + DAVINCI_MMCCTL);
- break;
- }
-
- calculate_clk_divider(mmc, ios);
-
- host->bus_mode = ios->bus_mode;
- if (ios->power_mode == MMC_POWER_UP) {
- unsigned long timeout = jiffies + msecs_to_jiffies(50);
- bool lose = true;
-
- /* Send clock cycles, poll completion */
- writel(0, host->base + DAVINCI_MMCARGHL);
- writel(MMCCMD_INITCK, host->base + DAVINCI_MMCCMD);
- while (time_before(jiffies, timeout)) {
- u32 tmp = readl(host->base + DAVINCI_MMCST0);
-
- if (tmp & MMCST0_RSPDNE) {
- lose = false;
- break;
- }
- cpu_relax();
- }
- if (lose)
- dev_warn(mmc_dev(host->mmc), "powerup timeout\n");
- }
-
- /* FIXME on power OFF, reset things ... */
-}
-
-static void
-mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data)
-{
- host->data = NULL;
-
- if (host->mmc->caps & MMC_CAP_SDIO_IRQ) {
- /*
- * SDIO Interrupt Detection work-around as suggested by
- * Davinci Errata (TMS320DM355 Silicon Revision 1.1 Errata
- * 2.1.6): Signal SDIO interrupt only if it is enabled by core
- */
- if (host->sdio_int && !(readl(host->base + DAVINCI_SDIOST0) &
- SDIOST0_DAT1_HI)) {
- writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST);
- mmc_signal_sdio_irq(host->mmc);
- }
- }
-
- if (host->do_dma) {
- davinci_abort_dma(host);
-
- dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- (data->flags & MMC_DATA_WRITE)
- ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- host->do_dma = false;
- }
- host->data_dir = DAVINCI_MMC_DATADIR_NONE;
-
- if (!data->stop || (host->cmd && host->cmd->error)) {
- mmc_request_done(host->mmc, data->mrq);
- writel(0, host->base + DAVINCI_MMCIM);
- host->active_request = false;
- } else
- mmc_davinci_start_command(host, data->stop);
-}
-
-static void mmc_davinci_cmd_done(struct mmc_davinci_host *host,
- struct mmc_command *cmd)
-{
- host->cmd = NULL;
-
- if (cmd->flags & MMC_RSP_PRESENT) {
- if (cmd->flags & MMC_RSP_136) {
- /* response type 2 */
- cmd->resp[3] = readl(host->base + DAVINCI_MMCRSP01);
- cmd->resp[2] = readl(host->base + DAVINCI_MMCRSP23);
- cmd->resp[1] = readl(host->base + DAVINCI_MMCRSP45);
- cmd->resp[0] = readl(host->base + DAVINCI_MMCRSP67);
- } else {
- /* response types 1, 1b, 3, 4, 5, 6 */
- cmd->resp[0] = readl(host->base + DAVINCI_MMCRSP67);
- }
- }
-
- if (host->data == NULL || cmd->error) {
- if (cmd->error == -ETIMEDOUT)
- cmd->mrq->cmd->retries = 0;
- mmc_request_done(host->mmc, cmd->mrq);
- writel(0, host->base + DAVINCI_MMCIM);
- host->active_request = false;
- }
-}
-
-static inline void mmc_davinci_reset_ctrl(struct mmc_davinci_host *host,
- int val)
-{
- u32 temp;
-
- temp = readl(host->base + DAVINCI_MMCCTL);
- if (val) /* reset */
- temp |= MMCCTL_CMDRST | MMCCTL_DATRST;
- else /* enable */
- temp &= ~(MMCCTL_CMDRST | MMCCTL_DATRST);
-
- writel(temp, host->base + DAVINCI_MMCCTL);
- udelay(10);
-}
-
-static void
-davinci_abort_data(struct mmc_davinci_host *host, struct mmc_data *data)
-{
- mmc_davinci_reset_ctrl(host, 1);
- mmc_davinci_reset_ctrl(host, 0);
-}
-
-static irqreturn_t mmc_davinci_sdio_irq(int irq, void *dev_id)
-{
- struct mmc_davinci_host *host = dev_id;
- unsigned int status;
-
- status = readl(host->base + DAVINCI_SDIOIST);
- if (status & SDIOIST_IOINT) {
- dev_dbg(mmc_dev(host->mmc),
- "SDIO interrupt status %x\n", status);
- writel(status | SDIOIST_IOINT, host->base + DAVINCI_SDIOIST);
- mmc_signal_sdio_irq(host->mmc);
- }
- return IRQ_HANDLED;
-}
-
-static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)
-{
- struct mmc_davinci_host *host = (struct mmc_davinci_host *)dev_id;
- unsigned int status, qstatus;
- int end_command = 0;
- int end_transfer = 0;
- struct mmc_data *data = host->data;
-
- if (host->cmd == NULL && host->data == NULL) {
- status = readl(host->base + DAVINCI_MMCST0);
- dev_dbg(mmc_dev(host->mmc),
- "Spurious interrupt 0x%04x\n", status);
- /* Disable the interrupt from mmcsd */
- writel(0, host->base + DAVINCI_MMCIM);
- return IRQ_NONE;
- }
-
- status = readl(host->base + DAVINCI_MMCST0);
- qstatus = status;
-
- /* handle FIFO first when using PIO for data.
- * bytes_left will decrease to zero as I/O progress and status will
- * read zero over iteration because this controller status
- * register(MMCST0) reports any status only once and it is cleared
- * by read. So, it is not unbouned loop even in the case of
- * non-dma.
- */
- if (host->bytes_left && (status & (MMCST0_DXRDY | MMCST0_DRRDY))) {
- unsigned long im_val;
-
- /*
- * If interrupts fire during the following loop, they will be
- * handled by the handler, but the PIC will still buffer these.
- * As a result, the handler will be called again to serve these
- * needlessly. In order to avoid these spurious interrupts,
- * keep interrupts masked during the loop.
- */
- im_val = readl(host->base + DAVINCI_MMCIM);
- writel(0, host->base + DAVINCI_MMCIM);
-
- do {
- davinci_fifo_data_trans(host, rw_threshold);
- status = readl(host->base + DAVINCI_MMCST0);
- qstatus |= status;
- } while (host->bytes_left &&
- (status & (MMCST0_DXRDY | MMCST0_DRRDY)));
-
- /*
- * If an interrupt is pending, it is assumed it will fire when
- * it is unmasked. This assumption is also taken when the MMCIM
- * is first set. Otherwise, writing to MMCIM after reading the
- * status is race-prone.
- */
- writel(im_val, host->base + DAVINCI_MMCIM);
- }
-
- if (qstatus & MMCST0_DATDNE) {
- /* All blocks sent/received, and CRC checks passed */
- if (data != NULL) {
- if ((host->do_dma == 0) && (host->bytes_left > 0)) {
- /* if datasize < rw_threshold
- * no RX ints are generated
- */
- davinci_fifo_data_trans(host, host->bytes_left);
- }
- end_transfer = 1;
- data->bytes_xfered = data->blocks * data->blksz;
- } else {
- dev_err(mmc_dev(host->mmc),
- "DATDNE with no host->data\n");
- }
- }
-
- if (qstatus & MMCST0_TOUTRD) {
- /* Read data timeout */
- data->error = -ETIMEDOUT;
- end_transfer = 1;
-
- dev_dbg(mmc_dev(host->mmc),
- "read data timeout, status %x\n",
- qstatus);
-
- davinci_abort_data(host, data);
- }
-
- if (qstatus & (MMCST0_CRCWR | MMCST0_CRCRD)) {
- /* Data CRC error */
- data->error = -EILSEQ;
- end_transfer = 1;
-
- /* NOTE: this controller uses CRCWR to report both CRC
- * errors and timeouts (on writes). MMCDRSP values are
- * only weakly documented, but 0x9f was clearly a timeout
- * case and the two three-bit patterns in various SD specs
- * (101, 010) aren't part of it ...
- */
- if (qstatus & MMCST0_CRCWR) {
- u32 temp = readb(host->base + DAVINCI_MMCDRSP);
-
- if (temp == 0x9f)
- data->error = -ETIMEDOUT;
- }
- dev_dbg(mmc_dev(host->mmc), "data %s %s error\n",
- (qstatus & MMCST0_CRCWR) ? "write" : "read",
- (data->error == -ETIMEDOUT) ? "timeout" : "CRC");
-
- davinci_abort_data(host, data);
- }
-
- if (qstatus & MMCST0_TOUTRS) {
- /* Command timeout */
- if (host->cmd) {
- dev_dbg(mmc_dev(host->mmc),
- "CMD%d timeout, status %x\n",
- host->cmd->opcode, qstatus);
- host->cmd->error = -ETIMEDOUT;
- if (data) {
- end_transfer = 1;
- davinci_abort_data(host, data);
- } else
- end_command = 1;
- }
- }
-
- if (qstatus & MMCST0_CRCRS) {
- /* Command CRC error */
- dev_dbg(mmc_dev(host->mmc), "Command CRC error\n");
- if (host->cmd) {
- host->cmd->error = -EILSEQ;
- end_command = 1;
- }
- }
-
- if (qstatus & MMCST0_RSPDNE) {
- /* End of command phase */
- end_command = (int) host->cmd;
- }
-
- if (end_command)
- mmc_davinci_cmd_done(host, host->cmd);
- if (end_transfer)
- mmc_davinci_xfer_done(host, data);
- return IRQ_HANDLED;
-}
-
-static int mmc_davinci_get_cd(struct mmc_host *mmc)
-{
- struct platform_device *pdev = to_platform_device(mmc->parent);
- struct davinci_mmc_config *config = pdev->dev.platform_data;
-
- if (!config || !config->get_cd)
- return -ENOSYS;
- return config->get_cd(pdev->id);
-}
-
-static int mmc_davinci_get_ro(struct mmc_host *mmc)
-{
- struct platform_device *pdev = to_platform_device(mmc->parent);
- struct davinci_mmc_config *config = pdev->dev.platform_data;
-
- if (!config || !config->get_ro)
- return -ENOSYS;
- return config->get_ro(pdev->id);
-}
-
-static void mmc_davinci_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
- struct mmc_davinci_host *host = mmc_priv(mmc);
-
- if (enable) {
- if (!(readl(host->base + DAVINCI_SDIOST0) & SDIOST0_DAT1_HI)) {
- writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST);
- mmc_signal_sdio_irq(host->mmc);
- } else {
- host->sdio_int = true;
- writel(readl(host->base + DAVINCI_SDIOIEN) |
- SDIOIEN_IOINTEN, host->base + DAVINCI_SDIOIEN);
- }
- } else {
- host->sdio_int = false;
- writel(readl(host->base + DAVINCI_SDIOIEN) & ~SDIOIEN_IOINTEN,
- host->base + DAVINCI_SDIOIEN);
- }
-}
-
-static struct mmc_host_ops mmc_davinci_ops = {
- .request = mmc_davinci_request,
- .set_ios = mmc_davinci_set_ios,
- .get_cd = mmc_davinci_get_cd,
- .get_ro = mmc_davinci_get_ro,
- .enable_sdio_irq = mmc_davinci_enable_sdio_irq,
-};
-
-/*----------------------------------------------------------------------*/
-
-#ifdef CONFIG_CPU_FREQ
-static int mmc_davinci_cpufreq_transition(struct notifier_block *nb,
- unsigned long val, void *data)
-{
- struct mmc_davinci_host *host;
- unsigned int mmc_pclk;
- struct mmc_host *mmc;
- unsigned long flags;
-
- host = container_of(nb, struct mmc_davinci_host, freq_transition);
- mmc = host->mmc;
- mmc_pclk = clk_get_rate(host->clk);
-
- if (val == CPUFREQ_POSTCHANGE) {
- spin_lock_irqsave(&mmc->lock, flags);
- host->mmc_input_clk = mmc_pclk;
- calculate_clk_divider(mmc, &mmc->ios);
- spin_unlock_irqrestore(&mmc->lock, flags);
- }
-
- return 0;
-}
-
-static inline int mmc_davinci_cpufreq_register(struct mmc_davinci_host *host)
-{
- host->freq_transition.notifier_call = mmc_davinci_cpufreq_transition;
-
- return cpufreq_register_notifier(&host->freq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
-}
-
-static inline void mmc_davinci_cpufreq_deregister(struct mmc_davinci_host *host)
-{
- cpufreq_unregister_notifier(&host->freq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
-}
-#else
-static inline int mmc_davinci_cpufreq_register(struct mmc_davinci_host *host)
-{
- return 0;
-}
-
-static inline void mmc_davinci_cpufreq_deregister(struct mmc_davinci_host *host)
-{
-}
-#endif
-static void __init init_mmcsd_host(struct mmc_davinci_host *host)
-{
-
- mmc_davinci_reset_ctrl(host, 1);
-
- writel(0, host->base + DAVINCI_MMCCLK);
- writel(MMCCLK_CLKEN, host->base + DAVINCI_MMCCLK);
-
- writel(0x1FFF, host->base + DAVINCI_MMCTOR);
- writel(0xFFFF, host->base + DAVINCI_MMCTOD);
-
- mmc_davinci_reset_ctrl(host, 0);
-}
-
-static int __init davinci_mmcsd_probe(struct platform_device *pdev)
-{
- struct davinci_mmc_config *pdata = pdev->dev.platform_data;
- struct mmc_davinci_host *host = NULL;
- struct mmc_host *mmc = NULL;
- struct resource *r, *mem = NULL;
- int ret = 0, irq = 0;
- size_t mem_size;
-
- /* REVISIT: when we're fully converted, fail if pdata is NULL */
-
- ret = -ENODEV;
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
- if (!r || irq == NO_IRQ)
- goto out;
-
- ret = -EBUSY;
- mem_size = resource_size(r);
- mem = request_mem_region(r->start, mem_size, pdev->name);
- if (!mem)
- goto out;
-
- ret = -ENOMEM;
- mmc = mmc_alloc_host(sizeof(struct mmc_davinci_host), &pdev->dev);
- if (!mmc)
- goto out;
-
- host = mmc_priv(mmc);
- host->mmc = mmc; /* Important */
-
- r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!r)
- goto out;
- host->rxdma = r->start;
-
- r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!r)
- goto out;
- host->txdma = r->start;
-
- host->mem_res = mem;
- host->base = ioremap(mem->start, mem_size);
- if (!host->base)
- goto out;
-
- ret = -ENXIO;
- host->clk = clk_get(&pdev->dev, "MMCSDCLK");
- if (IS_ERR(host->clk)) {
- ret = PTR_ERR(host->clk);
- goto out;
- }
- clk_enable(host->clk);
- host->mmc_input_clk = clk_get_rate(host->clk);
-
- init_mmcsd_host(host);
-
- if (pdata->nr_sg)
- host->nr_sg = pdata->nr_sg - 1;
-
- if (host->nr_sg > MAX_NR_SG || !host->nr_sg)
- host->nr_sg = MAX_NR_SG;
-
- host->use_dma = use_dma;
- host->mmc_irq = irq;
- host->sdio_irq = platform_get_irq(pdev, 1);
-
- if (host->use_dma && davinci_acquire_dma_channels(host) != 0)
- host->use_dma = 0;
-
- /* REVISIT: someday, support IRQ-driven card detection. */
- mmc->caps |= MMC_CAP_NEEDS_POLL;
- mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
-
- if (pdata && (pdata->wires == 4 || pdata->wires == 0))
- mmc->caps |= MMC_CAP_4_BIT_DATA;
-
- if (pdata && (pdata->wires == 8))
- mmc->caps |= (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA);
-
- host->version = pdata->version;
-
- mmc->ops = &mmc_davinci_ops;
- mmc->f_min = 312500;
- mmc->f_max = 25000000;
- if (pdata && pdata->max_freq)
- mmc->f_max = pdata->max_freq;
- if (pdata && pdata->caps)
- mmc->caps |= pdata->caps;
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-
- /* With no iommu coalescing pages, each phys_seg is a hw_seg.
- * Each hw_seg uses one EDMA parameter RAM slot, always one
- * channel and then usually some linked slots.
- */
- mmc->max_segs = 1 + host->n_link;
-
- /* EDMA limit per hw segment (one or two MBytes) */
- mmc->max_seg_size = MAX_CCNT * rw_threshold;
-
- /* MMC/SD controller limits for multiblock requests */
- mmc->max_blk_size = 4095; /* BLEN is 12 bits */
- 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_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);
-
- platform_set_drvdata(pdev, host);
-
- ret = mmc_davinci_cpufreq_register(host);
- if (ret) {
- dev_err(&pdev->dev, "failed to register cpufreq\n");
- goto cpu_freq_fail;
- }
-
- ret = mmc_add_host(mmc);
- if (ret < 0)
- goto out;
-
- ret = request_irq(irq, mmc_davinci_irq, 0, mmc_hostname(mmc), host);
- if (ret)
- goto out;
-
- if (host->sdio_irq >= 0) {
- ret = request_irq(host->sdio_irq, mmc_davinci_sdio_irq, 0,
- mmc_hostname(mmc), host);
- if (!ret)
- mmc->caps |= MMC_CAP_SDIO_IRQ;
- }
-
- rename_region(mem, mmc_hostname(mmc));
-
- dev_info(mmc_dev(host->mmc), "Using %s, %d-bit mode\n",
- host->use_dma ? "DMA" : "PIO",
- (mmc->caps & MMC_CAP_4_BIT_DATA) ? 4 : 1);
-
- return 0;
-
-out:
- mmc_davinci_cpufreq_deregister(host);
-cpu_freq_fail:
- if (host) {
- davinci_release_dma_channels(host);
-
- if (host->clk) {
- clk_disable(host->clk);
- clk_put(host->clk);
- }
-
- if (host->base)
- iounmap(host->base);
- }
-
- if (mmc)
- mmc_free_host(mmc);
-
- if (mem)
- release_resource(mem);
-
- dev_dbg(&pdev->dev, "probe err %d\n", ret);
-
- return ret;
-}
-
-static int __exit davinci_mmcsd_remove(struct platform_device *pdev)
-{
- struct mmc_davinci_host *host = platform_get_drvdata(pdev);
-
- platform_set_drvdata(pdev, NULL);
- if (host) {
- mmc_davinci_cpufreq_deregister(host);
-
- mmc_remove_host(host->mmc);
- free_irq(host->mmc_irq, host);
- if (host->mmc->caps & MMC_CAP_SDIO_IRQ)
- free_irq(host->sdio_irq, host);
-
- davinci_release_dma_channels(host);
-
- clk_disable(host->clk);
- clk_put(host->clk);
-
- iounmap(host->base);
-
- release_resource(host->mem_res);
-
- mmc_free_host(host->mmc);
- }
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int davinci_mmcsd_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct mmc_davinci_host *host = platform_get_drvdata(pdev);
- int ret;
-
- ret = mmc_suspend_host(host->mmc);
- if (!ret) {
- writel(0, host->base + DAVINCI_MMCIM);
- mmc_davinci_reset_ctrl(host, 1);
- clk_disable(host->clk);
- host->suspended = 1;
- } else {
- host->suspended = 0;
- }
-
- return ret;
-}
-
-static int davinci_mmcsd_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct mmc_davinci_host *host = platform_get_drvdata(pdev);
- int ret;
-
- if (!host->suspended)
- return 0;
-
- clk_enable(host->clk);
-
- mmc_davinci_reset_ctrl(host, 0);
- ret = mmc_resume_host(host->mmc);
- if (!ret)
- host->suspended = 0;
-
- return ret;
-}
-
-static const struct dev_pm_ops davinci_mmcsd_pm = {
- .suspend = davinci_mmcsd_suspend,
- .resume = davinci_mmcsd_resume,
-};
-
-#define davinci_mmcsd_pm_ops (&davinci_mmcsd_pm)
-#else
-#define davinci_mmcsd_pm_ops NULL
-#endif
-
-static struct platform_driver davinci_mmcsd_driver = {
- .driver = {
- .name = "davinci_mmc",
- .owner = THIS_MODULE,
- .pm = davinci_mmcsd_pm_ops,
- },
- .remove = __exit_p(davinci_mmcsd_remove),
-};
-
-static int __init davinci_mmcsd_init(void)
-{
- return platform_driver_probe(&davinci_mmcsd_driver,
- davinci_mmcsd_probe);
-}
-module_init(davinci_mmcsd_init);
-
-static void __exit davinci_mmcsd_exit(void)
-{
- platform_driver_unregister(&davinci_mmcsd_driver);
-}
-module_exit(davinci_mmcsd_exit);
-
-MODULE_AUTHOR("Texas Instruments India");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("MMC/SD driver for Davinci MMC controller");
-
diff --git a/ANDROID_3.4.5/drivers/mmc/host/dw_mmc-pci.c b/ANDROID_3.4.5/drivers/mmc/host/dw_mmc-pci.c
deleted file mode 100644
index dc0d25a0..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/dw_mmc-pci.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Synopsys DesignWare Multimedia Card PCI Interface driver
- *
- * Copyright (C) 2012 Vayavya Labs Pvt. 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.
- */
-
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/dw_mmc.h>
-#include "dw_mmc.h"
-
-#define PCI_BAR_NO 2
-#define COMPLETE_BAR 0
-#define SYNOPSYS_DW_MCI_VENDOR_ID 0x700
-#define SYNOPSYS_DW_MCI_DEVICE_ID 0x1107
-/* Defining the Capabilities */
-#define DW_MCI_CAPABILITIES (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED |\
- MMC_CAP_SD_HIGHSPEED | MMC_CAP_8_BIT_DATA |\
- MMC_CAP_SDIO_IRQ)
-
-static struct dw_mci_board pci_board_data = {
- .num_slots = 1,
- .caps = DW_MCI_CAPABILITIES,
- .bus_hz = 33 * 1000 * 1000,
- .detect_delay_ms = 200,
- .fifo_depth = 32,
-};
-
-static int __devinit dw_mci_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *entries)
-{
- struct dw_mci *host;
- int ret;
-
- ret = pci_enable_device(pdev);
- if (ret)
- return ret;
- if (pci_request_regions(pdev, "dw_mmc_pci")) {
- ret = -ENODEV;
- goto err_disable_dev;
- }
-
- host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL);
- if (!host) {
- ret = -ENOMEM;
- goto err_release;
- }
-
- host->irq = pdev->irq;
- host->irq_flags = IRQF_SHARED;
- host->dev = pdev->dev;
- host->pdata = &pci_board_data;
-
- host->regs = pci_iomap(pdev, PCI_BAR_NO, COMPLETE_BAR);
- if (!host->regs) {
- ret = -EIO;
- goto err_unmap;
- }
-
- pci_set_drvdata(pdev, host);
- ret = dw_mci_probe(host);
- if (ret)
- goto err_probe_failed;
- return ret;
-
-err_probe_failed:
- pci_iounmap(pdev, host->regs);
-err_unmap:
- kfree(host);
-err_release:
- pci_release_regions(pdev);
-err_disable_dev:
- pci_disable_device(pdev);
- return ret;
-}
-
-static void __devexit dw_mci_pci_remove(struct pci_dev *pdev)
-{
- struct dw_mci *host = pci_get_drvdata(pdev);
-
- dw_mci_remove(host);
- pci_set_drvdata(pdev, NULL);
- pci_release_regions(pdev);
- pci_iounmap(pdev, host->regs);
- kfree(host);
- pci_disable_device(pdev);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int dw_mci_pci_suspend(struct device *dev)
-{
- int ret;
- struct pci_dev *pdev = to_pci_dev(dev);
- struct dw_mci *host = pci_get_drvdata(pdev);
-
- ret = dw_mci_suspend(host);
- return ret;
-}
-
-static int dw_mci_pci_resume(struct device *dev)
-{
- int ret;
- struct pci_dev *pdev = to_pci_dev(dev);
- struct dw_mci *host = pci_get_drvdata(pdev);
-
- ret = dw_mci_resume(host);
- return ret;
-}
-#else
-#define dw_mci_pci_suspend NULL
-#define dw_mci_pci_resume NULL
-#endif /* CONFIG_PM_SLEEP */
-
-static SIMPLE_DEV_PM_OPS(dw_mci_pci_pmops, dw_mci_pci_suspend, dw_mci_pci_resume);
-
-static DEFINE_PCI_DEVICE_TABLE(dw_mci_pci_id) = {
- { PCI_DEVICE(SYNOPSYS_DW_MCI_VENDOR_ID, SYNOPSYS_DW_MCI_DEVICE_ID) },
- {}
-};
-MODULE_DEVICE_TABLE(pci, dw_mci_pci_id);
-
-static struct pci_driver dw_mci_pci_driver = {
- .name = "dw_mmc_pci",
- .id_table = dw_mci_pci_id,
- .probe = dw_mci_pci_probe,
- .remove = dw_mci_pci_remove,
- .driver = {
- .pm = &dw_mci_pci_pmops
- },
-};
-
-static int __init dw_mci_init(void)
-{
- return pci_register_driver(&dw_mci_pci_driver);
-}
-
-static void __exit dw_mci_exit(void)
-{
- pci_unregister_driver(&dw_mci_pci_driver);
-}
-
-module_init(dw_mci_init);
-module_exit(dw_mci_exit);
-
-MODULE_DESCRIPTION("DW Multimedia Card PCI Interface driver");
-MODULE_AUTHOR("Shashidhar Hiremath <shashidharh@vayavyalabs.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/dw_mmc-pltfm.c b/ANDROID_3.4.5/drivers/mmc/host/dw_mmc-pltfm.c
deleted file mode 100644
index 92ec3eb3..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/dw_mmc-pltfm.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Synopsys DesignWare Multimedia Card Interface driver
- *
- * Copyright (C) 2009 NXP Semiconductors
- * Copyright (C) 2009, 2010 Imagination Technologies 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.
- */
-
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/dw_mmc.h>
-#include "dw_mmc.h"
-
-static int dw_mci_pltfm_probe(struct platform_device *pdev)
-{
- struct dw_mci *host;
- struct resource *regs;
- int ret;
-
- host = kzalloc(sizeof(struct dw_mci), GFP_KERNEL);
- if (!host)
- return -ENOMEM;
-
- regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!regs) {
- ret = -ENXIO;
- goto err_free;
- }
-
- host->irq = platform_get_irq(pdev, 0);
- if (host->irq < 0) {
- ret = host->irq;
- goto err_free;
- }
-
- host->dev = pdev->dev;
- host->irq_flags = 0;
- host->pdata = pdev->dev.platform_data;
- ret = -ENOMEM;
- host->regs = ioremap(regs->start, resource_size(regs));
- if (!host->regs)
- goto err_free;
- platform_set_drvdata(pdev, host);
- ret = dw_mci_probe(host);
- if (ret)
- goto err_out;
- return ret;
-err_out:
- iounmap(host->regs);
-err_free:
- kfree(host);
- return ret;
-}
-
-static int __exit dw_mci_pltfm_remove(struct platform_device *pdev)
-{
- struct dw_mci *host = platform_get_drvdata(pdev);
-
- platform_set_drvdata(pdev, NULL);
- dw_mci_remove(host);
- iounmap(host->regs);
- kfree(host);
- return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-/*
- * TODO: we should probably disable the clock to the card in the suspend path.
- */
-static int dw_mci_pltfm_suspend(struct device *dev)
-{
- int ret;
- struct dw_mci *host = dev_get_drvdata(dev);
-
- ret = dw_mci_suspend(host);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int dw_mci_pltfm_resume(struct device *dev)
-{
- int ret;
- struct dw_mci *host = dev_get_drvdata(dev);
-
- ret = dw_mci_resume(host);
- if (ret)
- return ret;
-
- return 0;
-}
-#else
-#define dw_mci_pltfm_suspend NULL
-#define dw_mci_pltfm_resume NULL
-#endif /* CONFIG_PM_SLEEP */
-
-static SIMPLE_DEV_PM_OPS(dw_mci_pltfm_pmops, dw_mci_pltfm_suspend, dw_mci_pltfm_resume);
-
-static struct platform_driver dw_mci_pltfm_driver = {
- .remove = __exit_p(dw_mci_pltfm_remove),
- .driver = {
- .name = "dw_mmc",
- .pm = &dw_mci_pltfm_pmops,
- },
-};
-
-static int __init dw_mci_init(void)
-{
- return platform_driver_probe(&dw_mci_pltfm_driver, dw_mci_pltfm_probe);
-}
-
-static void __exit dw_mci_exit(void)
-{
- platform_driver_unregister(&dw_mci_pltfm_driver);
-}
-
-module_init(dw_mci_init);
-module_exit(dw_mci_exit);
-
-MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
-MODULE_AUTHOR("NXP Semiconductor VietNam");
-MODULE_AUTHOR("Imagination Technologies Ltd");
-MODULE_LICENSE("GPL v2");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/dw_mmc.c b/ANDROID_3.4.5/drivers/mmc/host/dw_mmc.c
deleted file mode 100644
index ab3fc461..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/dw_mmc.c
+++ /dev/null
@@ -1,2221 +0,0 @@
-/*
- * Synopsys DesignWare Multimedia Card Interface driver
- * (Based on NXP driver for lpc 31xx)
- *
- * Copyright (C) 2009 NXP Semiconductors
- * Copyright (C) 2009, 2010 Imagination Technologies 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.
- */
-
-#include <linux/blkdev.h>
-#include <linux/clk.h>
-#include <linux/debugfs.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/stat.h>
-#include <linux/delay.h>
-#include <linux/irq.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/dw_mmc.h>
-#include <linux/bitops.h>
-#include <linux/regulator/consumer.h>
-#include <linux/workqueue.h>
-
-#include "dw_mmc.h"
-
-/* Common flag combinations */
-#define DW_MCI_DATA_ERROR_FLAGS (SDMMC_INT_DTO | SDMMC_INT_DCRC | \
- SDMMC_INT_HTO | SDMMC_INT_SBE | \
- SDMMC_INT_EBE)
-#define DW_MCI_CMD_ERROR_FLAGS (SDMMC_INT_RTO | SDMMC_INT_RCRC | \
- SDMMC_INT_RESP_ERR)
-#define DW_MCI_ERROR_FLAGS (DW_MCI_DATA_ERROR_FLAGS | \
- DW_MCI_CMD_ERROR_FLAGS | SDMMC_INT_HLE)
-#define DW_MCI_SEND_STATUS 1
-#define DW_MCI_RECV_STATUS 2
-#define DW_MCI_DMA_THRESHOLD 16
-
-#ifdef CONFIG_MMC_DW_IDMAC
-struct idmac_desc {
- u32 des0; /* Control Descriptor */
-#define IDMAC_DES0_DIC BIT(1)
-#define IDMAC_DES0_LD BIT(2)
-#define IDMAC_DES0_FD BIT(3)
-#define IDMAC_DES0_CH BIT(4)
-#define IDMAC_DES0_ER BIT(5)
-#define IDMAC_DES0_CES BIT(30)
-#define IDMAC_DES0_OWN BIT(31)
-
- u32 des1; /* Buffer sizes */
-#define IDMAC_SET_BUFFER1_SIZE(d, s) \
- ((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff))
-
- u32 des2; /* buffer 1 physical address */
-
- u32 des3; /* buffer 2 physical address */
-};
-#endif /* CONFIG_MMC_DW_IDMAC */
-
-/**
- * struct dw_mci_slot - MMC slot state
- * @mmc: The mmc_host representing this slot.
- * @host: The MMC controller this slot is using.
- * @ctype: Card type for this slot.
- * @mrq: mmc_request currently being processed or waiting to be
- * processed, or NULL when the slot is idle.
- * @queue_node: List node for placing this node in the @queue list of
- * &struct dw_mci.
- * @clock: Clock rate configured by set_ios(). Protected by host->lock.
- * @flags: Random state bits associated with the slot.
- * @id: Number of this slot.
- * @last_detect_state: Most recently observed card detect state.
- */
-struct dw_mci_slot {
- struct mmc_host *mmc;
- struct dw_mci *host;
-
- u32 ctype;
-
- struct mmc_request *mrq;
- struct list_head queue_node;
-
- unsigned int clock;
- unsigned long flags;
-#define DW_MMC_CARD_PRESENT 0
-#define DW_MMC_CARD_NEED_INIT 1
- int id;
- int last_detect_state;
-};
-
-static struct workqueue_struct *dw_mci_card_workqueue;
-
-#if defined(CONFIG_DEBUG_FS)
-static int dw_mci_req_show(struct seq_file *s, void *v)
-{
- struct dw_mci_slot *slot = s->private;
- struct mmc_request *mrq;
- struct mmc_command *cmd;
- struct mmc_command *stop;
- struct mmc_data *data;
-
- /* Make sure we get a consistent snapshot */
- spin_lock_bh(&slot->host->lock);
- mrq = slot->mrq;
-
- if (mrq) {
- cmd = mrq->cmd;
- data = mrq->data;
- stop = mrq->stop;
-
- if (cmd)
- seq_printf(s,
- "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
- cmd->opcode, cmd->arg, cmd->flags,
- cmd->resp[0], cmd->resp[1], cmd->resp[2],
- cmd->resp[2], cmd->error);
- if (data)
- seq_printf(s, "DATA %u / %u * %u flg %x err %d\n",
- data->bytes_xfered, data->blocks,
- data->blksz, data->flags, data->error);
- if (stop)
- seq_printf(s,
- "CMD%u(0x%x) flg %x rsp %x %x %x %x err %d\n",
- stop->opcode, stop->arg, stop->flags,
- stop->resp[0], stop->resp[1], stop->resp[2],
- stop->resp[2], stop->error);
- }
-
- spin_unlock_bh(&slot->host->lock);
-
- return 0;
-}
-
-static int dw_mci_req_open(struct inode *inode, struct file *file)
-{
- return single_open(file, dw_mci_req_show, inode->i_private);
-}
-
-static const struct file_operations dw_mci_req_fops = {
- .owner = THIS_MODULE,
- .open = dw_mci_req_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int dw_mci_regs_show(struct seq_file *s, void *v)
-{
- seq_printf(s, "STATUS:\t0x%08x\n", SDMMC_STATUS);
- seq_printf(s, "RINTSTS:\t0x%08x\n", SDMMC_RINTSTS);
- seq_printf(s, "CMD:\t0x%08x\n", SDMMC_CMD);
- seq_printf(s, "CTRL:\t0x%08x\n", SDMMC_CTRL);
- seq_printf(s, "INTMASK:\t0x%08x\n", SDMMC_INTMASK);
- seq_printf(s, "CLKENA:\t0x%08x\n", SDMMC_CLKENA);
-
- return 0;
-}
-
-static int dw_mci_regs_open(struct inode *inode, struct file *file)
-{
- return single_open(file, dw_mci_regs_show, inode->i_private);
-}
-
-static const struct file_operations dw_mci_regs_fops = {
- .owner = THIS_MODULE,
- .open = dw_mci_regs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static void dw_mci_init_debugfs(struct dw_mci_slot *slot)
-{
- struct mmc_host *mmc = slot->mmc;
- struct dw_mci *host = slot->host;
- struct dentry *root;
- struct dentry *node;
-
- root = mmc->debugfs_root;
- if (!root)
- return;
-
- node = debugfs_create_file("regs", S_IRUSR, root, host,
- &dw_mci_regs_fops);
- if (!node)
- goto err;
-
- node = debugfs_create_file("req", S_IRUSR, root, slot,
- &dw_mci_req_fops);
- if (!node)
- goto err;
-
- node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
- if (!node)
- goto err;
-
- node = debugfs_create_x32("pending_events", S_IRUSR, root,
- (u32 *)&host->pending_events);
- if (!node)
- goto err;
-
- node = debugfs_create_x32("completed_events", S_IRUSR, root,
- (u32 *)&host->completed_events);
- if (!node)
- goto err;
-
- return;
-
-err:
- dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
-}
-#endif /* defined(CONFIG_DEBUG_FS) */
-
-static void dw_mci_set_timeout(struct dw_mci *host)
-{
- /* timeout (maximum) */
- mci_writel(host, TMOUT, 0xffffffff);
-}
-
-static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
-{
- struct mmc_data *data;
- u32 cmdr;
- cmd->error = -EINPROGRESS;
-
- cmdr = cmd->opcode;
-
- if (cmdr == MMC_STOP_TRANSMISSION)
- cmdr |= SDMMC_CMD_STOP;
- else
- cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
-
- if (cmd->flags & MMC_RSP_PRESENT) {
- /* We expect a response, so set this bit */
- cmdr |= SDMMC_CMD_RESP_EXP;
- if (cmd->flags & MMC_RSP_136)
- cmdr |= SDMMC_CMD_RESP_LONG;
- }
-
- if (cmd->flags & MMC_RSP_CRC)
- cmdr |= SDMMC_CMD_RESP_CRC;
-
- data = cmd->data;
- if (data) {
- cmdr |= SDMMC_CMD_DAT_EXP;
- if (data->flags & MMC_DATA_STREAM)
- cmdr |= SDMMC_CMD_STRM_MODE;
- if (data->flags & MMC_DATA_WRITE)
- cmdr |= SDMMC_CMD_DAT_WR;
- }
-
- return cmdr;
-}
-
-static void dw_mci_start_command(struct dw_mci *host,
- struct mmc_command *cmd, u32 cmd_flags)
-{
- host->cmd = cmd;
- dev_vdbg(&host->dev,
- "start command: ARGR=0x%08x CMDR=0x%08x\n",
- cmd->arg, cmd_flags);
-
- mci_writel(host, CMDARG, cmd->arg);
- wmb();
-
- mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
-}
-
-static void send_stop_cmd(struct dw_mci *host, struct mmc_data *data)
-{
- dw_mci_start_command(host, data->stop, host->stop_cmdr);
-}
-
-/* DMA interface functions */
-static void dw_mci_stop_dma(struct dw_mci *host)
-{
- if (host->using_dma) {
- host->dma_ops->stop(host);
- host->dma_ops->cleanup(host);
- } else {
- /* Data transfer was stopped by the interrupt handler */
- set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
- }
-}
-
-static int dw_mci_get_dma_dir(struct mmc_data *data)
-{
- if (data->flags & MMC_DATA_WRITE)
- return DMA_TO_DEVICE;
- else
- return DMA_FROM_DEVICE;
-}
-
-#ifdef CONFIG_MMC_DW_IDMAC
-static void dw_mci_dma_cleanup(struct dw_mci *host)
-{
- struct mmc_data *data = host->data;
-
- if (data)
- if (!data->host_cookie)
- dma_unmap_sg(&host->dev,
- data->sg,
- data->sg_len,
- dw_mci_get_dma_dir(data));
-}
-
-static void dw_mci_idmac_stop_dma(struct dw_mci *host)
-{
- u32 temp;
-
- /* Disable and reset the IDMAC interface */
- temp = mci_readl(host, CTRL);
- temp &= ~SDMMC_CTRL_USE_IDMAC;
- temp |= SDMMC_CTRL_DMA_RESET;
- mci_writel(host, CTRL, temp);
-
- /* Stop the IDMAC running */
- temp = mci_readl(host, BMOD);
- temp &= ~(SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB);
- mci_writel(host, BMOD, temp);
-}
-
-static void dw_mci_idmac_complete_dma(struct dw_mci *host)
-{
- struct mmc_data *data = host->data;
-
- dev_vdbg(&host->dev, "DMA complete\n");
-
- host->dma_ops->cleanup(host);
-
- /*
- * If the card was removed, data will be NULL. No point in trying to
- * send the stop command or waiting for NBUSY in this case.
- */
- if (data) {
- set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
- tasklet_schedule(&host->tasklet);
- }
-}
-
-static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
- unsigned int sg_len)
-{
- int i;
- struct idmac_desc *desc = host->sg_cpu;
-
- for (i = 0; i < sg_len; i++, desc++) {
- unsigned int length = sg_dma_len(&data->sg[i]);
- u32 mem_addr = sg_dma_address(&data->sg[i]);
-
- /* Set the OWN bit and disable interrupts for this descriptor */
- desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH;
-
- /* Buffer length */
- IDMAC_SET_BUFFER1_SIZE(desc, length);
-
- /* Physical address to DMA to/from */
- desc->des2 = mem_addr;
- }
-
- /* Set first descriptor */
- desc = host->sg_cpu;
- desc->des0 |= IDMAC_DES0_FD;
-
- /* Set last descriptor */
- desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
- desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
- desc->des0 |= IDMAC_DES0_LD;
-
- wmb();
-}
-
-static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
-{
- u32 temp;
-
- dw_mci_translate_sglist(host, host->data, sg_len);
-
- /* Select IDMAC interface */
- temp = mci_readl(host, CTRL);
- temp |= SDMMC_CTRL_USE_IDMAC;
- mci_writel(host, CTRL, temp);
-
- wmb();
-
- /* Enable the IDMAC */
- temp = mci_readl(host, BMOD);
- temp |= SDMMC_IDMAC_ENABLE | SDMMC_IDMAC_FB;
- mci_writel(host, BMOD, temp);
-
- /* Start it running */
- mci_writel(host, PLDMND, 1);
-}
-
-static int dw_mci_idmac_init(struct dw_mci *host)
-{
- struct idmac_desc *p;
- int i;
-
- /* Number of descriptors in the ring buffer */
- host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
-
- /* Forward link the descriptor list */
- for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
- p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1));
-
- /* Set the last descriptor as the end-of-ring descriptor */
- p->des3 = host->sg_dma;
- p->des0 = IDMAC_DES0_ER;
-
- /* Mask out interrupts - get Tx & Rx complete only */
- mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI |
- SDMMC_IDMAC_INT_TI);
-
- /* Set the descriptor base address */
- mci_writel(host, DBADDR, host->sg_dma);
- return 0;
-}
-
-static struct dw_mci_dma_ops dw_mci_idmac_ops = {
- .init = dw_mci_idmac_init,
- .start = dw_mci_idmac_start_dma,
- .stop = dw_mci_idmac_stop_dma,
- .complete = dw_mci_idmac_complete_dma,
- .cleanup = dw_mci_dma_cleanup,
-};
-#endif /* CONFIG_MMC_DW_IDMAC */
-
-static int dw_mci_pre_dma_transfer(struct dw_mci *host,
- struct mmc_data *data,
- bool next)
-{
- struct scatterlist *sg;
- unsigned int i, sg_len;
-
- if (!next && data->host_cookie)
- return data->host_cookie;
-
- /*
- * We don't do DMA on "complex" transfers, i.e. with
- * non-word-aligned buffers or lengths. Also, we don't bother
- * with all the DMA setup overhead for short transfers.
- */
- if (data->blocks * data->blksz < DW_MCI_DMA_THRESHOLD)
- return -EINVAL;
-
- if (data->blksz & 3)
- return -EINVAL;
-
- for_each_sg(data->sg, sg, data->sg_len, i) {
- if (sg->offset & 3 || sg->length & 3)
- return -EINVAL;
- }
-
- sg_len = dma_map_sg(&host->dev,
- data->sg,
- data->sg_len,
- dw_mci_get_dma_dir(data));
- if (sg_len == 0)
- return -EINVAL;
-
- if (next)
- data->host_cookie = sg_len;
-
- return sg_len;
-}
-
-static void dw_mci_pre_req(struct mmc_host *mmc,
- struct mmc_request *mrq,
- bool is_first_req)
-{
- struct dw_mci_slot *slot = mmc_priv(mmc);
- struct mmc_data *data = mrq->data;
-
- if (!slot->host->use_dma || !data)
- return;
-
- if (data->host_cookie) {
- data->host_cookie = 0;
- return;
- }
-
- if (dw_mci_pre_dma_transfer(slot->host, mrq->data, 1) < 0)
- data->host_cookie = 0;
-}
-
-static void dw_mci_post_req(struct mmc_host *mmc,
- struct mmc_request *mrq,
- int err)
-{
- struct dw_mci_slot *slot = mmc_priv(mmc);
- struct mmc_data *data = mrq->data;
-
- if (!slot->host->use_dma || !data)
- return;
-
- if (data->host_cookie)
- dma_unmap_sg(&slot->host->dev,
- data->sg,
- data->sg_len,
- dw_mci_get_dma_dir(data));
- data->host_cookie = 0;
-}
-
-static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
-{
- int sg_len;
- u32 temp;
-
- host->using_dma = 0;
-
- /* If we don't have a channel, we can't do DMA */
- if (!host->use_dma)
- return -ENODEV;
-
- sg_len = dw_mci_pre_dma_transfer(host, data, 0);
- if (sg_len < 0) {
- host->dma_ops->stop(host);
- return sg_len;
- }
-
- host->using_dma = 1;
-
- dev_vdbg(&host->dev,
- "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
- (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
- sg_len);
-
- /* Enable the DMA interface */
- temp = mci_readl(host, CTRL);
- temp |= SDMMC_CTRL_DMA_ENABLE;
- mci_writel(host, CTRL, temp);
-
- /* Disable RX/TX IRQs, let DMA handle it */
- temp = mci_readl(host, INTMASK);
- temp &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR);
- mci_writel(host, INTMASK, temp);
-
- host->dma_ops->start(host, sg_len);
-
- return 0;
-}
-
-static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
-{
- u32 temp;
-
- data->error = -EINPROGRESS;
-
- WARN_ON(host->data);
- host->sg = NULL;
- host->data = data;
-
- if (data->flags & MMC_DATA_READ)
- host->dir_status = DW_MCI_RECV_STATUS;
- else
- host->dir_status = DW_MCI_SEND_STATUS;
-
- if (dw_mci_submit_data_dma(host, data)) {
- int flags = SG_MITER_ATOMIC;
- if (host->data->flags & MMC_DATA_READ)
- flags |= SG_MITER_TO_SG;
- else
- flags |= SG_MITER_FROM_SG;
-
- sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
- host->sg = data->sg;
- host->part_buf_start = 0;
- host->part_buf_count = 0;
-
- mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR);
- temp = mci_readl(host, INTMASK);
- temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR;
- mci_writel(host, INTMASK, temp);
-
- temp = mci_readl(host, CTRL);
- temp &= ~SDMMC_CTRL_DMA_ENABLE;
- mci_writel(host, CTRL, temp);
- }
-}
-
-static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
-{
- struct dw_mci *host = slot->host;
- unsigned long timeout = jiffies + msecs_to_jiffies(500);
- unsigned int cmd_status = 0;
-
- mci_writel(host, CMDARG, arg);
- wmb();
- mci_writel(host, CMD, SDMMC_CMD_START | cmd);
-
- while (time_before(jiffies, timeout)) {
- cmd_status = mci_readl(host, CMD);
- if (!(cmd_status & SDMMC_CMD_START))
- return;
- }
- dev_err(&slot->mmc->class_dev,
- "Timeout sending command (cmd %#x arg %#x status %#x)\n",
- cmd, arg, cmd_status);
-}
-
-static void dw_mci_setup_bus(struct dw_mci_slot *slot)
-{
- struct dw_mci *host = slot->host;
- u32 div;
-
- if (slot->clock != host->current_speed) {
- if (host->bus_hz % slot->clock)
- /*
- * move the + 1 after the divide to prevent
- * over-clocking the card.
- */
- div = ((host->bus_hz / slot->clock) >> 1) + 1;
- else
- div = (host->bus_hz / slot->clock) >> 1;
-
- dev_info(&slot->mmc->class_dev,
- "Bus speed (slot %d) = %dHz (slot req %dHz, actual %dHZ"
- " div = %d)\n", slot->id, host->bus_hz, slot->clock,
- div ? ((host->bus_hz / div) >> 1) : host->bus_hz, div);
-
- /* disable clock */
- mci_writel(host, CLKENA, 0);
- mci_writel(host, CLKSRC, 0);
-
- /* inform CIU */
- mci_send_cmd(slot,
- SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
-
- /* set clock to desired speed */
- mci_writel(host, CLKDIV, div);
-
- /* inform CIU */
- mci_send_cmd(slot,
- SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
-
- /* enable clock */
- mci_writel(host, CLKENA, ((SDMMC_CLKEN_ENABLE |
- SDMMC_CLKEN_LOW_PWR) << slot->id));
-
- /* inform CIU */
- mci_send_cmd(slot,
- SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
-
- host->current_speed = slot->clock;
- }
-
- /* Set the current slot bus width */
- mci_writel(host, CTYPE, (slot->ctype << slot->id));
-}
-
-static void __dw_mci_start_request(struct dw_mci *host,
- struct dw_mci_slot *slot,
- struct mmc_command *cmd)
-{
- struct mmc_request *mrq;
- struct mmc_data *data;
- u32 cmdflags;
-
- mrq = slot->mrq;
- if (host->pdata->select_slot)
- host->pdata->select_slot(slot->id);
-
- /* Slot specific timing and width adjustment */
- dw_mci_setup_bus(slot);
-
- host->cur_slot = slot;
- host->mrq = mrq;
-
- host->pending_events = 0;
- host->completed_events = 0;
- host->data_status = 0;
-
- data = cmd->data;
- if (data) {
- dw_mci_set_timeout(host);
- mci_writel(host, BYTCNT, data->blksz*data->blocks);
- mci_writel(host, BLKSIZ, data->blksz);
- }
-
- cmdflags = dw_mci_prepare_command(slot->mmc, cmd);
-
- /* this is the first command, send the initialization clock */
- if (test_and_clear_bit(DW_MMC_CARD_NEED_INIT, &slot->flags))
- cmdflags |= SDMMC_CMD_INIT;
-
- if (data) {
- dw_mci_submit_data(host, data);
- wmb();
- }
-
- dw_mci_start_command(host, cmd, cmdflags);
-
- if (mrq->stop)
- host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop);
-}
-
-static void dw_mci_start_request(struct dw_mci *host,
- struct dw_mci_slot *slot)
-{
- struct mmc_request *mrq = slot->mrq;
- struct mmc_command *cmd;
-
- cmd = mrq->sbc ? mrq->sbc : mrq->cmd;
- __dw_mci_start_request(host, slot, cmd);
-}
-
-/* must be called with host->lock held */
-static void dw_mci_queue_request(struct dw_mci *host, struct dw_mci_slot *slot,
- struct mmc_request *mrq)
-{
- dev_vdbg(&slot->mmc->class_dev, "queue request: state=%d\n",
- host->state);
-
- slot->mrq = mrq;
-
- if (host->state == STATE_IDLE) {
- host->state = STATE_SENDING_CMD;
- dw_mci_start_request(host, slot);
- } else {
- list_add_tail(&slot->queue_node, &host->queue);
- }
-}
-
-static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct dw_mci_slot *slot = mmc_priv(mmc);
- struct dw_mci *host = slot->host;
-
- WARN_ON(slot->mrq);
-
- /*
- * The check for card presence and queueing of the request must be
- * atomic, otherwise the card could be removed in between and the
- * request wouldn't fail until another card was inserted.
- */
- spin_lock_bh(&host->lock);
-
- if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
- spin_unlock_bh(&host->lock);
- mrq->cmd->error = -ENOMEDIUM;
- mmc_request_done(mmc, mrq);
- return;
- }
-
- dw_mci_queue_request(host, slot, mrq);
-
- spin_unlock_bh(&host->lock);
-}
-
-static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct dw_mci_slot *slot = mmc_priv(mmc);
- u32 regs;
-
- /* set default 1 bit mode */
- slot->ctype = SDMMC_CTYPE_1BIT;
-
- switch (ios->bus_width) {
- case MMC_BUS_WIDTH_1:
- slot->ctype = SDMMC_CTYPE_1BIT;
- break;
- case MMC_BUS_WIDTH_4:
- slot->ctype = SDMMC_CTYPE_4BIT;
- break;
- case MMC_BUS_WIDTH_8:
- slot->ctype = SDMMC_CTYPE_8BIT;
- break;
- }
-
- regs = mci_readl(slot->host, UHS_REG);
-
- /* DDR mode set */
- if (ios->timing == MMC_TIMING_UHS_DDR50)
- regs |= (0x1 << slot->id) << 16;
- else
- regs &= ~(0x1 << slot->id) << 16;
-
- mci_writel(slot->host, UHS_REG, regs);
-
- if (ios->clock) {
- /*
- * Use mirror of ios->clock to prevent race with mmc
- * core ios update when finding the minimum.
- */
- slot->clock = ios->clock;
- }
-
- switch (ios->power_mode) {
- case MMC_POWER_UP:
- set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
- break;
- default:
- break;
- }
-}
-
-static int dw_mci_get_ro(struct mmc_host *mmc)
-{
- int read_only;
- struct dw_mci_slot *slot = mmc_priv(mmc);
- struct dw_mci_board *brd = slot->host->pdata;
-
- /* Use platform get_ro function, else try on board write protect */
- if (brd->get_ro)
- read_only = brd->get_ro(slot->id);
- else
- read_only =
- mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0;
-
- dev_dbg(&mmc->class_dev, "card is %s\n",
- read_only ? "read-only" : "read-write");
-
- return read_only;
-}
-
-static int dw_mci_get_cd(struct mmc_host *mmc)
-{
- int present;
- struct dw_mci_slot *slot = mmc_priv(mmc);
- struct dw_mci_board *brd = slot->host->pdata;
-
- /* Use platform get_cd function, else try onboard card detect */
- if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
- present = 1;
- else if (brd->get_cd)
- present = !brd->get_cd(slot->id);
- else
- present = (mci_readl(slot->host, CDETECT) & (1 << slot->id))
- == 0 ? 1 : 0;
-
- if (present)
- dev_dbg(&mmc->class_dev, "card is present\n");
- else
- dev_dbg(&mmc->class_dev, "card is not present\n");
-
- return present;
-}
-
-static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
-{
- struct dw_mci_slot *slot = mmc_priv(mmc);
- struct dw_mci *host = slot->host;
- u32 int_mask;
-
- /* Enable/disable Slot Specific SDIO interrupt */
- int_mask = mci_readl(host, INTMASK);
- if (enb) {
- mci_writel(host, INTMASK,
- (int_mask | (1 << SDMMC_INT_SDIO(slot->id))));
- } else {
- mci_writel(host, INTMASK,
- (int_mask & ~(1 << SDMMC_INT_SDIO(slot->id))));
- }
-}
-
-static const struct mmc_host_ops dw_mci_ops = {
- .request = dw_mci_request,
- .pre_req = dw_mci_pre_req,
- .post_req = dw_mci_post_req,
- .set_ios = dw_mci_set_ios,
- .get_ro = dw_mci_get_ro,
- .get_cd = dw_mci_get_cd,
- .enable_sdio_irq = dw_mci_enable_sdio_irq,
-};
-
-static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
- __releases(&host->lock)
- __acquires(&host->lock)
-{
- struct dw_mci_slot *slot;
- struct mmc_host *prev_mmc = host->cur_slot->mmc;
-
- WARN_ON(host->cmd || host->data);
-
- host->cur_slot->mrq = NULL;
- host->mrq = NULL;
- if (!list_empty(&host->queue)) {
- slot = list_entry(host->queue.next,
- struct dw_mci_slot, queue_node);
- list_del(&slot->queue_node);
- dev_vdbg(&host->dev, "list not empty: %s is next\n",
- mmc_hostname(slot->mmc));
- host->state = STATE_SENDING_CMD;
- dw_mci_start_request(host, slot);
- } else {
- dev_vdbg(&host->dev, "list empty\n");
- host->state = STATE_IDLE;
- }
-
- spin_unlock(&host->lock);
- mmc_request_done(prev_mmc, mrq);
- spin_lock(&host->lock);
-}
-
-static void dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd)
-{
- u32 status = host->cmd_status;
-
- host->cmd_status = 0;
-
- /* Read the response from the card (up to 16 bytes) */
- if (cmd->flags & MMC_RSP_PRESENT) {
- if (cmd->flags & MMC_RSP_136) {
- cmd->resp[3] = mci_readl(host, RESP0);
- cmd->resp[2] = mci_readl(host, RESP1);
- cmd->resp[1] = mci_readl(host, RESP2);
- cmd->resp[0] = mci_readl(host, RESP3);
- } else {
- cmd->resp[0] = mci_readl(host, RESP0);
- cmd->resp[1] = 0;
- cmd->resp[2] = 0;
- cmd->resp[3] = 0;
- }
- }
-
- if (status & SDMMC_INT_RTO)
- cmd->error = -ETIMEDOUT;
- else if ((cmd->flags & MMC_RSP_CRC) && (status & SDMMC_INT_RCRC))
- cmd->error = -EILSEQ;
- else if (status & SDMMC_INT_RESP_ERR)
- cmd->error = -EIO;
- else
- cmd->error = 0;
-
- if (cmd->error) {
- /* newer ip versions need a delay between retries */
- if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY)
- mdelay(20);
-
- if (cmd->data) {
- host->data = NULL;
- dw_mci_stop_dma(host);
- }
- }
-}
-
-static void dw_mci_tasklet_func(unsigned long priv)
-{
- struct dw_mci *host = (struct dw_mci *)priv;
- struct mmc_data *data;
- struct mmc_command *cmd;
- enum dw_mci_state state;
- enum dw_mci_state prev_state;
- u32 status, ctrl;
-
- spin_lock(&host->lock);
-
- state = host->state;
- data = host->data;
-
- do {
- prev_state = state;
-
- switch (state) {
- case STATE_IDLE:
- break;
-
- case STATE_SENDING_CMD:
- if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
- &host->pending_events))
- break;
-
- cmd = host->cmd;
- host->cmd = NULL;
- set_bit(EVENT_CMD_COMPLETE, &host->completed_events);
- dw_mci_command_complete(host, cmd);
- if (cmd == host->mrq->sbc && !cmd->error) {
- prev_state = state = STATE_SENDING_CMD;
- __dw_mci_start_request(host, host->cur_slot,
- host->mrq->cmd);
- goto unlock;
- }
-
- if (!host->mrq->data || cmd->error) {
- dw_mci_request_end(host, host->mrq);
- goto unlock;
- }
-
- prev_state = state = STATE_SENDING_DATA;
- /* fall through */
-
- case STATE_SENDING_DATA:
- if (test_and_clear_bit(EVENT_DATA_ERROR,
- &host->pending_events)) {
- dw_mci_stop_dma(host);
- if (data->stop)
- send_stop_cmd(host, data);
- state = STATE_DATA_ERROR;
- break;
- }
-
- if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
- &host->pending_events))
- break;
-
- set_bit(EVENT_XFER_COMPLETE, &host->completed_events);
- prev_state = state = STATE_DATA_BUSY;
- /* fall through */
-
- case STATE_DATA_BUSY:
- if (!test_and_clear_bit(EVENT_DATA_COMPLETE,
- &host->pending_events))
- break;
-
- host->data = NULL;
- set_bit(EVENT_DATA_COMPLETE, &host->completed_events);
- status = host->data_status;
-
- if (status & DW_MCI_DATA_ERROR_FLAGS) {
- if (status & SDMMC_INT_DTO) {
- data->error = -ETIMEDOUT;
- } else if (status & SDMMC_INT_DCRC) {
- data->error = -EILSEQ;
- } else if (status & SDMMC_INT_EBE &&
- host->dir_status ==
- DW_MCI_SEND_STATUS) {
- /*
- * No data CRC status was returned.
- * The number of bytes transferred will
- * be exaggerated in PIO mode.
- */
- data->bytes_xfered = 0;
- data->error = -ETIMEDOUT;
- } else {
- dev_err(&host->dev,
- "data FIFO error "
- "(status=%08x)\n",
- status);
- data->error = -EIO;
- }
- /*
- * After an error, there may be data lingering
- * in the FIFO, so reset it - doing so
- * generates a block interrupt, hence setting
- * the scatter-gather pointer to NULL.
- */
- sg_miter_stop(&host->sg_miter);
- host->sg = NULL;
- ctrl = mci_readl(host, CTRL);
- ctrl |= SDMMC_CTRL_FIFO_RESET;
- mci_writel(host, CTRL, ctrl);
- } else {
- data->bytes_xfered = data->blocks * data->blksz;
- data->error = 0;
- }
-
- if (!data->stop) {
- dw_mci_request_end(host, host->mrq);
- goto unlock;
- }
-
- if (host->mrq->sbc && !data->error) {
- data->stop->error = 0;
- dw_mci_request_end(host, host->mrq);
- goto unlock;
- }
-
- prev_state = state = STATE_SENDING_STOP;
- if (!data->error)
- send_stop_cmd(host, data);
- /* fall through */
-
- case STATE_SENDING_STOP:
- if (!test_and_clear_bit(EVENT_CMD_COMPLETE,
- &host->pending_events))
- break;
-
- host->cmd = NULL;
- dw_mci_command_complete(host, host->mrq->stop);
- dw_mci_request_end(host, host->mrq);
- goto unlock;
-
- case STATE_DATA_ERROR:
- if (!test_and_clear_bit(EVENT_XFER_COMPLETE,
- &host->pending_events))
- break;
-
- state = STATE_DATA_BUSY;
- break;
- }
- } while (state != prev_state);
-
- host->state = state;
-unlock:
- spin_unlock(&host->lock);
-
-}
-
-/* push final bytes to part_buf, only use during push */
-static void dw_mci_set_part_bytes(struct dw_mci *host, void *buf, int cnt)
-{
- memcpy((void *)&host->part_buf, buf, cnt);
- host->part_buf_count = cnt;
-}
-
-/* append bytes to part_buf, only use during push */
-static int dw_mci_push_part_bytes(struct dw_mci *host, void *buf, int cnt)
-{
- cnt = min(cnt, (1 << host->data_shift) - host->part_buf_count);
- memcpy((void *)&host->part_buf + host->part_buf_count, buf, cnt);
- host->part_buf_count += cnt;
- return cnt;
-}
-
-/* pull first bytes from part_buf, only use during pull */
-static int dw_mci_pull_part_bytes(struct dw_mci *host, void *buf, int cnt)
-{
- cnt = min(cnt, (int)host->part_buf_count);
- if (cnt) {
- memcpy(buf, (void *)&host->part_buf + host->part_buf_start,
- cnt);
- host->part_buf_count -= cnt;
- host->part_buf_start += cnt;
- }
- return cnt;
-}
-
-/* pull final bytes from the part_buf, assuming it's just been filled */
-static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt)
-{
- memcpy(buf, &host->part_buf, cnt);
- host->part_buf_start = cnt;
- host->part_buf_count = (1 << host->data_shift) - cnt;
-}
-
-static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
-{
- /* try and push anything in the part_buf */
- if (unlikely(host->part_buf_count)) {
- int len = dw_mci_push_part_bytes(host, buf, cnt);
- buf += len;
- cnt -= len;
- if (!sg_next(host->sg) || host->part_buf_count == 2) {
- mci_writew(host, DATA(host->data_offset),
- host->part_buf16);
- host->part_buf_count = 0;
- }
- }
-#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
- if (unlikely((unsigned long)buf & 0x1)) {
- while (cnt >= 2) {
- u16 aligned_buf[64];
- int len = min(cnt & -2, (int)sizeof(aligned_buf));
- int items = len >> 1;
- int i;
- /* memcpy from input buffer into aligned buffer */
- memcpy(aligned_buf, buf, len);
- buf += len;
- cnt -= len;
- /* push data from aligned buffer into fifo */
- for (i = 0; i < items; ++i)
- mci_writew(host, DATA(host->data_offset),
- aligned_buf[i]);
- }
- } else
-#endif
- {
- u16 *pdata = buf;
- for (; cnt >= 2; cnt -= 2)
- mci_writew(host, DATA(host->data_offset), *pdata++);
- buf = pdata;
- }
- /* put anything remaining in the part_buf */
- if (cnt) {
- dw_mci_set_part_bytes(host, buf, cnt);
- if (!sg_next(host->sg))
- mci_writew(host, DATA(host->data_offset),
- host->part_buf16);
- }
-}
-
-static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt)
-{
-#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
- if (unlikely((unsigned long)buf & 0x1)) {
- while (cnt >= 2) {
- /* pull data from fifo into aligned buffer */
- u16 aligned_buf[64];
- int len = min(cnt & -2, (int)sizeof(aligned_buf));
- int items = len >> 1;
- int i;
- for (i = 0; i < items; ++i)
- aligned_buf[i] = mci_readw(host,
- DATA(host->data_offset));
- /* memcpy from aligned buffer into output buffer */
- memcpy(buf, aligned_buf, len);
- buf += len;
- cnt -= len;
- }
- } else
-#endif
- {
- u16 *pdata = buf;
- for (; cnt >= 2; cnt -= 2)
- *pdata++ = mci_readw(host, DATA(host->data_offset));
- buf = pdata;
- }
- if (cnt) {
- host->part_buf16 = mci_readw(host, DATA(host->data_offset));
- dw_mci_pull_final_bytes(host, buf, cnt);
- }
-}
-
-static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
-{
- /* try and push anything in the part_buf */
- if (unlikely(host->part_buf_count)) {
- int len = dw_mci_push_part_bytes(host, buf, cnt);
- buf += len;
- cnt -= len;
- if (!sg_next(host->sg) || host->part_buf_count == 4) {
- mci_writel(host, DATA(host->data_offset),
- host->part_buf32);
- host->part_buf_count = 0;
- }
- }
-#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
- if (unlikely((unsigned long)buf & 0x3)) {
- while (cnt >= 4) {
- u32 aligned_buf[32];
- int len = min(cnt & -4, (int)sizeof(aligned_buf));
- int items = len >> 2;
- int i;
- /* memcpy from input buffer into aligned buffer */
- memcpy(aligned_buf, buf, len);
- buf += len;
- cnt -= len;
- /* push data from aligned buffer into fifo */
- for (i = 0; i < items; ++i)
- mci_writel(host, DATA(host->data_offset),
- aligned_buf[i]);
- }
- } else
-#endif
- {
- u32 *pdata = buf;
- for (; cnt >= 4; cnt -= 4)
- mci_writel(host, DATA(host->data_offset), *pdata++);
- buf = pdata;
- }
- /* put anything remaining in the part_buf */
- if (cnt) {
- dw_mci_set_part_bytes(host, buf, cnt);
- if (!sg_next(host->sg))
- mci_writel(host, DATA(host->data_offset),
- host->part_buf32);
- }
-}
-
-static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt)
-{
-#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
- if (unlikely((unsigned long)buf & 0x3)) {
- while (cnt >= 4) {
- /* pull data from fifo into aligned buffer */
- u32 aligned_buf[32];
- int len = min(cnt & -4, (int)sizeof(aligned_buf));
- int items = len >> 2;
- int i;
- for (i = 0; i < items; ++i)
- aligned_buf[i] = mci_readl(host,
- DATA(host->data_offset));
- /* memcpy from aligned buffer into output buffer */
- memcpy(buf, aligned_buf, len);
- buf += len;
- cnt -= len;
- }
- } else
-#endif
- {
- u32 *pdata = buf;
- for (; cnt >= 4; cnt -= 4)
- *pdata++ = mci_readl(host, DATA(host->data_offset));
- buf = pdata;
- }
- if (cnt) {
- host->part_buf32 = mci_readl(host, DATA(host->data_offset));
- dw_mci_pull_final_bytes(host, buf, cnt);
- }
-}
-
-static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
-{
- /* try and push anything in the part_buf */
- if (unlikely(host->part_buf_count)) {
- int len = dw_mci_push_part_bytes(host, buf, cnt);
- buf += len;
- cnt -= len;
- if (!sg_next(host->sg) || host->part_buf_count == 8) {
- mci_writew(host, DATA(host->data_offset),
- host->part_buf);
- host->part_buf_count = 0;
- }
- }
-#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
- if (unlikely((unsigned long)buf & 0x7)) {
- while (cnt >= 8) {
- u64 aligned_buf[16];
- int len = min(cnt & -8, (int)sizeof(aligned_buf));
- int items = len >> 3;
- int i;
- /* memcpy from input buffer into aligned buffer */
- memcpy(aligned_buf, buf, len);
- buf += len;
- cnt -= len;
- /* push data from aligned buffer into fifo */
- for (i = 0; i < items; ++i)
- mci_writeq(host, DATA(host->data_offset),
- aligned_buf[i]);
- }
- } else
-#endif
- {
- u64 *pdata = buf;
- for (; cnt >= 8; cnt -= 8)
- mci_writeq(host, DATA(host->data_offset), *pdata++);
- buf = pdata;
- }
- /* put anything remaining in the part_buf */
- if (cnt) {
- dw_mci_set_part_bytes(host, buf, cnt);
- if (!sg_next(host->sg))
- mci_writeq(host, DATA(host->data_offset),
- host->part_buf);
- }
-}
-
-static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt)
-{
-#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
- if (unlikely((unsigned long)buf & 0x7)) {
- while (cnt >= 8) {
- /* pull data from fifo into aligned buffer */
- u64 aligned_buf[16];
- int len = min(cnt & -8, (int)sizeof(aligned_buf));
- int items = len >> 3;
- int i;
- for (i = 0; i < items; ++i)
- aligned_buf[i] = mci_readq(host,
- DATA(host->data_offset));
- /* memcpy from aligned buffer into output buffer */
- memcpy(buf, aligned_buf, len);
- buf += len;
- cnt -= len;
- }
- } else
-#endif
- {
- u64 *pdata = buf;
- for (; cnt >= 8; cnt -= 8)
- *pdata++ = mci_readq(host, DATA(host->data_offset));
- buf = pdata;
- }
- if (cnt) {
- host->part_buf = mci_readq(host, DATA(host->data_offset));
- dw_mci_pull_final_bytes(host, buf, cnt);
- }
-}
-
-static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt)
-{
- int len;
-
- /* get remaining partial bytes */
- len = dw_mci_pull_part_bytes(host, buf, cnt);
- if (unlikely(len == cnt))
- return;
- buf += len;
- cnt -= len;
-
- /* get the rest of the data */
- host->pull_data(host, buf, cnt);
-}
-
-static void dw_mci_read_data_pio(struct dw_mci *host)
-{
- struct sg_mapping_iter *sg_miter = &host->sg_miter;
- void *buf;
- unsigned int offset;
- struct mmc_data *data = host->data;
- int shift = host->data_shift;
- u32 status;
- unsigned int nbytes = 0, len;
- unsigned int remain, fcnt;
-
- do {
- if (!sg_miter_next(sg_miter))
- goto done;
-
- host->sg = sg_miter->__sg;
- buf = sg_miter->addr;
- remain = sg_miter->length;
- offset = 0;
-
- do {
- fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS))
- << shift) + host->part_buf_count;
- len = min(remain, fcnt);
- if (!len)
- break;
- dw_mci_pull_data(host, (void *)(buf + offset), len);
- offset += len;
- nbytes += len;
- remain -= len;
- } while (remain);
- sg_miter->consumed = offset;
-
- status = mci_readl(host, MINTSTS);
- mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
- if (status & DW_MCI_DATA_ERROR_FLAGS) {
- host->data_status = status;
- data->bytes_xfered += nbytes;
- sg_miter_stop(sg_miter);
- host->sg = NULL;
- smp_wmb();
-
- set_bit(EVENT_DATA_ERROR, &host->pending_events);
-
- tasklet_schedule(&host->tasklet);
- return;
- }
- } while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/
- data->bytes_xfered += nbytes;
-
- if (!remain) {
- if (!sg_miter_next(sg_miter))
- goto done;
- sg_miter->consumed = 0;
- }
- sg_miter_stop(sg_miter);
- return;
-
-done:
- data->bytes_xfered += nbytes;
- sg_miter_stop(sg_miter);
- host->sg = NULL;
- smp_wmb();
- set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
-}
-
-static void dw_mci_write_data_pio(struct dw_mci *host)
-{
- struct sg_mapping_iter *sg_miter = &host->sg_miter;
- void *buf;
- unsigned int offset;
- struct mmc_data *data = host->data;
- int shift = host->data_shift;
- u32 status;
- unsigned int nbytes = 0, len;
- unsigned int fifo_depth = host->fifo_depth;
- unsigned int remain, fcnt;
-
- do {
- if (!sg_miter_next(sg_miter))
- goto done;
-
- host->sg = sg_miter->__sg;
- buf = sg_miter->addr;
- remain = sg_miter->length;
- offset = 0;
-
- do {
- fcnt = ((fifo_depth -
- SDMMC_GET_FCNT(mci_readl(host, STATUS)))
- << shift) - host->part_buf_count;
- len = min(remain, fcnt);
- if (!len)
- break;
- host->push_data(host, (void *)(buf + offset), len);
- offset += len;
- nbytes += len;
- remain -= len;
- } while (remain);
- sg_miter->consumed = offset;
-
- status = mci_readl(host, MINTSTS);
- mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
- if (status & DW_MCI_DATA_ERROR_FLAGS) {
- host->data_status = status;
- data->bytes_xfered += nbytes;
- sg_miter_stop(sg_miter);
- host->sg = NULL;
-
- smp_wmb();
-
- set_bit(EVENT_DATA_ERROR, &host->pending_events);
-
- tasklet_schedule(&host->tasklet);
- return;
- }
- } while (status & SDMMC_INT_TXDR); /* if TXDR write again */
- data->bytes_xfered += nbytes;
-
- if (!remain) {
- if (!sg_miter_next(sg_miter))
- goto done;
- sg_miter->consumed = 0;
- }
- sg_miter_stop(sg_miter);
- return;
-
-done:
- data->bytes_xfered += nbytes;
- sg_miter_stop(sg_miter);
- host->sg = NULL;
- smp_wmb();
- set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
-}
-
-static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
-{
- if (!host->cmd_status)
- host->cmd_status = status;
-
- smp_wmb();
-
- set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
- tasklet_schedule(&host->tasklet);
-}
-
-static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
-{
- struct dw_mci *host = dev_id;
- u32 status, pending;
- unsigned int pass_count = 0;
- int i;
-
- do {
- status = mci_readl(host, RINTSTS);
- pending = mci_readl(host, MINTSTS); /* read-only mask reg */
-
- /*
- * DTO fix - version 2.10a and below, and only if internal DMA
- * is configured.
- */
- if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) {
- if (!pending &&
- ((mci_readl(host, STATUS) >> 17) & 0x1fff))
- pending |= SDMMC_INT_DATA_OVER;
- }
-
- if (!pending)
- break;
-
- if (pending & DW_MCI_CMD_ERROR_FLAGS) {
- mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
- host->cmd_status = status;
- smp_wmb();
- set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
- }
-
- if (pending & DW_MCI_DATA_ERROR_FLAGS) {
- /* if there is an error report DATA_ERROR */
- mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS);
- host->data_status = status;
- smp_wmb();
- set_bit(EVENT_DATA_ERROR, &host->pending_events);
- if (!(pending & (SDMMC_INT_DTO | SDMMC_INT_DCRC |
- SDMMC_INT_SBE | SDMMC_INT_EBE)))
- tasklet_schedule(&host->tasklet);
- }
-
- if (pending & SDMMC_INT_DATA_OVER) {
- mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
- if (!host->data_status)
- host->data_status = status;
- smp_wmb();
- if (host->dir_status == DW_MCI_RECV_STATUS) {
- if (host->sg != NULL)
- dw_mci_read_data_pio(host);
- }
- set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
- tasklet_schedule(&host->tasklet);
- }
-
- if (pending & SDMMC_INT_RXDR) {
- mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
- if (host->dir_status == DW_MCI_RECV_STATUS && host->sg)
- dw_mci_read_data_pio(host);
- }
-
- if (pending & SDMMC_INT_TXDR) {
- mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
- if (host->dir_status == DW_MCI_SEND_STATUS && host->sg)
- dw_mci_write_data_pio(host);
- }
-
- if (pending & SDMMC_INT_CMD_DONE) {
- mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
- dw_mci_cmd_interrupt(host, status);
- }
-
- if (pending & SDMMC_INT_CD) {
- mci_writel(host, RINTSTS, SDMMC_INT_CD);
- queue_work(dw_mci_card_workqueue, &host->card_work);
- }
-
- /* Handle SDIO Interrupts */
- for (i = 0; i < host->num_slots; i++) {
- struct dw_mci_slot *slot = host->slot[i];
- if (pending & SDMMC_INT_SDIO(i)) {
- mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
- mmc_signal_sdio_irq(slot->mmc);
- }
- }
-
- } while (pass_count++ < 5);
-
-#ifdef CONFIG_MMC_DW_IDMAC
- /* Handle DMA interrupts */
- pending = mci_readl(host, IDSTS);
- if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
- mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI);
- mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
- set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
- host->dma_ops->complete(host);
- }
-#endif
-
- return IRQ_HANDLED;
-}
-
-static void dw_mci_work_routine_card(struct work_struct *work)
-{
- struct dw_mci *host = container_of(work, struct dw_mci, card_work);
- int i;
-
- for (i = 0; i < host->num_slots; i++) {
- struct dw_mci_slot *slot = host->slot[i];
- struct mmc_host *mmc = slot->mmc;
- struct mmc_request *mrq;
- int present;
- u32 ctrl;
-
- present = dw_mci_get_cd(mmc);
- while (present != slot->last_detect_state) {
- dev_dbg(&slot->mmc->class_dev, "card %s\n",
- present ? "inserted" : "removed");
-
- /* Power up slot (before spin_lock, may sleep) */
- if (present != 0 && host->pdata->setpower)
- host->pdata->setpower(slot->id, mmc->ocr_avail);
-
- spin_lock_bh(&host->lock);
-
- /* Card change detected */
- slot->last_detect_state = present;
-
- /* Mark card as present if applicable */
- if (present != 0)
- set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-
- /* Clean up queue if present */
- mrq = slot->mrq;
- if (mrq) {
- if (mrq == host->mrq) {
- host->data = NULL;
- host->cmd = NULL;
-
- switch (host->state) {
- case STATE_IDLE:
- break;
- case STATE_SENDING_CMD:
- mrq->cmd->error = -ENOMEDIUM;
- if (!mrq->data)
- break;
- /* fall through */
- case STATE_SENDING_DATA:
- mrq->data->error = -ENOMEDIUM;
- dw_mci_stop_dma(host);
- break;
- case STATE_DATA_BUSY:
- case STATE_DATA_ERROR:
- if (mrq->data->error == -EINPROGRESS)
- mrq->data->error = -ENOMEDIUM;
- if (!mrq->stop)
- break;
- /* fall through */
- case STATE_SENDING_STOP:
- mrq->stop->error = -ENOMEDIUM;
- break;
- }
-
- dw_mci_request_end(host, mrq);
- } else {
- list_del(&slot->queue_node);
- mrq->cmd->error = -ENOMEDIUM;
- if (mrq->data)
- mrq->data->error = -ENOMEDIUM;
- if (mrq->stop)
- mrq->stop->error = -ENOMEDIUM;
-
- spin_unlock(&host->lock);
- mmc_request_done(slot->mmc, mrq);
- spin_lock(&host->lock);
- }
- }
-
- /* Power down slot */
- if (present == 0) {
- clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-
- /*
- * Clear down the FIFO - doing so generates a
- * block interrupt, hence setting the
- * scatter-gather pointer to NULL.
- */
- sg_miter_stop(&host->sg_miter);
- host->sg = NULL;
-
- ctrl = mci_readl(host, CTRL);
- ctrl |= SDMMC_CTRL_FIFO_RESET;
- mci_writel(host, CTRL, ctrl);
-
-#ifdef CONFIG_MMC_DW_IDMAC
- ctrl = mci_readl(host, BMOD);
- ctrl |= 0x01; /* Software reset of DMA */
- mci_writel(host, BMOD, ctrl);
-#endif
-
- }
-
- spin_unlock_bh(&host->lock);
-
- /* Power down slot (after spin_unlock, may sleep) */
- if (present == 0 && host->pdata->setpower)
- host->pdata->setpower(slot->id, 0);
-
- present = dw_mci_get_cd(mmc);
- }
-
- mmc_detect_change(slot->mmc,
- msecs_to_jiffies(host->pdata->detect_delay_ms));
- }
-}
-
-static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
-{
- struct mmc_host *mmc;
- struct dw_mci_slot *slot;
-
- mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), &host->dev);
- if (!mmc)
- return -ENOMEM;
-
- slot = mmc_priv(mmc);
- slot->id = id;
- slot->mmc = mmc;
- slot->host = host;
-
- mmc->ops = &dw_mci_ops;
- mmc->f_min = DIV_ROUND_UP(host->bus_hz, 510);
- mmc->f_max = host->bus_hz;
-
- if (host->pdata->get_ocr)
- mmc->ocr_avail = host->pdata->get_ocr(id);
- else
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-
- /*
- * Start with slot power disabled, it will be enabled when a card
- * is detected.
- */
- if (host->pdata->setpower)
- host->pdata->setpower(id, 0);
-
- if (host->pdata->caps)
- mmc->caps = host->pdata->caps;
-
- if (host->pdata->caps2)
- mmc->caps2 = host->pdata->caps2;
-
- if (host->pdata->get_bus_wd)
- if (host->pdata->get_bus_wd(slot->id) >= 4)
- mmc->caps |= MMC_CAP_4_BIT_DATA;
-
- if (host->pdata->quirks & DW_MCI_QUIRK_HIGHSPEED)
- mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
-
- if (mmc->caps2 & MMC_CAP2_POWEROFF_NOTIFY)
- mmc->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
- else
- mmc->power_notify_type = MMC_HOST_PW_NOTIFY_NONE;
-
- if (host->pdata->blk_settings) {
- mmc->max_segs = host->pdata->blk_settings->max_segs;
- mmc->max_blk_size = host->pdata->blk_settings->max_blk_size;
- mmc->max_blk_count = host->pdata->blk_settings->max_blk_count;
- mmc->max_req_size = host->pdata->blk_settings->max_req_size;
- mmc->max_seg_size = host->pdata->blk_settings->max_seg_size;
- } else {
- /* Useful defaults if platform data is unset. */
-#ifdef CONFIG_MMC_DW_IDMAC
- mmc->max_segs = host->ring_size;
- mmc->max_blk_size = 65536;
- mmc->max_blk_count = host->ring_size;
- mmc->max_seg_size = 0x1000;
- mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
-#else
- mmc->max_segs = 64;
- mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
- mmc->max_blk_count = 512;
- mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
- mmc->max_seg_size = mmc->max_req_size;
-#endif /* CONFIG_MMC_DW_IDMAC */
- }
-
- host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
- if (IS_ERR(host->vmmc)) {
- pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
- host->vmmc = NULL;
- } else
- regulator_enable(host->vmmc);
-
- if (dw_mci_get_cd(mmc))
- set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
- else
- clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-
- host->slot[id] = slot;
- mmc_add_host(mmc);
-
-#if defined(CONFIG_DEBUG_FS)
- dw_mci_init_debugfs(slot);
-#endif
-
- /* Card initially undetected */
- slot->last_detect_state = 0;
-
- /*
- * Card may have been plugged in prior to boot so we
- * need to run the detect tasklet
- */
- queue_work(dw_mci_card_workqueue, &host->card_work);
-
- return 0;
-}
-
-static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
-{
- /* Shutdown detect IRQ */
- if (slot->host->pdata->exit)
- slot->host->pdata->exit(id);
-
- /* Debugfs stuff is cleaned up by mmc core */
- mmc_remove_host(slot->mmc);
- slot->host->slot[id] = NULL;
- mmc_free_host(slot->mmc);
-}
-
-static void dw_mci_init_dma(struct dw_mci *host)
-{
- /* Alloc memory for sg translation */
- host->sg_cpu = dma_alloc_coherent(&host->dev, PAGE_SIZE,
- &host->sg_dma, GFP_KERNEL);
- if (!host->sg_cpu) {
- dev_err(&host->dev, "%s: could not alloc DMA memory\n",
- __func__);
- goto no_dma;
- }
-
- /* Determine which DMA interface to use */
-#ifdef CONFIG_MMC_DW_IDMAC
- host->dma_ops = &dw_mci_idmac_ops;
- dev_info(&host->dev, "Using internal DMA controller.\n");
-#endif
-
- if (!host->dma_ops)
- goto no_dma;
-
- if (host->dma_ops->init && host->dma_ops->start &&
- host->dma_ops->stop && host->dma_ops->cleanup) {
- if (host->dma_ops->init(host)) {
- dev_err(&host->dev, "%s: Unable to initialize "
- "DMA Controller.\n", __func__);
- goto no_dma;
- }
- } else {
- dev_err(&host->dev, "DMA initialization not found.\n");
- goto no_dma;
- }
-
- host->use_dma = 1;
- return;
-
-no_dma:
- dev_info(&host->dev, "Using PIO mode.\n");
- host->use_dma = 0;
- return;
-}
-
-static bool mci_wait_reset(struct device *dev, struct dw_mci *host)
-{
- unsigned long timeout = jiffies + msecs_to_jiffies(500);
- unsigned int ctrl;
-
- mci_writel(host, CTRL, (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET |
- SDMMC_CTRL_DMA_RESET));
-
- /* wait till resets clear */
- do {
- ctrl = mci_readl(host, CTRL);
- if (!(ctrl & (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET |
- SDMMC_CTRL_DMA_RESET)))
- return true;
- } while (time_before(jiffies, timeout));
-
- dev_err(dev, "Timeout resetting block (ctrl %#x)\n", ctrl);
-
- return false;
-}
-
-int dw_mci_probe(struct dw_mci *host)
-{
- int width, i, ret = 0;
- u32 fifo_size;
-
- if (!host->pdata || !host->pdata->init) {
- dev_err(&host->dev,
- "Platform data must supply init function\n");
- return -ENODEV;
- }
-
- if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
- dev_err(&host->dev,
- "Platform data must supply select_slot function\n");
- return -ENODEV;
- }
-
- if (!host->pdata->bus_hz) {
- dev_err(&host->dev,
- "Platform data must supply bus speed\n");
- return -ENODEV;
- }
-
- host->bus_hz = host->pdata->bus_hz;
- host->quirks = host->pdata->quirks;
-
- spin_lock_init(&host->lock);
- INIT_LIST_HEAD(&host->queue);
-
-
- host->dma_ops = host->pdata->dma_ops;
- dw_mci_init_dma(host);
-
- /*
- * Get the host data width - this assumes that HCON has been set with
- * the correct values.
- */
- i = (mci_readl(host, HCON) >> 7) & 0x7;
- if (!i) {
- host->push_data = dw_mci_push_data16;
- host->pull_data = dw_mci_pull_data16;
- width = 16;
- host->data_shift = 1;
- } else if (i == 2) {
- host->push_data = dw_mci_push_data64;
- host->pull_data = dw_mci_pull_data64;
- width = 64;
- host->data_shift = 3;
- } else {
- /* Check for a reserved value, and warn if it is */
- WARN((i != 1),
- "HCON reports a reserved host data width!\n"
- "Defaulting to 32-bit access.\n");
- host->push_data = dw_mci_push_data32;
- host->pull_data = dw_mci_pull_data32;
- width = 32;
- host->data_shift = 2;
- }
-
- /* Reset all blocks */
- if (!mci_wait_reset(&host->dev, host)) {
- ret = -ENODEV;
- goto err_dmaunmap;
- }
-
- /* Clear the interrupts for the host controller */
- mci_writel(host, RINTSTS, 0xFFFFFFFF);
- mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
-
- /* Put in max timeout */
- mci_writel(host, TMOUT, 0xFFFFFFFF);
-
- /*
- * FIFO threshold settings RxMark = fifo_size / 2 - 1,
- * Tx Mark = fifo_size / 2 DMA Size = 8
- */
- if (!host->pdata->fifo_depth) {
- /*
- * Power-on value of RX_WMark is FIFO_DEPTH-1, but this may
- * have been overwritten by the bootloader, just like we're
- * about to do, so if you know the value for your hardware, you
- * should put it in the platform data.
- */
- fifo_size = mci_readl(host, FIFOTH);
- fifo_size = 1 + ((fifo_size >> 16) & 0xfff);
- } else {
- fifo_size = host->pdata->fifo_depth;
- }
- host->fifo_depth = fifo_size;
- host->fifoth_val = ((0x2 << 28) | ((fifo_size/2 - 1) << 16) |
- ((fifo_size/2) << 0));
- mci_writel(host, FIFOTH, host->fifoth_val);
-
- /* disable clock to CIU */
- mci_writel(host, CLKENA, 0);
- mci_writel(host, CLKSRC, 0);
-
- tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
- dw_mci_card_workqueue = alloc_workqueue("dw-mci-card",
- WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1);
- if (!dw_mci_card_workqueue)
- goto err_dmaunmap;
- INIT_WORK(&host->card_work, dw_mci_work_routine_card);
- ret = request_irq(host->irq, dw_mci_interrupt, host->irq_flags, "dw-mci", host);
- if (ret)
- goto err_workqueue;
-
- if (host->pdata->num_slots)
- host->num_slots = host->pdata->num_slots;
- else
- host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1;
-
- /* We need at least one slot to succeed */
- for (i = 0; i < host->num_slots; i++) {
- ret = dw_mci_init_slot(host, i);
- if (ret) {
- ret = -ENODEV;
- goto err_init_slot;
- }
- }
-
- /*
- * In 2.40a spec, Data offset is changed.
- * Need to check the version-id and set data-offset for DATA register.
- */
- host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
- dev_info(&host->dev, "Version ID is %04x\n", host->verid);
-
- if (host->verid < DW_MMC_240A)
- host->data_offset = DATA_OFFSET;
- else
- host->data_offset = DATA_240A_OFFSET;
-
- /*
- * Enable interrupts for command done, data over, data empty, card det,
- * receive ready and error such as transmit, receive timeout, crc error
- */
- mci_writel(host, RINTSTS, 0xFFFFFFFF);
- mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
- SDMMC_INT_TXDR | SDMMC_INT_RXDR |
- DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
- mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
-
- dev_info(&host->dev, "DW MMC controller at irq %d, "
- "%d bit host data width, "
- "%u deep fifo\n",
- host->irq, width, fifo_size);
- if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
- dev_info(&host->dev, "Internal DMAC interrupt fix enabled.\n");
-
- return 0;
-
-err_init_slot:
- /* De-init any initialized slots */
- while (i > 0) {
- if (host->slot[i])
- dw_mci_cleanup_slot(host->slot[i], i);
- i--;
- }
- free_irq(host->irq, host);
-
-err_workqueue:
- destroy_workqueue(dw_mci_card_workqueue);
-
-err_dmaunmap:
- if (host->use_dma && host->dma_ops->exit)
- host->dma_ops->exit(host);
- dma_free_coherent(&host->dev, PAGE_SIZE,
- host->sg_cpu, host->sg_dma);
-
- if (host->vmmc) {
- regulator_disable(host->vmmc);
- regulator_put(host->vmmc);
- }
- return ret;
-}
-EXPORT_SYMBOL(dw_mci_probe);
-
-void dw_mci_remove(struct dw_mci *host)
-{
- int i;
-
- mci_writel(host, RINTSTS, 0xFFFFFFFF);
- mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
-
- for (i = 0; i < host->num_slots; i++) {
- dev_dbg(&host->dev, "remove slot %d\n", i);
- if (host->slot[i])
- dw_mci_cleanup_slot(host->slot[i], i);
- }
-
- /* disable clock to CIU */
- mci_writel(host, CLKENA, 0);
- mci_writel(host, CLKSRC, 0);
-
- free_irq(host->irq, host);
- destroy_workqueue(dw_mci_card_workqueue);
- dma_free_coherent(&host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
-
- if (host->use_dma && host->dma_ops->exit)
- host->dma_ops->exit(host);
-
- if (host->vmmc) {
- regulator_disable(host->vmmc);
- regulator_put(host->vmmc);
- }
-
-}
-EXPORT_SYMBOL(dw_mci_remove);
-
-
-
-#ifdef CONFIG_PM_SLEEP
-/*
- * TODO: we should probably disable the clock to the card in the suspend path.
- */
-int dw_mci_suspend(struct dw_mci *host)
-{
- int i, ret = 0;
-
- for (i = 0; i < host->num_slots; i++) {
- struct dw_mci_slot *slot = host->slot[i];
- if (!slot)
- continue;
- ret = mmc_suspend_host(slot->mmc);
- if (ret < 0) {
- while (--i >= 0) {
- slot = host->slot[i];
- if (slot)
- mmc_resume_host(host->slot[i]->mmc);
- }
- return ret;
- }
- }
-
- if (host->vmmc)
- regulator_disable(host->vmmc);
-
- return 0;
-}
-EXPORT_SYMBOL(dw_mci_suspend);
-
-int dw_mci_resume(struct dw_mci *host)
-{
- int i, ret;
-
- if (host->vmmc)
- regulator_enable(host->vmmc);
-
- if (host->dma_ops->init)
- host->dma_ops->init(host);
-
- if (!mci_wait_reset(&host->dev, host)) {
- ret = -ENODEV;
- return ret;
- }
-
- /* Restore the old value at FIFOTH register */
- mci_writel(host, FIFOTH, host->fifoth_val);
-
- mci_writel(host, RINTSTS, 0xFFFFFFFF);
- mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
- SDMMC_INT_TXDR | SDMMC_INT_RXDR |
- DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
- mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
-
- for (i = 0; i < host->num_slots; i++) {
- struct dw_mci_slot *slot = host->slot[i];
- if (!slot)
- continue;
- ret = mmc_resume_host(host->slot[i]->mmc);
- if (ret < 0)
- return ret;
- }
- return 0;
-}
-EXPORT_SYMBOL(dw_mci_resume);
-#endif /* CONFIG_PM_SLEEP */
-
-static int __init dw_mci_init(void)
-{
- printk(KERN_INFO "Synopsys Designware Multimedia Card Interface Driver");
- return 0;
-}
-
-static void __exit dw_mci_exit(void)
-{
-}
-
-module_init(dw_mci_init);
-module_exit(dw_mci_exit);
-
-MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
-MODULE_AUTHOR("NXP Semiconductor VietNam");
-MODULE_AUTHOR("Imagination Technologies Ltd");
-MODULE_LICENSE("GPL v2");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/dw_mmc.h b/ANDROID_3.4.5/drivers/mmc/host/dw_mmc.h
deleted file mode 100644
index 15c27e17..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/dw_mmc.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Synopsys DesignWare Multimedia Card Interface driver
- * (Based on NXP driver for lpc 31xx)
- *
- * Copyright (C) 2009 NXP Semiconductors
- * Copyright (C) 2009, 2010 Imagination Technologies 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.
- */
-
-#ifndef _DW_MMC_H_
-#define _DW_MMC_H_
-
-#define DW_MMC_240A 0x240a
-
-#define SDMMC_CTRL 0x000
-#define SDMMC_PWREN 0x004
-#define SDMMC_CLKDIV 0x008
-#define SDMMC_CLKSRC 0x00c
-#define SDMMC_CLKENA 0x010
-#define SDMMC_TMOUT 0x014
-#define SDMMC_CTYPE 0x018
-#define SDMMC_BLKSIZ 0x01c
-#define SDMMC_BYTCNT 0x020
-#define SDMMC_INTMASK 0x024
-#define SDMMC_CMDARG 0x028
-#define SDMMC_CMD 0x02c
-#define SDMMC_RESP0 0x030
-#define SDMMC_RESP1 0x034
-#define SDMMC_RESP2 0x038
-#define SDMMC_RESP3 0x03c
-#define SDMMC_MINTSTS 0x040
-#define SDMMC_RINTSTS 0x044
-#define SDMMC_STATUS 0x048
-#define SDMMC_FIFOTH 0x04c
-#define SDMMC_CDETECT 0x050
-#define SDMMC_WRTPRT 0x054
-#define SDMMC_GPIO 0x058
-#define SDMMC_TCBCNT 0x05c
-#define SDMMC_TBBCNT 0x060
-#define SDMMC_DEBNCE 0x064
-#define SDMMC_USRID 0x068
-#define SDMMC_VERID 0x06c
-#define SDMMC_HCON 0x070
-#define SDMMC_UHS_REG 0x074
-#define SDMMC_BMOD 0x080
-#define SDMMC_PLDMND 0x084
-#define SDMMC_DBADDR 0x088
-#define SDMMC_IDSTS 0x08c
-#define SDMMC_IDINTEN 0x090
-#define SDMMC_DSCADDR 0x094
-#define SDMMC_BUFADDR 0x098
-#define SDMMC_DATA(x) (x)
-
-/*
- * Data offset is difference according to Version
- * Lower than 2.40a : data register offest is 0x100
- */
-#define DATA_OFFSET 0x100
-#define DATA_240A_OFFSET 0x200
-
-/* shift bit field */
-#define _SBF(f, v) ((v) << (f))
-
-/* Control register defines */
-#define SDMMC_CTRL_USE_IDMAC BIT(25)
-#define SDMMC_CTRL_CEATA_INT_EN BIT(11)
-#define SDMMC_CTRL_SEND_AS_CCSD BIT(10)
-#define SDMMC_CTRL_SEND_CCSD BIT(9)
-#define SDMMC_CTRL_ABRT_READ_DATA BIT(8)
-#define SDMMC_CTRL_SEND_IRQ_RESP BIT(7)
-#define SDMMC_CTRL_READ_WAIT BIT(6)
-#define SDMMC_CTRL_DMA_ENABLE BIT(5)
-#define SDMMC_CTRL_INT_ENABLE BIT(4)
-#define SDMMC_CTRL_DMA_RESET BIT(2)
-#define SDMMC_CTRL_FIFO_RESET BIT(1)
-#define SDMMC_CTRL_RESET BIT(0)
-/* Clock Enable register defines */
-#define SDMMC_CLKEN_LOW_PWR BIT(16)
-#define SDMMC_CLKEN_ENABLE BIT(0)
-/* time-out register defines */
-#define SDMMC_TMOUT_DATA(n) _SBF(8, (n))
-#define SDMMC_TMOUT_DATA_MSK 0xFFFFFF00
-#define SDMMC_TMOUT_RESP(n) ((n) & 0xFF)
-#define SDMMC_TMOUT_RESP_MSK 0xFF
-/* card-type register defines */
-#define SDMMC_CTYPE_8BIT BIT(16)
-#define SDMMC_CTYPE_4BIT BIT(0)
-#define SDMMC_CTYPE_1BIT 0
-/* Interrupt status & mask register defines */
-#define SDMMC_INT_SDIO(n) BIT(16 + (n))
-#define SDMMC_INT_EBE BIT(15)
-#define SDMMC_INT_ACD BIT(14)
-#define SDMMC_INT_SBE BIT(13)
-#define SDMMC_INT_HLE BIT(12)
-#define SDMMC_INT_FRUN BIT(11)
-#define SDMMC_INT_HTO BIT(10)
-#define SDMMC_INT_DTO BIT(9)
-#define SDMMC_INT_RTO BIT(8)
-#define SDMMC_INT_DCRC BIT(7)
-#define SDMMC_INT_RCRC BIT(6)
-#define SDMMC_INT_RXDR BIT(5)
-#define SDMMC_INT_TXDR BIT(4)
-#define SDMMC_INT_DATA_OVER BIT(3)
-#define SDMMC_INT_CMD_DONE BIT(2)
-#define SDMMC_INT_RESP_ERR BIT(1)
-#define SDMMC_INT_CD BIT(0)
-#define SDMMC_INT_ERROR 0xbfc2
-/* Command register defines */
-#define SDMMC_CMD_START BIT(31)
-#define SDMMC_CMD_CCS_EXP BIT(23)
-#define SDMMC_CMD_CEATA_RD BIT(22)
-#define SDMMC_CMD_UPD_CLK BIT(21)
-#define SDMMC_CMD_INIT BIT(15)
-#define SDMMC_CMD_STOP BIT(14)
-#define SDMMC_CMD_PRV_DAT_WAIT BIT(13)
-#define SDMMC_CMD_SEND_STOP BIT(12)
-#define SDMMC_CMD_STRM_MODE BIT(11)
-#define SDMMC_CMD_DAT_WR BIT(10)
-#define SDMMC_CMD_DAT_EXP BIT(9)
-#define SDMMC_CMD_RESP_CRC BIT(8)
-#define SDMMC_CMD_RESP_LONG BIT(7)
-#define SDMMC_CMD_RESP_EXP BIT(6)
-#define SDMMC_CMD_INDX(n) ((n) & 0x1F)
-/* Status register defines */
-#define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF)
-/* Internal DMAC interrupt defines */
-#define SDMMC_IDMAC_INT_AI BIT(9)
-#define SDMMC_IDMAC_INT_NI BIT(8)
-#define SDMMC_IDMAC_INT_CES BIT(5)
-#define SDMMC_IDMAC_INT_DU BIT(4)
-#define SDMMC_IDMAC_INT_FBE BIT(2)
-#define SDMMC_IDMAC_INT_RI BIT(1)
-#define SDMMC_IDMAC_INT_TI BIT(0)
-/* Internal DMAC bus mode bits */
-#define SDMMC_IDMAC_ENABLE BIT(7)
-#define SDMMC_IDMAC_FB BIT(1)
-#define SDMMC_IDMAC_SWRESET BIT(0)
-/* Version ID register define */
-#define SDMMC_GET_VERID(x) ((x) & 0xFFFF)
-
-/* Register access macros */
-#define mci_readl(dev, reg) \
- __raw_readl((dev)->regs + SDMMC_##reg)
-#define mci_writel(dev, reg, value) \
- __raw_writel((value), (dev)->regs + SDMMC_##reg)
-
-/* 16-bit FIFO access macros */
-#define mci_readw(dev, reg) \
- __raw_readw((dev)->regs + SDMMC_##reg)
-#define mci_writew(dev, reg, value) \
- __raw_writew((value), (dev)->regs + SDMMC_##reg)
-
-/* 64-bit FIFO access macros */
-#ifdef readq
-#define mci_readq(dev, reg) \
- __raw_readq((dev)->regs + SDMMC_##reg)
-#define mci_writeq(dev, reg, value) \
- __raw_writeq((value), (dev)->regs + SDMMC_##reg)
-#else
-/*
- * Dummy readq implementation for architectures that don't define it.
- *
- * We would assume that none of these architectures would configure
- * the IP block with a 64bit FIFO width, so this code will never be
- * executed on those machines. Defining these macros here keeps the
- * rest of the code free from ifdefs.
- */
-#define mci_readq(dev, reg) \
- (*(volatile u64 __force *)((dev)->regs + SDMMC_##reg))
-#define mci_writeq(dev, reg, value) \
- (*(volatile u64 __force *)((dev)->regs + SDMMC_##reg) = (value))
-#endif
-
-extern int dw_mci_probe(struct dw_mci *host);
-extern void dw_mci_remove(struct dw_mci *host);
-#ifdef CONFIG_PM
-extern int dw_mci_suspend(struct dw_mci *host);
-extern int dw_mci_resume(struct dw_mci *host);
-#endif
-
-#endif /* _DW_MMC_H_ */
diff --git a/ANDROID_3.4.5/drivers/mmc/host/imxmmc.c b/ANDROID_3.4.5/drivers/mmc/host/imxmmc.c
deleted file mode 100644
index ea0f3ced..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/imxmmc.c
+++ /dev/null
@@ -1,1169 +0,0 @@
-/*
- * linux/drivers/mmc/host/imxmmc.c - Motorola i.MX MMCI driver
- *
- * Copyright (C) 2004 Sascha Hauer, Pengutronix <sascha@saschahauer.de>
- * Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com>
- *
- * derived from pxamci.c by Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/dma-mapping.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include <asm/dma.h>
-#include <asm/irq.h>
-#include <asm/sizes.h>
-#include <mach/mmc.h>
-#include <mach/imx-dma.h>
-
-#include "imxmmc.h"
-
-#define DRIVER_NAME "imx-mmc"
-
-#define IMXMCI_INT_MASK_DEFAULT (INT_MASK_BUF_READY | INT_MASK_DATA_TRAN | \
- INT_MASK_WRITE_OP_DONE | INT_MASK_END_CMD_RES | \
- INT_MASK_AUTO_CARD_DETECT | INT_MASK_DAT0_EN | INT_MASK_SDIO)
-
-struct imxmci_host {
- struct mmc_host *mmc;
- spinlock_t lock;
- struct resource *res;
- void __iomem *base;
- int irq;
- imx_dmach_t dma;
- volatile unsigned int imask;
- unsigned int power_mode;
- unsigned int present;
- struct imxmmc_platform_data *pdata;
-
- struct mmc_request *req;
- struct mmc_command *cmd;
- struct mmc_data *data;
-
- struct timer_list timer;
- struct tasklet_struct tasklet;
- unsigned int status_reg;
- unsigned long pending_events;
- /* Next two fields are there for CPU driven transfers to overcome SDHC deficiencies */
- u16 *data_ptr;
- unsigned int data_cnt;
- atomic_t stuck_timeout;
-
- unsigned int dma_nents;
- unsigned int dma_size;
- unsigned int dma_dir;
- int dma_allocated;
-
- unsigned char actual_bus_width;
-
- int prev_cmd_code;
-
- struct clk *clk;
-};
-
-#define IMXMCI_PEND_IRQ_b 0
-#define IMXMCI_PEND_DMA_END_b 1
-#define IMXMCI_PEND_DMA_ERR_b 2
-#define IMXMCI_PEND_WAIT_RESP_b 3
-#define IMXMCI_PEND_DMA_DATA_b 4
-#define IMXMCI_PEND_CPU_DATA_b 5
-#define IMXMCI_PEND_CARD_XCHG_b 6
-#define IMXMCI_PEND_SET_INIT_b 7
-#define IMXMCI_PEND_STARTED_b 8
-
-#define IMXMCI_PEND_IRQ_m (1 << IMXMCI_PEND_IRQ_b)
-#define IMXMCI_PEND_DMA_END_m (1 << IMXMCI_PEND_DMA_END_b)
-#define IMXMCI_PEND_DMA_ERR_m (1 << IMXMCI_PEND_DMA_ERR_b)
-#define IMXMCI_PEND_WAIT_RESP_m (1 << IMXMCI_PEND_WAIT_RESP_b)
-#define IMXMCI_PEND_DMA_DATA_m (1 << IMXMCI_PEND_DMA_DATA_b)
-#define IMXMCI_PEND_CPU_DATA_m (1 << IMXMCI_PEND_CPU_DATA_b)
-#define IMXMCI_PEND_CARD_XCHG_m (1 << IMXMCI_PEND_CARD_XCHG_b)
-#define IMXMCI_PEND_SET_INIT_m (1 << IMXMCI_PEND_SET_INIT_b)
-#define IMXMCI_PEND_STARTED_m (1 << IMXMCI_PEND_STARTED_b)
-
-static void imxmci_stop_clock(struct imxmci_host *host)
-{
- int i = 0;
- u16 reg;
-
- reg = readw(host->base + MMC_REG_STR_STP_CLK);
- writew(reg & ~STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK);
- while (i < 0x1000) {
- if (!(i & 0x7f)) {
- reg = readw(host->base + MMC_REG_STR_STP_CLK);
- writew(reg | STR_STP_CLK_STOP_CLK,
- host->base + MMC_REG_STR_STP_CLK);
- }
-
- reg = readw(host->base + MMC_REG_STATUS);
- if (!(reg & STATUS_CARD_BUS_CLK_RUN)) {
- /* Check twice before cut */
- reg = readw(host->base + MMC_REG_STATUS);
- if (!(reg & STATUS_CARD_BUS_CLK_RUN))
- return;
- }
-
- i++;
- }
- dev_dbg(mmc_dev(host->mmc), "imxmci_stop_clock blocked, no luck\n");
-}
-
-static int imxmci_start_clock(struct imxmci_host *host)
-{
- unsigned int trials = 0;
- unsigned int delay_limit = 128;
- unsigned long flags;
- u16 reg;
-
- reg = readw(host->base + MMC_REG_STR_STP_CLK);
- writew(reg & ~STR_STP_CLK_STOP_CLK, host->base + MMC_REG_STR_STP_CLK);
-
- clear_bit(IMXMCI_PEND_STARTED_b, &host->pending_events);
-
- /*
- * Command start of the clock, this usually succeeds in less
- * then 6 delay loops, but during card detection (low clockrate)
- * it takes up to 5000 delay loops and sometimes fails for the first time
- */
- reg = readw(host->base + MMC_REG_STR_STP_CLK);
- writew(reg | STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK);
-
- do {
- unsigned int delay = delay_limit;
-
- while (delay--) {
- reg = readw(host->base + MMC_REG_STATUS);
- if (reg & STATUS_CARD_BUS_CLK_RUN) {
- /* Check twice before cut */
- reg = readw(host->base + MMC_REG_STATUS);
- if (reg & STATUS_CARD_BUS_CLK_RUN)
- return 0;
- }
-
- if (test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events))
- return 0;
- }
-
- local_irq_save(flags);
- /*
- * Ensure, that request is not doubled under all possible circumstances.
- * It is possible, that cock running state is missed, because some other
- * IRQ or schedule delays this function execution and the clocks has
- * been already stopped by other means (response processing, SDHC HW)
- */
- if (!test_bit(IMXMCI_PEND_STARTED_b, &host->pending_events)) {
- reg = readw(host->base + MMC_REG_STR_STP_CLK);
- writew(reg | STR_STP_CLK_START_CLK,
- host->base + MMC_REG_STR_STP_CLK);
- }
- local_irq_restore(flags);
-
- } while (++trials < 256);
-
- dev_err(mmc_dev(host->mmc), "imxmci_start_clock blocked, no luck\n");
-
- return -1;
-}
-
-static void imxmci_softreset(struct imxmci_host *host)
-{
- int i;
-
- /* reset sequence */
- writew(0x08, host->base + MMC_REG_STR_STP_CLK);
- writew(0x0D, host->base + MMC_REG_STR_STP_CLK);
-
- for (i = 0; i < 8; i++)
- writew(0x05, host->base + MMC_REG_STR_STP_CLK);
-
- writew(0xff, host->base + MMC_REG_RES_TO);
- writew(512, host->base + MMC_REG_BLK_LEN);
- writew(1, host->base + MMC_REG_NOB);
-}
-
-static int imxmci_busy_wait_for_status(struct imxmci_host *host,
- unsigned int *pstat, unsigned int stat_mask,
- int timeout, const char *where)
-{
- int loops = 0;
-
- while (!(*pstat & stat_mask)) {
- loops += 2;
- if (loops >= timeout) {
- dev_dbg(mmc_dev(host->mmc), "busy wait timeout in %s, STATUS = 0x%x (0x%x)\n",
- where, *pstat, stat_mask);
- return -1;
- }
- udelay(2);
- *pstat |= readw(host->base + MMC_REG_STATUS);
- }
- if (!loops)
- return 0;
-
- /* The busy-wait is expected there for clock <8MHz due to SDHC hardware flaws */
- if (!(stat_mask & STATUS_END_CMD_RESP) || (host->mmc->ios.clock >= 8000000))
- dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n",
- loops, where, *pstat, stat_mask);
- return loops;
-}
-
-static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
-{
- unsigned int nob = data->blocks;
- unsigned int blksz = data->blksz;
- unsigned int datasz = nob * blksz;
- int i;
-
- if (data->flags & MMC_DATA_STREAM)
- nob = 0xffff;
-
- host->data = data;
- data->bytes_xfered = 0;
-
- writew(nob, host->base + MMC_REG_NOB);
- writew(blksz, host->base + MMC_REG_BLK_LEN);
-
- /*
- * DMA cannot be used for small block sizes, we have to use CPU driven transfers otherwise.
- * We are in big troubles for non-512 byte transfers according to note in the paragraph
- * 20.6.7 of User Manual anyway, but we need to be able to transfer SCR at least.
- * The situation is even more complex in reality. The SDHC in not able to handle wll
- * partial FIFO fills and reads. The length has to be rounded up to burst size multiple.
- * This is required for SCR read at least.
- */
- if (datasz < 512) {
- host->dma_size = datasz;
- if (data->flags & MMC_DATA_READ) {
- host->dma_dir = DMA_FROM_DEVICE;
-
- /* Hack to enable read SCR */
- writew(1, host->base + MMC_REG_NOB);
- writew(512, host->base + MMC_REG_BLK_LEN);
- } else {
- host->dma_dir = DMA_TO_DEVICE;
- }
-
- /* Convert back to virtual address */
- host->data_ptr = (u16 *)sg_virt(data->sg);
- host->data_cnt = 0;
-
- clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events);
- set_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events);
-
- return;
- }
-
- if (data->flags & MMC_DATA_READ) {
- host->dma_dir = DMA_FROM_DEVICE;
- host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, host->dma_dir);
-
- imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
- host->res->start + MMC_REG_BUFFER_ACCESS,
- DMA_MODE_READ);
-
- /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_READ, IMX_DMA_WIDTH_16, CCR_REN);*/
- CCR(host->dma) = CCR_DMOD_LINEAR | CCR_DSIZ_32 | CCR_SMOD_FIFO | CCR_SSIZ_16 | CCR_REN;
- } else {
- host->dma_dir = DMA_TO_DEVICE;
-
- host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, host->dma_dir);
-
- imx_dma_setup_sg(host->dma, data->sg, data->sg_len, datasz,
- host->res->start + MMC_REG_BUFFER_ACCESS,
- DMA_MODE_WRITE);
-
- /*imx_dma_setup_mem2dev_ccr(host->dma, DMA_MODE_WRITE, IMX_DMA_WIDTH_16, CCR_REN);*/
- CCR(host->dma) = CCR_SMOD_LINEAR | CCR_SSIZ_32 | CCR_DMOD_FIFO | CCR_DSIZ_16 | CCR_REN;
- }
-
-#if 1 /* This code is there only for consistency checking and can be disabled in future */
- host->dma_size = 0;
- for (i = 0; i < host->dma_nents; i++)
- host->dma_size += data->sg[i].length;
-
- if (datasz > host->dma_size) {
- dev_err(mmc_dev(host->mmc), "imxmci_setup_data datasz 0x%x > 0x%x dm_size\n",
- datasz, host->dma_size);
- }
-#endif
-
- host->dma_size = datasz;
-
- wmb();
-
- set_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events);
- clear_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events);
-
- /* start DMA engine for read, write is delayed after initial response */
- if (host->dma_dir == DMA_FROM_DEVICE)
- imx_dma_enable(host->dma);
-}
-
-static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd, unsigned int cmdat)
-{
- unsigned long flags;
- u32 imask;
-
- WARN_ON(host->cmd != NULL);
- host->cmd = cmd;
-
- /* Ensure, that clock are stopped else command programming and start fails */
- imxmci_stop_clock(host);
-
- if (cmd->flags & MMC_RSP_BUSY)
- cmdat |= CMD_DAT_CONT_BUSY;
-
- switch (mmc_resp_type(cmd)) {
- case MMC_RSP_R1: /* short CRC, OPCODE */
- case MMC_RSP_R1B:/* short CRC, OPCODE, BUSY */
- cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R1;
- break;
- case MMC_RSP_R2: /* long 136 bit + CRC */
- cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R2;
- break;
- case MMC_RSP_R3: /* short */
- cmdat |= CMD_DAT_CONT_RESPONSE_FORMAT_R3;
- break;
- default:
- break;
- }
-
- if (test_and_clear_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events))
- cmdat |= CMD_DAT_CONT_INIT; /* This command needs init */
-
- if (host->actual_bus_width == MMC_BUS_WIDTH_4)
- cmdat |= CMD_DAT_CONT_BUS_WIDTH_4;
-
- writew(cmd->opcode, host->base + MMC_REG_CMD);
- writew(cmd->arg >> 16, host->base + MMC_REG_ARGH);
- writew(cmd->arg & 0xffff, host->base + MMC_REG_ARGL);
- writew(cmdat, host->base + MMC_REG_CMD_DAT_CONT);
-
- atomic_set(&host->stuck_timeout, 0);
- set_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events);
-
-
- imask = IMXMCI_INT_MASK_DEFAULT;
- imask &= ~INT_MASK_END_CMD_RES;
- if (cmdat & CMD_DAT_CONT_DATA_ENABLE) {
- /* imask &= ~INT_MASK_BUF_READY; */
- imask &= ~INT_MASK_DATA_TRAN;
- if (cmdat & CMD_DAT_CONT_WRITE)
- imask &= ~INT_MASK_WRITE_OP_DONE;
- if (test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events))
- imask &= ~INT_MASK_BUF_READY;
- }
-
- spin_lock_irqsave(&host->lock, flags);
- host->imask = imask;
- writew(host->imask, host->base + MMC_REG_INT_MASK);
- spin_unlock_irqrestore(&host->lock, flags);
-
- dev_dbg(mmc_dev(host->mmc), "CMD%02d (0x%02x) mask set to 0x%04x\n",
- cmd->opcode, cmd->opcode, imask);
-
- imxmci_start_clock(host);
-}
-
-static void imxmci_finish_request(struct imxmci_host *host, struct mmc_request *req)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
-
- host->pending_events &= ~(IMXMCI_PEND_WAIT_RESP_m | IMXMCI_PEND_DMA_END_m |
- IMXMCI_PEND_DMA_DATA_m | IMXMCI_PEND_CPU_DATA_m);
-
- host->imask = IMXMCI_INT_MASK_DEFAULT;
- writew(host->imask, host->base + MMC_REG_INT_MASK);
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- if (req && req->cmd)
- host->prev_cmd_code = req->cmd->opcode;
-
- host->req = NULL;
- host->cmd = NULL;
- host->data = NULL;
- mmc_request_done(host->mmc, req);
-}
-
-static int imxmci_finish_data(struct imxmci_host *host, unsigned int stat)
-{
- struct mmc_data *data = host->data;
- int data_error;
-
- if (test_and_clear_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) {
- imx_dma_disable(host->dma);
- dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_nents,
- host->dma_dir);
- }
-
- if (stat & STATUS_ERR_MASK) {
- dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n", stat);
- if (stat & (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR))
- data->error = -EILSEQ;
- else if (stat & STATUS_TIME_OUT_READ)
- data->error = -ETIMEDOUT;
- else
- data->error = -EIO;
- } else {
- data->bytes_xfered = host->dma_size;
- }
-
- data_error = data->error;
-
- host->data = NULL;
-
- return data_error;
-}
-
-static int imxmci_cmd_done(struct imxmci_host *host, unsigned int stat)
-{
- struct mmc_command *cmd = host->cmd;
- int i;
- u32 a, b, c;
- struct mmc_data *data = host->data;
-
- if (!cmd)
- return 0;
-
- host->cmd = NULL;
-
- if (stat & STATUS_TIME_OUT_RESP) {
- dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n");
- cmd->error = -ETIMEDOUT;
- } else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
- dev_dbg(mmc_dev(host->mmc), "cmd crc error\n");
- cmd->error = -EILSEQ;
- }
-
- if (cmd->flags & MMC_RSP_PRESENT) {
- if (cmd->flags & MMC_RSP_136) {
- for (i = 0; i < 4; i++) {
- a = readw(host->base + MMC_REG_RES_FIFO);
- b = readw(host->base + MMC_REG_RES_FIFO);
- cmd->resp[i] = a << 16 | b;
- }
- } else {
- a = readw(host->base + MMC_REG_RES_FIFO);
- b = readw(host->base + MMC_REG_RES_FIFO);
- c = readw(host->base + MMC_REG_RES_FIFO);
- cmd->resp[0] = a << 24 | b << 8 | c >> 8;
- }
- }
-
- dev_dbg(mmc_dev(host->mmc), "RESP 0x%08x, 0x%08x, 0x%08x, 0x%08x, error %d\n",
- cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error);
-
- if (data && !cmd->error && !(stat & STATUS_ERR_MASK)) {
- if (host->req->data->flags & MMC_DATA_WRITE) {
-
- /* Wait for FIFO to be empty before starting DMA write */
-
- stat = readw(host->base + MMC_REG_STATUS);
- if (imxmci_busy_wait_for_status(host, &stat,
- STATUS_APPL_BUFF_FE,
- 40, "imxmci_cmd_done DMA WR") < 0) {
- cmd->error = -EIO;
- imxmci_finish_data(host, stat);
- if (host->req)
- imxmci_finish_request(host, host->req);
- dev_warn(mmc_dev(host->mmc), "STATUS = 0x%04x\n",
- stat);
- return 0;
- }
-
- if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
- imx_dma_enable(host->dma);
- }
- } else {
- struct mmc_request *req;
- imxmci_stop_clock(host);
- req = host->req;
-
- if (data)
- imxmci_finish_data(host, stat);
-
- if (req)
- imxmci_finish_request(host, req);
- else
- dev_warn(mmc_dev(host->mmc), "imxmci_cmd_done: no request to finish\n");
- }
-
- return 1;
-}
-
-static int imxmci_data_done(struct imxmci_host *host, unsigned int stat)
-{
- struct mmc_data *data = host->data;
- int data_error;
-
- if (!data)
- return 0;
-
- data_error = imxmci_finish_data(host, stat);
-
- if (host->req->stop) {
- imxmci_stop_clock(host);
- imxmci_start_cmd(host, host->req->stop, 0);
- } else {
- struct mmc_request *req;
- req = host->req;
- if (req)
- imxmci_finish_request(host, req);
- else
- dev_warn(mmc_dev(host->mmc), "imxmci_data_done: no request to finish\n");
- }
-
- return 1;
-}
-
-static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
-{
- int i;
- int burst_len;
- int trans_done = 0;
- unsigned int stat = *pstat;
-
- if (host->actual_bus_width != MMC_BUS_WIDTH_4)
- burst_len = 16;
- else
- burst_len = 64;
-
- /* This is unfortunately required */
- dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data running STATUS = 0x%x\n",
- stat);
-
- udelay(20); /* required for clocks < 8MHz*/
-
- if (host->dma_dir == DMA_FROM_DEVICE) {
- imxmci_busy_wait_for_status(host, &stat,
- STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE |
- STATUS_TIME_OUT_READ,
- 50, "imxmci_cpu_driven_data read");
-
- while ((stat & (STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE)) &&
- !(stat & STATUS_TIME_OUT_READ) &&
- (host->data_cnt < 512)) {
-
- udelay(20); /* required for clocks < 8MHz*/
-
- for (i = burst_len; i >= 2 ; i -= 2) {
- u16 data;
- data = readw(host->base + MMC_REG_BUFFER_ACCESS);
- udelay(10); /* required for clocks < 8MHz*/
- if (host->data_cnt+2 <= host->dma_size) {
- *(host->data_ptr++) = data;
- } else {
- if (host->data_cnt < host->dma_size)
- *(u8 *)(host->data_ptr) = data;
- }
- host->data_cnt += 2;
- }
-
- stat = readw(host->base + MMC_REG_STATUS);
-
- dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read %d burst %d STATUS = 0x%x\n",
- host->data_cnt, burst_len, stat);
- }
-
- if ((stat & STATUS_DATA_TRANS_DONE) && (host->data_cnt >= 512))
- trans_done = 1;
-
- if (host->dma_size & 0x1ff)
- stat &= ~STATUS_CRC_READ_ERR;
-
- if (stat & STATUS_TIME_OUT_READ) {
- dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read timeout STATUS = 0x%x\n",
- stat);
- trans_done = -1;
- }
-
- } else {
- imxmci_busy_wait_for_status(host, &stat,
- STATUS_APPL_BUFF_FE,
- 20, "imxmci_cpu_driven_data write");
-
- while ((stat & STATUS_APPL_BUFF_FE) &&
- (host->data_cnt < host->dma_size)) {
- if (burst_len >= host->dma_size - host->data_cnt) {
- burst_len = host->dma_size - host->data_cnt;
- host->data_cnt = host->dma_size;
- trans_done = 1;
- } else {
- host->data_cnt += burst_len;
- }
-
- for (i = burst_len; i > 0 ; i -= 2)
- writew(*(host->data_ptr++), host->base + MMC_REG_BUFFER_ACCESS);
-
- stat = readw(host->base + MMC_REG_STATUS);
-
- dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data write burst %d STATUS = 0x%x\n",
- burst_len, stat);
- }
- }
-
- *pstat = stat;
-
- return trans_done;
-}
-
-static void imxmci_dma_irq(int dma, void *devid)
-{
- struct imxmci_host *host = devid;
- u32 stat = readw(host->base + MMC_REG_STATUS);
-
- atomic_set(&host->stuck_timeout, 0);
- host->status_reg = stat;
- set_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events);
- tasklet_schedule(&host->tasklet);
-}
-
-static irqreturn_t imxmci_irq(int irq, void *devid)
-{
- struct imxmci_host *host = devid;
- u32 stat = readw(host->base + MMC_REG_STATUS);
- int handled = 1;
-
- writew(host->imask | INT_MASK_SDIO | INT_MASK_AUTO_CARD_DETECT,
- host->base + MMC_REG_INT_MASK);
-
- atomic_set(&host->stuck_timeout, 0);
- host->status_reg = stat;
- set_bit(IMXMCI_PEND_IRQ_b, &host->pending_events);
- set_bit(IMXMCI_PEND_STARTED_b, &host->pending_events);
- tasklet_schedule(&host->tasklet);
-
- return IRQ_RETVAL(handled);
-}
-
-static void imxmci_tasklet_fnc(unsigned long data)
-{
- struct imxmci_host *host = (struct imxmci_host *)data;
- u32 stat;
- unsigned int data_dir_mask = 0; /* STATUS_WR_CRC_ERROR_CODE_MASK */
- int timeout = 0;
-
- if (atomic_read(&host->stuck_timeout) > 4) {
- char *what;
- timeout = 1;
- stat = readw(host->base + MMC_REG_STATUS);
- host->status_reg = stat;
- if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
- if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
- what = "RESP+DMA";
- else
- what = "RESP";
- else
- if (test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events))
- if (test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events))
- what = "DATA";
- else
- what = "DMA";
- else
- what = "???";
-
- dev_err(mmc_dev(host->mmc),
- "%s TIMEOUT, hardware stucked STATUS = 0x%04x IMASK = 0x%04x\n",
- what, stat,
- readw(host->base + MMC_REG_INT_MASK));
- dev_err(mmc_dev(host->mmc),
- "CMD_DAT_CONT = 0x%04x, MMC_BLK_LEN = 0x%04x, MMC_NOB = 0x%04x, DMA_CCR = 0x%08x\n",
- readw(host->base + MMC_REG_CMD_DAT_CONT),
- readw(host->base + MMC_REG_BLK_LEN),
- readw(host->base + MMC_REG_NOB),
- CCR(host->dma));
- dev_err(mmc_dev(host->mmc), "CMD%d, prevCMD%d, bus %d-bit, dma_size = 0x%x\n",
- host->cmd ? host->cmd->opcode : 0,
- host->prev_cmd_code,
- 1 << host->actual_bus_width, host->dma_size);
- }
-
- if (!host->present || timeout)
- host->status_reg = STATUS_TIME_OUT_RESP | STATUS_TIME_OUT_READ |
- STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR;
-
- if (test_bit(IMXMCI_PEND_IRQ_b, &host->pending_events) || timeout) {
- clear_bit(IMXMCI_PEND_IRQ_b, &host->pending_events);
-
- stat = readw(host->base + MMC_REG_STATUS);
- /*
- * This is not required in theory, but there is chance to miss some flag
- * which clears automatically by mask write, FreeScale original code keeps
- * stat from IRQ time so do I
- */
- stat |= host->status_reg;
-
- if (test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events))
- stat &= ~STATUS_CRC_READ_ERR;
-
- if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
- imxmci_busy_wait_for_status(host, &stat,
- STATUS_END_CMD_RESP | STATUS_ERR_MASK,
- 20, "imxmci_tasklet_fnc resp (ERRATUM #4)");
- }
-
- if (stat & (STATUS_END_CMD_RESP | STATUS_ERR_MASK)) {
- if (test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
- imxmci_cmd_done(host, stat);
- if (host->data && (stat & STATUS_ERR_MASK))
- imxmci_data_done(host, stat);
- }
-
- if (test_bit(IMXMCI_PEND_CPU_DATA_b, &host->pending_events)) {
- stat |= readw(host->base + MMC_REG_STATUS);
- if (imxmci_cpu_driven_data(host, &stat)) {
- if (test_and_clear_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events))
- imxmci_cmd_done(host, stat);
- atomic_clear_mask(IMXMCI_PEND_IRQ_m|IMXMCI_PEND_CPU_DATA_m,
- &host->pending_events);
- imxmci_data_done(host, stat);
- }
- }
- }
-
- if (test_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events) &&
- !test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events)) {
-
- stat = readw(host->base + MMC_REG_STATUS);
- /* Same as above */
- stat |= host->status_reg;
-
- if (host->dma_dir == DMA_TO_DEVICE)
- data_dir_mask = STATUS_WRITE_OP_DONE;
- else
- data_dir_mask = STATUS_DATA_TRANS_DONE;
-
- if (stat & data_dir_mask) {
- clear_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events);
- imxmci_data_done(host, stat);
- }
- }
-
- if (test_and_clear_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events)) {
-
- if (host->cmd)
- imxmci_cmd_done(host, STATUS_TIME_OUT_RESP);
-
- if (host->data)
- imxmci_data_done(host, STATUS_TIME_OUT_READ |
- STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR);
-
- if (host->req)
- imxmci_finish_request(host, host->req);
-
- mmc_detect_change(host->mmc, msecs_to_jiffies(100));
-
- }
-}
-
-static void imxmci_request(struct mmc_host *mmc, struct mmc_request *req)
-{
- struct imxmci_host *host = mmc_priv(mmc);
- unsigned int cmdat;
-
- WARN_ON(host->req != NULL);
-
- host->req = req;
-
- cmdat = 0;
-
- if (req->data) {
- imxmci_setup_data(host, req->data);
-
- cmdat |= CMD_DAT_CONT_DATA_ENABLE;
-
- if (req->data->flags & MMC_DATA_WRITE)
- cmdat |= CMD_DAT_CONT_WRITE;
-
- if (req->data->flags & MMC_DATA_STREAM)
- cmdat |= CMD_DAT_CONT_STREAM_BLOCK;
- }
-
- imxmci_start_cmd(host, req->cmd, cmdat);
-}
-
-#define CLK_RATE 19200000
-
-static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct imxmci_host *host = mmc_priv(mmc);
- int prescaler;
-
- if (ios->bus_width == MMC_BUS_WIDTH_4) {
- host->actual_bus_width = MMC_BUS_WIDTH_4;
- imx_gpio_mode(PB11_PF_SD_DAT3);
- BLR(host->dma) = 0; /* burst 64 byte read/write */
- } else {
- host->actual_bus_width = MMC_BUS_WIDTH_1;
- imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11);
- BLR(host->dma) = 16; /* burst 16 byte read/write */
- }
-
- if (host->power_mode != ios->power_mode) {
- switch (ios->power_mode) {
- case MMC_POWER_OFF:
- break;
- case MMC_POWER_UP:
- set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events);
- break;
- case MMC_POWER_ON:
- break;
- }
- host->power_mode = ios->power_mode;
- }
-
- if (ios->clock) {
- unsigned int clk;
- u16 reg;
-
- /* The prescaler is 5 for PERCLK2 equal to 96MHz
- * then 96MHz / 5 = 19.2 MHz
- */
- clk = clk_get_rate(host->clk);
- prescaler = (clk + (CLK_RATE * 7) / 8) / CLK_RATE;
- switch (prescaler) {
- case 0:
- case 1: prescaler = 0;
- break;
- case 2: prescaler = 1;
- break;
- case 3: prescaler = 2;
- break;
- case 4: prescaler = 4;
- break;
- default:
- case 5: prescaler = 5;
- break;
- }
-
- dev_dbg(mmc_dev(host->mmc), "PERCLK2 %d MHz -> prescaler %d\n",
- clk, prescaler);
-
- for (clk = 0; clk < 8; clk++) {
- int x;
- x = CLK_RATE / (1 << clk);
- if (x <= ios->clock)
- break;
- }
-
- /* enable controller */
- reg = readw(host->base + MMC_REG_STR_STP_CLK);
- writew(reg | STR_STP_CLK_ENABLE,
- host->base + MMC_REG_STR_STP_CLK);
-
- imxmci_stop_clock(host);
- writew((prescaler << 3) | clk, host->base + MMC_REG_CLK_RATE);
- /*
- * Under my understanding, clock should not be started there, because it would
- * initiate SDHC sequencer and send last or random command into card
- */
- /* imxmci_start_clock(host); */
-
- dev_dbg(mmc_dev(host->mmc),
- "MMC_CLK_RATE: 0x%08x\n",
- readw(host->base + MMC_REG_CLK_RATE));
- } else {
- imxmci_stop_clock(host);
- }
-}
-
-static int imxmci_get_ro(struct mmc_host *mmc)
-{
- struct imxmci_host *host = mmc_priv(mmc);
-
- if (host->pdata && host->pdata->get_ro)
- return !!host->pdata->get_ro(mmc_dev(mmc));
- /*
- * Board doesn't support read only detection; let the mmc core
- * decide what to do.
- */
- return -ENOSYS;
-}
-
-
-static const struct mmc_host_ops imxmci_ops = {
- .request = imxmci_request,
- .set_ios = imxmci_set_ios,
- .get_ro = imxmci_get_ro,
-};
-
-static void imxmci_check_status(unsigned long data)
-{
- struct imxmci_host *host = (struct imxmci_host *)data;
-
- if (host->pdata && host->pdata->card_present &&
- host->pdata->card_present(mmc_dev(host->mmc)) != host->present) {
- host->present ^= 1;
- dev_info(mmc_dev(host->mmc), "card %s\n",
- host->present ? "inserted" : "removed");
-
- set_bit(IMXMCI_PEND_CARD_XCHG_b, &host->pending_events);
- tasklet_schedule(&host->tasklet);
- }
-
- if (test_bit(IMXMCI_PEND_WAIT_RESP_b, &host->pending_events) ||
- test_bit(IMXMCI_PEND_DMA_DATA_b, &host->pending_events)) {
- atomic_inc(&host->stuck_timeout);
- if (atomic_read(&host->stuck_timeout) > 4)
- tasklet_schedule(&host->tasklet);
- } else {
- atomic_set(&host->stuck_timeout, 0);
-
- }
-
- mod_timer(&host->timer, jiffies + (HZ>>1));
-}
-
-static int __init imxmci_probe(struct platform_device *pdev)
-{
- struct mmc_host *mmc;
- struct imxmci_host *host = NULL;
- struct resource *r;
- int ret = 0, irq;
- u16 rev_no;
-
- pr_info("i.MX mmc driver\n");
-
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
- if (!r || irq < 0)
- return -ENXIO;
-
- r = request_mem_region(r->start, resource_size(r), pdev->name);
- if (!r)
- return -EBUSY;
-
- mmc = mmc_alloc_host(sizeof(struct imxmci_host), &pdev->dev);
- if (!mmc) {
- ret = -ENOMEM;
- goto out;
- }
-
- mmc->ops = &imxmci_ops;
- mmc->f_min = 150000;
- mmc->f_max = CLK_RATE/2;
- mmc->ocr_avail = MMC_VDD_32_33;
- mmc->caps = MMC_CAP_4_BIT_DATA;
-
- /* MMC core transfer sizes tunable parameters */
- 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;
- mmc->max_blk_count = 65535;
-
- host = mmc_priv(mmc);
- host->base = ioremap(r->start, resource_size(r));
- if (!host->base) {
- ret = -ENOMEM;
- goto out;
- }
-
- host->mmc = mmc;
- host->dma_allocated = 0;
- host->pdata = pdev->dev.platform_data;
- if (!host->pdata)
- dev_warn(&pdev->dev, "No platform data provided!\n");
-
- spin_lock_init(&host->lock);
- host->res = r;
- host->irq = irq;
-
- host->clk = clk_get(&pdev->dev, "perclk2");
- if (IS_ERR(host->clk)) {
- ret = PTR_ERR(host->clk);
- goto out;
- }
- clk_enable(host->clk);
-
- imx_gpio_mode(PB8_PF_SD_DAT0);
- imx_gpio_mode(PB9_PF_SD_DAT1);
- imx_gpio_mode(PB10_PF_SD_DAT2);
- /* Configured as GPIO with pull-up to ensure right MCC card mode */
- /* Switched to PB11_PF_SD_DAT3 if 4 bit bus is configured */
- imx_gpio_mode(GPIO_PORTB | GPIO_IN | GPIO_PUEN | 11);
- /* imx_gpio_mode(PB11_PF_SD_DAT3); */
- imx_gpio_mode(PB12_PF_SD_CLK);
- imx_gpio_mode(PB13_PF_SD_CMD);
-
- imxmci_softreset(host);
-
- rev_no = readw(host->base + MMC_REG_REV_NO);
- if (rev_no != 0x390) {
- dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n",
- readw(host->base + MMC_REG_REV_NO));
- goto out;
- }
-
- /* recommended in data sheet */
- writew(0x2db4, host->base + MMC_REG_READ_TO);
-
- host->imask = IMXMCI_INT_MASK_DEFAULT;
- writew(host->imask, host->base + MMC_REG_INT_MASK);
-
- host->dma = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_LOW);
- if(host->dma < 0) {
- dev_err(mmc_dev(host->mmc), "imx_dma_request_by_prio failed\n");
- ret = -EBUSY;
- goto out;
- }
- host->dma_allocated = 1;
- imx_dma_setup_handlers(host->dma, imxmci_dma_irq, NULL, host);
- RSSR(host->dma) = DMA_REQ_SDHC;
-
- tasklet_init(&host->tasklet, imxmci_tasklet_fnc, (unsigned long)host);
- host->status_reg=0;
- host->pending_events=0;
-
- ret = request_irq(host->irq, imxmci_irq, 0, DRIVER_NAME, host);
- if (ret)
- goto out;
-
- if (host->pdata && host->pdata->card_present)
- host->present = host->pdata->card_present(mmc_dev(mmc));
- else /* if there is no way to detect assume that card is present */
- host->present = 1;
-
- init_timer(&host->timer);
- host->timer.data = (unsigned long)host;
- host->timer.function = imxmci_check_status;
- add_timer(&host->timer);
- mod_timer(&host->timer, jiffies + (HZ >> 1));
-
- platform_set_drvdata(pdev, mmc);
-
- mmc_add_host(mmc);
-
- return 0;
-
-out:
- if (host) {
- if (host->dma_allocated) {
- imx_dma_free(host->dma);
- host->dma_allocated = 0;
- }
- if (host->clk) {
- clk_disable(host->clk);
- clk_put(host->clk);
- }
- if (host->base)
- iounmap(host->base);
- }
- if (mmc)
- mmc_free_host(mmc);
- release_mem_region(r->start, resource_size(r));
- return ret;
-}
-
-static int __exit imxmci_remove(struct platform_device *pdev)
-{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
-
- platform_set_drvdata(pdev, NULL);
-
- if (mmc) {
- struct imxmci_host *host = mmc_priv(mmc);
-
- tasklet_disable(&host->tasklet);
-
- del_timer_sync(&host->timer);
- mmc_remove_host(mmc);
-
- free_irq(host->irq, host);
- iounmap(host->base);
- if (host->dma_allocated) {
- imx_dma_free(host->dma);
- host->dma_allocated = 0;
- }
-
- tasklet_kill(&host->tasklet);
-
- clk_disable(host->clk);
- clk_put(host->clk);
-
- release_mem_region(host->res->start, resource_size(host->res));
-
- mmc_free_host(mmc);
- }
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int imxmci_suspend(struct platform_device *dev, pm_message_t state)
-{
- struct mmc_host *mmc = platform_get_drvdata(dev);
- int ret = 0;
-
- if (mmc)
- ret = mmc_suspend_host(mmc);
-
- return ret;
-}
-
-static int imxmci_resume(struct platform_device *dev)
-{
- struct mmc_host *mmc = platform_get_drvdata(dev);
- struct imxmci_host *host;
- int ret = 0;
-
- if (mmc) {
- host = mmc_priv(mmc);
- if (host)
- set_bit(IMXMCI_PEND_SET_INIT_b, &host->pending_events);
- ret = mmc_resume_host(mmc);
- }
-
- return ret;
-}
-#else
-#define imxmci_suspend NULL
-#define imxmci_resume NULL
-#endif /* CONFIG_PM */
-
-static struct platform_driver imxmci_driver = {
- .remove = __exit_p(imxmci_remove),
- .suspend = imxmci_suspend,
- .resume = imxmci_resume,
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- }
-};
-
-static int __init imxmci_init(void)
-{
- return platform_driver_probe(&imxmci_driver, imxmci_probe);
-}
-
-static void __exit imxmci_exit(void)
-{
- platform_driver_unregister(&imxmci_driver);
-}
-
-module_init(imxmci_init);
-module_exit(imxmci_exit);
-
-MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver");
-MODULE_AUTHOR("Sascha Hauer, Pengutronix");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-mmc");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/imxmmc.h b/ANDROID_3.4.5/drivers/mmc/host/imxmmc.h
deleted file mode 100644
index 09d5d4ee..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/imxmmc.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#define MMC_REG_STR_STP_CLK 0x00
-#define MMC_REG_STATUS 0x04
-#define MMC_REG_CLK_RATE 0x08
-#define MMC_REG_CMD_DAT_CONT 0x0C
-#define MMC_REG_RES_TO 0x10
-#define MMC_REG_READ_TO 0x14
-#define MMC_REG_BLK_LEN 0x18
-#define MMC_REG_NOB 0x1C
-#define MMC_REG_REV_NO 0x20
-#define MMC_REG_INT_MASK 0x24
-#define MMC_REG_CMD 0x28
-#define MMC_REG_ARGH 0x2C
-#define MMC_REG_ARGL 0x30
-#define MMC_REG_RES_FIFO 0x34
-#define MMC_REG_BUFFER_ACCESS 0x38
-
-#define STR_STP_CLK_IPG_CLK_GATE_DIS (1<<15)
-#define STR_STP_CLK_IPG_PERCLK_GATE_DIS (1<<14)
-#define STR_STP_CLK_ENDIAN (1<<5)
-#define STR_STP_CLK_RESET (1<<3)
-#define STR_STP_CLK_ENABLE (1<<2)
-#define STR_STP_CLK_START_CLK (1<<1)
-#define STR_STP_CLK_STOP_CLK (1<<0)
-#define STATUS_CARD_PRESENCE (1<<15)
-#define STATUS_SDIO_INT_ACTIVE (1<<14)
-#define STATUS_END_CMD_RESP (1<<13)
-#define STATUS_WRITE_OP_DONE (1<<12)
-#define STATUS_DATA_TRANS_DONE (1<<11)
-#define STATUS_WR_CRC_ERROR_CODE_MASK (3<<10)
-#define STATUS_CARD_BUS_CLK_RUN (1<<8)
-#define STATUS_APPL_BUFF_FF (1<<7)
-#define STATUS_APPL_BUFF_FE (1<<6)
-#define STATUS_RESP_CRC_ERR (1<<5)
-#define STATUS_CRC_READ_ERR (1<<3)
-#define STATUS_CRC_WRITE_ERR (1<<2)
-#define STATUS_TIME_OUT_RESP (1<<1)
-#define STATUS_TIME_OUT_READ (1<<0)
-#define STATUS_ERR_MASK 0x2f
-#define CLK_RATE_PRESCALER(x) ((x) & 0x7)
-#define CLK_RATE_CLK_RATE(x) (((x) & 0x7) << 3)
-#define CMD_DAT_CONT_CMD_RESP_LONG_OFF (1<<12)
-#define CMD_DAT_CONT_STOP_READWAIT (1<<11)
-#define CMD_DAT_CONT_START_READWAIT (1<<10)
-#define CMD_DAT_CONT_BUS_WIDTH_1 (0<<8)
-#define CMD_DAT_CONT_BUS_WIDTH_4 (2<<8)
-#define CMD_DAT_CONT_INIT (1<<7)
-#define CMD_DAT_CONT_BUSY (1<<6)
-#define CMD_DAT_CONT_STREAM_BLOCK (1<<5)
-#define CMD_DAT_CONT_WRITE (1<<4)
-#define CMD_DAT_CONT_DATA_ENABLE (1<<3)
-#define CMD_DAT_CONT_RESPONSE_FORMAT_R1 (1)
-#define CMD_DAT_CONT_RESPONSE_FORMAT_R2 (2)
-#define CMD_DAT_CONT_RESPONSE_FORMAT_R3 (3)
-#define CMD_DAT_CONT_RESPONSE_FORMAT_R4 (4)
-#define CMD_DAT_CONT_RESPONSE_FORMAT_R5 (5)
-#define CMD_DAT_CONT_RESPONSE_FORMAT_R6 (6)
-#define INT_MASK_AUTO_CARD_DETECT (1<<6)
-#define INT_MASK_DAT0_EN (1<<5)
-#define INT_MASK_SDIO (1<<4)
-#define INT_MASK_BUF_READY (1<<3)
-#define INT_MASK_END_CMD_RES (1<<2)
-#define INT_MASK_WRITE_OP_DONE (1<<1)
-#define INT_MASK_DATA_TRAN (1<<0)
-#define INT_ALL (0x7f)
diff --git a/ANDROID_3.4.5/drivers/mmc/host/jz4740_mmc.c b/ANDROID_3.4.5/drivers/mmc/host/jz4740_mmc.c
deleted file mode 100644
index c8852a81..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/jz4740_mmc.c
+++ /dev/null
@@ -1,1019 +0,0 @@
-/*
- * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
- * JZ4740 SD/MMC controller driver
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/mmc/host.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/scatterlist.h>
-#include <linux/clk.h>
-
-#include <linux/bitops.h>
-#include <linux/gpio.h>
-#include <asm/mach-jz4740/gpio.h>
-#include <asm/cacheflush.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/mach-jz4740/jz4740_mmc.h>
-
-#define JZ_REG_MMC_STRPCL 0x00
-#define JZ_REG_MMC_STATUS 0x04
-#define JZ_REG_MMC_CLKRT 0x08
-#define JZ_REG_MMC_CMDAT 0x0C
-#define JZ_REG_MMC_RESTO 0x10
-#define JZ_REG_MMC_RDTO 0x14
-#define JZ_REG_MMC_BLKLEN 0x18
-#define JZ_REG_MMC_NOB 0x1C
-#define JZ_REG_MMC_SNOB 0x20
-#define JZ_REG_MMC_IMASK 0x24
-#define JZ_REG_MMC_IREG 0x28
-#define JZ_REG_MMC_CMD 0x2C
-#define JZ_REG_MMC_ARG 0x30
-#define JZ_REG_MMC_RESP_FIFO 0x34
-#define JZ_REG_MMC_RXFIFO 0x38
-#define JZ_REG_MMC_TXFIFO 0x3C
-
-#define JZ_MMC_STRPCL_EXIT_MULTIPLE BIT(7)
-#define JZ_MMC_STRPCL_EXIT_TRANSFER BIT(6)
-#define JZ_MMC_STRPCL_START_READWAIT BIT(5)
-#define JZ_MMC_STRPCL_STOP_READWAIT BIT(4)
-#define JZ_MMC_STRPCL_RESET BIT(3)
-#define JZ_MMC_STRPCL_START_OP BIT(2)
-#define JZ_MMC_STRPCL_CLOCK_CONTROL (BIT(1) | BIT(0))
-#define JZ_MMC_STRPCL_CLOCK_STOP BIT(0)
-#define JZ_MMC_STRPCL_CLOCK_START BIT(1)
-
-
-#define JZ_MMC_STATUS_IS_RESETTING BIT(15)
-#define JZ_MMC_STATUS_SDIO_INT_ACTIVE BIT(14)
-#define JZ_MMC_STATUS_PRG_DONE BIT(13)
-#define JZ_MMC_STATUS_DATA_TRAN_DONE BIT(12)
-#define JZ_MMC_STATUS_END_CMD_RES BIT(11)
-#define JZ_MMC_STATUS_DATA_FIFO_AFULL BIT(10)
-#define JZ_MMC_STATUS_IS_READWAIT BIT(9)
-#define JZ_MMC_STATUS_CLK_EN BIT(8)
-#define JZ_MMC_STATUS_DATA_FIFO_FULL BIT(7)
-#define JZ_MMC_STATUS_DATA_FIFO_EMPTY BIT(6)
-#define JZ_MMC_STATUS_CRC_RES_ERR BIT(5)
-#define JZ_MMC_STATUS_CRC_READ_ERROR BIT(4)
-#define JZ_MMC_STATUS_TIMEOUT_WRITE BIT(3)
-#define JZ_MMC_STATUS_CRC_WRITE_ERROR BIT(2)
-#define JZ_MMC_STATUS_TIMEOUT_RES BIT(1)
-#define JZ_MMC_STATUS_TIMEOUT_READ BIT(0)
-
-#define JZ_MMC_STATUS_READ_ERROR_MASK (BIT(4) | BIT(0))
-#define JZ_MMC_STATUS_WRITE_ERROR_MASK (BIT(3) | BIT(2))
-
-
-#define JZ_MMC_CMDAT_IO_ABORT BIT(11)
-#define JZ_MMC_CMDAT_BUS_WIDTH_4BIT BIT(10)
-#define JZ_MMC_CMDAT_DMA_EN BIT(8)
-#define JZ_MMC_CMDAT_INIT BIT(7)
-#define JZ_MMC_CMDAT_BUSY BIT(6)
-#define JZ_MMC_CMDAT_STREAM BIT(5)
-#define JZ_MMC_CMDAT_WRITE BIT(4)
-#define JZ_MMC_CMDAT_DATA_EN BIT(3)
-#define JZ_MMC_CMDAT_RESPONSE_FORMAT (BIT(2) | BIT(1) | BIT(0))
-#define JZ_MMC_CMDAT_RSP_R1 1
-#define JZ_MMC_CMDAT_RSP_R2 2
-#define JZ_MMC_CMDAT_RSP_R3 3
-
-#define JZ_MMC_IRQ_SDIO BIT(7)
-#define JZ_MMC_IRQ_TXFIFO_WR_REQ BIT(6)
-#define JZ_MMC_IRQ_RXFIFO_RD_REQ BIT(5)
-#define JZ_MMC_IRQ_END_CMD_RES BIT(2)
-#define JZ_MMC_IRQ_PRG_DONE BIT(1)
-#define JZ_MMC_IRQ_DATA_TRAN_DONE BIT(0)
-
-
-#define JZ_MMC_CLK_RATE 24000000
-
-enum jz4740_mmc_state {
- JZ4740_MMC_STATE_READ_RESPONSE,
- JZ4740_MMC_STATE_TRANSFER_DATA,
- JZ4740_MMC_STATE_SEND_STOP,
- JZ4740_MMC_STATE_DONE,
-};
-
-struct jz4740_mmc_host {
- struct mmc_host *mmc;
- struct platform_device *pdev;
- struct jz4740_mmc_platform_data *pdata;
- struct clk *clk;
-
- int irq;
- int card_detect_irq;
-
- struct resource *mem;
- void __iomem *base;
- struct mmc_request *req;
- struct mmc_command *cmd;
-
- unsigned long waiting;
-
- uint32_t cmdat;
-
- uint16_t irq_mask;
-
- spinlock_t lock;
-
- struct timer_list timeout_timer;
- struct sg_mapping_iter miter;
- enum jz4740_mmc_state state;
-};
-
-static void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host,
- unsigned int irq, bool enabled)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- if (enabled)
- host->irq_mask &= ~irq;
- else
- host->irq_mask |= irq;
- spin_unlock_irqrestore(&host->lock, flags);
-
- writew(host->irq_mask, host->base + JZ_REG_MMC_IMASK);
-}
-
-static void jz4740_mmc_clock_enable(struct jz4740_mmc_host *host,
- bool start_transfer)
-{
- uint16_t val = JZ_MMC_STRPCL_CLOCK_START;
-
- if (start_transfer)
- val |= JZ_MMC_STRPCL_START_OP;
-
- writew(val, host->base + JZ_REG_MMC_STRPCL);
-}
-
-static void jz4740_mmc_clock_disable(struct jz4740_mmc_host *host)
-{
- uint32_t status;
- unsigned int timeout = 1000;
-
- writew(JZ_MMC_STRPCL_CLOCK_STOP, host->base + JZ_REG_MMC_STRPCL);
- do {
- status = readl(host->base + JZ_REG_MMC_STATUS);
- } while (status & JZ_MMC_STATUS_CLK_EN && --timeout);
-}
-
-static void jz4740_mmc_reset(struct jz4740_mmc_host *host)
-{
- uint32_t status;
- unsigned int timeout = 1000;
-
- writew(JZ_MMC_STRPCL_RESET, host->base + JZ_REG_MMC_STRPCL);
- udelay(10);
- do {
- status = readl(host->base + JZ_REG_MMC_STATUS);
- } while (status & JZ_MMC_STATUS_IS_RESETTING && --timeout);
-}
-
-static void jz4740_mmc_request_done(struct jz4740_mmc_host *host)
-{
- struct mmc_request *req;
-
- req = host->req;
- host->req = NULL;
-
- mmc_request_done(host->mmc, req);
-}
-
-static unsigned int jz4740_mmc_poll_irq(struct jz4740_mmc_host *host,
- unsigned int irq)
-{
- unsigned int timeout = 0x800;
- uint16_t status;
-
- do {
- status = readw(host->base + JZ_REG_MMC_IREG);
- } while (!(status & irq) && --timeout);
-
- if (timeout == 0) {
- set_bit(0, &host->waiting);
- mod_timer(&host->timeout_timer, jiffies + 5*HZ);
- jz4740_mmc_set_irq_enabled(host, irq, true);
- return true;
- }
-
- return false;
-}
-
-static void jz4740_mmc_transfer_check_state(struct jz4740_mmc_host *host,
- struct mmc_data *data)
-{
- int status;
-
- status = readl(host->base + JZ_REG_MMC_STATUS);
- if (status & JZ_MMC_STATUS_WRITE_ERROR_MASK) {
- if (status & (JZ_MMC_STATUS_TIMEOUT_WRITE)) {
- host->req->cmd->error = -ETIMEDOUT;
- data->error = -ETIMEDOUT;
- } else {
- host->req->cmd->error = -EIO;
- data->error = -EIO;
- }
- }
-}
-
-static bool jz4740_mmc_write_data(struct jz4740_mmc_host *host,
- struct mmc_data *data)
-{
- struct sg_mapping_iter *miter = &host->miter;
- void __iomem *fifo_addr = host->base + JZ_REG_MMC_TXFIFO;
- uint32_t *buf;
- bool timeout;
- size_t i, j;
-
- while (sg_miter_next(miter)) {
- buf = miter->addr;
- i = miter->length / 4;
- j = i / 8;
- i = i & 0x7;
- while (j) {
- timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ);
- if (unlikely(timeout))
- goto poll_timeout;
-
- writel(buf[0], fifo_addr);
- writel(buf[1], fifo_addr);
- writel(buf[2], fifo_addr);
- writel(buf[3], fifo_addr);
- writel(buf[4], fifo_addr);
- writel(buf[5], fifo_addr);
- writel(buf[6], fifo_addr);
- writel(buf[7], fifo_addr);
- buf += 8;
- --j;
- }
- if (unlikely(i)) {
- timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_TXFIFO_WR_REQ);
- if (unlikely(timeout))
- goto poll_timeout;
-
- while (i) {
- writel(*buf, fifo_addr);
- ++buf;
- --i;
- }
- }
- data->bytes_xfered += miter->length;
- }
- sg_miter_stop(miter);
-
- return false;
-
-poll_timeout:
- miter->consumed = (void *)buf - miter->addr;
- data->bytes_xfered += miter->consumed;
- sg_miter_stop(miter);
-
- return true;
-}
-
-static bool jz4740_mmc_read_data(struct jz4740_mmc_host *host,
- struct mmc_data *data)
-{
- struct sg_mapping_iter *miter = &host->miter;
- void __iomem *fifo_addr = host->base + JZ_REG_MMC_RXFIFO;
- uint32_t *buf;
- uint32_t d;
- uint16_t status;
- size_t i, j;
- unsigned int timeout;
-
- while (sg_miter_next(miter)) {
- buf = miter->addr;
- i = miter->length;
- j = i / 32;
- i = i & 0x1f;
- while (j) {
- timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ);
- if (unlikely(timeout))
- goto poll_timeout;
-
- buf[0] = readl(fifo_addr);
- buf[1] = readl(fifo_addr);
- buf[2] = readl(fifo_addr);
- buf[3] = readl(fifo_addr);
- buf[4] = readl(fifo_addr);
- buf[5] = readl(fifo_addr);
- buf[6] = readl(fifo_addr);
- buf[7] = readl(fifo_addr);
-
- buf += 8;
- --j;
- }
-
- if (unlikely(i)) {
- timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_RXFIFO_RD_REQ);
- if (unlikely(timeout))
- goto poll_timeout;
-
- while (i >= 4) {
- *buf++ = readl(fifo_addr);
- i -= 4;
- }
- if (unlikely(i > 0)) {
- d = readl(fifo_addr);
- memcpy(buf, &d, i);
- }
- }
- data->bytes_xfered += miter->length;
-
- /* This can go away once MIPS implements
- * flush_kernel_dcache_page */
- flush_dcache_page(miter->page);
- }
- sg_miter_stop(miter);
-
- /* For whatever reason there is sometime one word more in the fifo then
- * requested */
- timeout = 1000;
- status = readl(host->base + JZ_REG_MMC_STATUS);
- while (!(status & JZ_MMC_STATUS_DATA_FIFO_EMPTY) && --timeout) {
- d = readl(fifo_addr);
- status = readl(host->base + JZ_REG_MMC_STATUS);
- }
-
- return false;
-
-poll_timeout:
- miter->consumed = (void *)buf - miter->addr;
- data->bytes_xfered += miter->consumed;
- sg_miter_stop(miter);
-
- return true;
-}
-
-static void jz4740_mmc_timeout(unsigned long data)
-{
- struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)data;
-
- if (!test_and_clear_bit(0, &host->waiting))
- return;
-
- jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, false);
-
- host->req->cmd->error = -ETIMEDOUT;
- jz4740_mmc_request_done(host);
-}
-
-static void jz4740_mmc_read_response(struct jz4740_mmc_host *host,
- struct mmc_command *cmd)
-{
- int i;
- uint16_t tmp;
- void __iomem *fifo_addr = host->base + JZ_REG_MMC_RESP_FIFO;
-
- if (cmd->flags & MMC_RSP_136) {
- tmp = readw(fifo_addr);
- for (i = 0; i < 4; ++i) {
- cmd->resp[i] = tmp << 24;
- tmp = readw(fifo_addr);
- cmd->resp[i] |= tmp << 8;
- tmp = readw(fifo_addr);
- cmd->resp[i] |= tmp >> 8;
- }
- } else {
- cmd->resp[0] = readw(fifo_addr) << 24;
- cmd->resp[0] |= readw(fifo_addr) << 8;
- cmd->resp[0] |= readw(fifo_addr) & 0xff;
- }
-}
-
-static void jz4740_mmc_send_command(struct jz4740_mmc_host *host,
- struct mmc_command *cmd)
-{
- uint32_t cmdat = host->cmdat;
-
- host->cmdat &= ~JZ_MMC_CMDAT_INIT;
- jz4740_mmc_clock_disable(host);
-
- host->cmd = cmd;
-
- if (cmd->flags & MMC_RSP_BUSY)
- cmdat |= JZ_MMC_CMDAT_BUSY;
-
- switch (mmc_resp_type(cmd)) {
- case MMC_RSP_R1B:
- case MMC_RSP_R1:
- cmdat |= JZ_MMC_CMDAT_RSP_R1;
- break;
- case MMC_RSP_R2:
- cmdat |= JZ_MMC_CMDAT_RSP_R2;
- break;
- case MMC_RSP_R3:
- cmdat |= JZ_MMC_CMDAT_RSP_R3;
- break;
- default:
- break;
- }
-
- if (cmd->data) {
- cmdat |= JZ_MMC_CMDAT_DATA_EN;
- if (cmd->data->flags & MMC_DATA_WRITE)
- cmdat |= JZ_MMC_CMDAT_WRITE;
- if (cmd->data->flags & MMC_DATA_STREAM)
- cmdat |= JZ_MMC_CMDAT_STREAM;
-
- writew(cmd->data->blksz, host->base + JZ_REG_MMC_BLKLEN);
- writew(cmd->data->blocks, host->base + JZ_REG_MMC_NOB);
- }
-
- writeb(cmd->opcode, host->base + JZ_REG_MMC_CMD);
- writel(cmd->arg, host->base + JZ_REG_MMC_ARG);
- writel(cmdat, host->base + JZ_REG_MMC_CMDAT);
-
- jz4740_mmc_clock_enable(host, 1);
-}
-
-static void jz_mmc_prepare_data_transfer(struct jz4740_mmc_host *host)
-{
- struct mmc_command *cmd = host->req->cmd;
- struct mmc_data *data = cmd->data;
- int direction;
-
- if (data->flags & MMC_DATA_READ)
- direction = SG_MITER_TO_SG;
- else
- direction = SG_MITER_FROM_SG;
-
- sg_miter_start(&host->miter, data->sg, data->sg_len, direction);
-}
-
-
-static irqreturn_t jz_mmc_irq_worker(int irq, void *devid)
-{
- struct jz4740_mmc_host *host = (struct jz4740_mmc_host *)devid;
- struct mmc_command *cmd = host->req->cmd;
- struct mmc_request *req = host->req;
- bool timeout = false;
-
- if (cmd->error)
- host->state = JZ4740_MMC_STATE_DONE;
-
- switch (host->state) {
- case JZ4740_MMC_STATE_READ_RESPONSE:
- if (cmd->flags & MMC_RSP_PRESENT)
- jz4740_mmc_read_response(host, cmd);
-
- if (!cmd->data)
- break;
-
- jz_mmc_prepare_data_transfer(host);
-
- case JZ4740_MMC_STATE_TRANSFER_DATA:
- if (cmd->data->flags & MMC_DATA_READ)
- timeout = jz4740_mmc_read_data(host, cmd->data);
- else
- timeout = jz4740_mmc_write_data(host, cmd->data);
-
- if (unlikely(timeout)) {
- host->state = JZ4740_MMC_STATE_TRANSFER_DATA;
- break;
- }
-
- jz4740_mmc_transfer_check_state(host, cmd->data);
-
- timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_DATA_TRAN_DONE);
- if (unlikely(timeout)) {
- host->state = JZ4740_MMC_STATE_SEND_STOP;
- break;
- }
- writew(JZ_MMC_IRQ_DATA_TRAN_DONE, host->base + JZ_REG_MMC_IREG);
-
- case JZ4740_MMC_STATE_SEND_STOP:
- if (!req->stop)
- break;
-
- jz4740_mmc_send_command(host, req->stop);
-
- timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_PRG_DONE);
- if (timeout) {
- host->state = JZ4740_MMC_STATE_DONE;
- break;
- }
- case JZ4740_MMC_STATE_DONE:
- break;
- }
-
- if (!timeout)
- jz4740_mmc_request_done(host);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t jz_mmc_irq(int irq, void *devid)
-{
- struct jz4740_mmc_host *host = devid;
- struct mmc_command *cmd = host->cmd;
- uint16_t irq_reg, status, tmp;
-
- irq_reg = readw(host->base + JZ_REG_MMC_IREG);
-
- tmp = irq_reg;
- irq_reg &= ~host->irq_mask;
-
- tmp &= ~(JZ_MMC_IRQ_TXFIFO_WR_REQ | JZ_MMC_IRQ_RXFIFO_RD_REQ |
- JZ_MMC_IRQ_PRG_DONE | JZ_MMC_IRQ_DATA_TRAN_DONE);
-
- if (tmp != irq_reg)
- writew(tmp & ~irq_reg, host->base + JZ_REG_MMC_IREG);
-
- if (irq_reg & JZ_MMC_IRQ_SDIO) {
- writew(JZ_MMC_IRQ_SDIO, host->base + JZ_REG_MMC_IREG);
- mmc_signal_sdio_irq(host->mmc);
- irq_reg &= ~JZ_MMC_IRQ_SDIO;
- }
-
- if (host->req && cmd && irq_reg) {
- if (test_and_clear_bit(0, &host->waiting)) {
- del_timer(&host->timeout_timer);
-
- status = readl(host->base + JZ_REG_MMC_STATUS);
-
- if (status & JZ_MMC_STATUS_TIMEOUT_RES) {
- cmd->error = -ETIMEDOUT;
- } else if (status & JZ_MMC_STATUS_CRC_RES_ERR) {
- cmd->error = -EIO;
- } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR |
- JZ_MMC_STATUS_CRC_WRITE_ERROR)) {
- if (cmd->data)
- cmd->data->error = -EIO;
- cmd->error = -EIO;
- } else if (status & (JZ_MMC_STATUS_CRC_READ_ERROR |
- JZ_MMC_STATUS_CRC_WRITE_ERROR)) {
- if (cmd->data)
- cmd->data->error = -EIO;
- cmd->error = -EIO;
- }
-
- jz4740_mmc_set_irq_enabled(host, irq_reg, false);
- writew(irq_reg, host->base + JZ_REG_MMC_IREG);
-
- return IRQ_WAKE_THREAD;
- }
- }
-
- return IRQ_HANDLED;
-}
-
-static int jz4740_mmc_set_clock_rate(struct jz4740_mmc_host *host, int rate)
-{
- int div = 0;
- int real_rate;
-
- jz4740_mmc_clock_disable(host);
- clk_set_rate(host->clk, JZ_MMC_CLK_RATE);
-
- real_rate = clk_get_rate(host->clk);
-
- while (real_rate > rate && div < 7) {
- ++div;
- real_rate >>= 1;
- }
-
- writew(div, host->base + JZ_REG_MMC_CLKRT);
- return real_rate;
-}
-
-static void jz4740_mmc_request(struct mmc_host *mmc, struct mmc_request *req)
-{
- struct jz4740_mmc_host *host = mmc_priv(mmc);
-
- host->req = req;
-
- writew(0xffff, host->base + JZ_REG_MMC_IREG);
-
- writew(JZ_MMC_IRQ_END_CMD_RES, host->base + JZ_REG_MMC_IREG);
- jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_END_CMD_RES, true);
-
- host->state = JZ4740_MMC_STATE_READ_RESPONSE;
- set_bit(0, &host->waiting);
- mod_timer(&host->timeout_timer, jiffies + 5*HZ);
- jz4740_mmc_send_command(host, req->cmd);
-}
-
-static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct jz4740_mmc_host *host = mmc_priv(mmc);
- if (ios->clock)
- jz4740_mmc_set_clock_rate(host, ios->clock);
-
- switch (ios->power_mode) {
- case MMC_POWER_UP:
- jz4740_mmc_reset(host);
- if (gpio_is_valid(host->pdata->gpio_power))
- gpio_set_value(host->pdata->gpio_power,
- !host->pdata->power_active_low);
- host->cmdat |= JZ_MMC_CMDAT_INIT;
- clk_enable(host->clk);
- break;
- case MMC_POWER_ON:
- break;
- default:
- if (gpio_is_valid(host->pdata->gpio_power))
- gpio_set_value(host->pdata->gpio_power,
- host->pdata->power_active_low);
- clk_disable(host->clk);
- break;
- }
-
- switch (ios->bus_width) {
- case MMC_BUS_WIDTH_1:
- host->cmdat &= ~JZ_MMC_CMDAT_BUS_WIDTH_4BIT;
- break;
- case MMC_BUS_WIDTH_4:
- host->cmdat |= JZ_MMC_CMDAT_BUS_WIDTH_4BIT;
- break;
- default:
- break;
- }
-}
-
-static int jz4740_mmc_get_ro(struct mmc_host *mmc)
-{
- struct jz4740_mmc_host *host = mmc_priv(mmc);
- if (!gpio_is_valid(host->pdata->gpio_read_only))
- return -ENOSYS;
-
- return gpio_get_value(host->pdata->gpio_read_only) ^
- host->pdata->read_only_active_low;
-}
-
-static int jz4740_mmc_get_cd(struct mmc_host *mmc)
-{
- struct jz4740_mmc_host *host = mmc_priv(mmc);
- if (!gpio_is_valid(host->pdata->gpio_card_detect))
- return -ENOSYS;
-
- return gpio_get_value(host->pdata->gpio_card_detect) ^
- host->pdata->card_detect_active_low;
-}
-
-static irqreturn_t jz4740_mmc_card_detect_irq(int irq, void *devid)
-{
- struct jz4740_mmc_host *host = devid;
-
- mmc_detect_change(host->mmc, HZ / 2);
-
- return IRQ_HANDLED;
-}
-
-static void jz4740_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
- struct jz4740_mmc_host *host = mmc_priv(mmc);
- jz4740_mmc_set_irq_enabled(host, JZ_MMC_IRQ_SDIO, enable);
-}
-
-static const struct mmc_host_ops jz4740_mmc_ops = {
- .request = jz4740_mmc_request,
- .set_ios = jz4740_mmc_set_ios,
- .get_ro = jz4740_mmc_get_ro,
- .get_cd = jz4740_mmc_get_cd,
- .enable_sdio_irq = jz4740_mmc_enable_sdio_irq,
-};
-
-static const struct jz_gpio_bulk_request jz4740_mmc_pins[] = {
- JZ_GPIO_BULK_PIN(MSC_CMD),
- JZ_GPIO_BULK_PIN(MSC_CLK),
- JZ_GPIO_BULK_PIN(MSC_DATA0),
- JZ_GPIO_BULK_PIN(MSC_DATA1),
- JZ_GPIO_BULK_PIN(MSC_DATA2),
- JZ_GPIO_BULK_PIN(MSC_DATA3),
-};
-
-static int __devinit jz4740_mmc_request_gpio(struct device *dev, int gpio,
- const char *name, bool output, int value)
-{
- int ret;
-
- if (!gpio_is_valid(gpio))
- return 0;
-
- ret = gpio_request(gpio, name);
- if (ret) {
- dev_err(dev, "Failed to request %s gpio: %d\n", name, ret);
- return ret;
- }
-
- if (output)
- gpio_direction_output(gpio, value);
- else
- gpio_direction_input(gpio);
-
- return 0;
-}
-
-static int __devinit jz4740_mmc_request_gpios(struct platform_device *pdev)
-{
- int ret;
- struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
-
- if (!pdata)
- return 0;
-
- ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_card_detect,
- "MMC detect change", false, 0);
- if (ret)
- goto err;
-
- ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_read_only,
- "MMC read only", false, 0);
- if (ret)
- goto err_free_gpio_card_detect;
-
- ret = jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_power,
- "MMC read only", true, pdata->power_active_low);
- if (ret)
- goto err_free_gpio_read_only;
-
- return 0;
-
-err_free_gpio_read_only:
- if (gpio_is_valid(pdata->gpio_read_only))
- gpio_free(pdata->gpio_read_only);
-err_free_gpio_card_detect:
- if (gpio_is_valid(pdata->gpio_card_detect))
- gpio_free(pdata->gpio_card_detect);
-err:
- return ret;
-}
-
-static int __devinit jz4740_mmc_request_cd_irq(struct platform_device *pdev,
- struct jz4740_mmc_host *host)
-{
- struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
-
- if (!gpio_is_valid(pdata->gpio_card_detect))
- return 0;
-
- host->card_detect_irq = gpio_to_irq(pdata->gpio_card_detect);
- if (host->card_detect_irq < 0) {
- dev_warn(&pdev->dev, "Failed to get card detect irq\n");
- return 0;
- }
-
- return request_irq(host->card_detect_irq, jz4740_mmc_card_detect_irq,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "MMC card detect", host);
-}
-
-static void jz4740_mmc_free_gpios(struct platform_device *pdev)
-{
- struct jz4740_mmc_platform_data *pdata = pdev->dev.platform_data;
-
- if (!pdata)
- return;
-
- if (gpio_is_valid(pdata->gpio_power))
- gpio_free(pdata->gpio_power);
- if (gpio_is_valid(pdata->gpio_read_only))
- gpio_free(pdata->gpio_read_only);
- if (gpio_is_valid(pdata->gpio_card_detect))
- gpio_free(pdata->gpio_card_detect);
-}
-
-static inline size_t jz4740_mmc_num_pins(struct jz4740_mmc_host *host)
-{
- size_t num_pins = ARRAY_SIZE(jz4740_mmc_pins);
- if (host->pdata && host->pdata->data_1bit)
- num_pins -= 3;
-
- return num_pins;
-}
-
-static int __devinit jz4740_mmc_probe(struct platform_device* pdev)
-{
- int ret;
- struct mmc_host *mmc;
- struct jz4740_mmc_host *host;
- struct jz4740_mmc_platform_data *pdata;
-
- pdata = pdev->dev.platform_data;
-
- mmc = mmc_alloc_host(sizeof(struct jz4740_mmc_host), &pdev->dev);
- if (!mmc) {
- dev_err(&pdev->dev, "Failed to alloc mmc host structure\n");
- return -ENOMEM;
- }
-
- host = mmc_priv(mmc);
- host->pdata = pdata;
-
- host->irq = platform_get_irq(pdev, 0);
- if (host->irq < 0) {
- ret = host->irq;
- dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
- goto err_free_host;
- }
-
- host->clk = clk_get(&pdev->dev, "mmc");
- if (IS_ERR(host->clk)) {
- ret = PTR_ERR(host->clk);
- dev_err(&pdev->dev, "Failed to get mmc clock\n");
- goto err_free_host;
- }
-
- host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!host->mem) {
- ret = -ENOENT;
- dev_err(&pdev->dev, "Failed to get base platform memory\n");
- goto err_clk_put;
- }
-
- host->mem = request_mem_region(host->mem->start,
- resource_size(host->mem), pdev->name);
- if (!host->mem) {
- ret = -EBUSY;
- dev_err(&pdev->dev, "Failed to request base memory region\n");
- goto err_clk_put;
- }
-
- host->base = ioremap_nocache(host->mem->start, resource_size(host->mem));
- if (!host->base) {
- ret = -EBUSY;
- dev_err(&pdev->dev, "Failed to ioremap base memory\n");
- goto err_release_mem_region;
- }
-
- ret = jz_gpio_bulk_request(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
- if (ret) {
- dev_err(&pdev->dev, "Failed to request mmc pins: %d\n", ret);
- goto err_iounmap;
- }
-
- ret = jz4740_mmc_request_gpios(pdev);
- if (ret)
- goto err_gpio_bulk_free;
-
- mmc->ops = &jz4740_mmc_ops;
- mmc->f_min = JZ_MMC_CLK_RATE / 128;
- mmc->f_max = JZ_MMC_CLK_RATE;
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps = (pdata && pdata->data_1bit) ? 0 : MMC_CAP_4_BIT_DATA;
- mmc->caps |= MMC_CAP_SDIO_IRQ;
-
- mmc->max_blk_size = (1 << 10) - 1;
- mmc->max_blk_count = (1 << 15) - 1;
- mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
-
- mmc->max_segs = 128;
- mmc->max_seg_size = mmc->max_req_size;
-
- host->mmc = mmc;
- host->pdev = pdev;
- spin_lock_init(&host->lock);
- host->irq_mask = 0xffff;
-
- ret = jz4740_mmc_request_cd_irq(pdev, host);
- if (ret) {
- dev_err(&pdev->dev, "Failed to request card detect irq\n");
- goto err_free_gpios;
- }
-
- ret = request_threaded_irq(host->irq, jz_mmc_irq, jz_mmc_irq_worker, 0,
- dev_name(&pdev->dev), host);
- if (ret) {
- dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
- goto err_free_card_detect_irq;
- }
-
- jz4740_mmc_reset(host);
- jz4740_mmc_clock_disable(host);
- setup_timer(&host->timeout_timer, jz4740_mmc_timeout,
- (unsigned long)host);
- /* It is not important when it times out, it just needs to timeout. */
- set_timer_slack(&host->timeout_timer, HZ);
-
- platform_set_drvdata(pdev, host);
- ret = mmc_add_host(mmc);
-
- if (ret) {
- dev_err(&pdev->dev, "Failed to add mmc host: %d\n", ret);
- goto err_free_irq;
- }
- dev_info(&pdev->dev, "JZ SD/MMC card driver registered\n");
-
- return 0;
-
-err_free_irq:
- free_irq(host->irq, host);
-err_free_card_detect_irq:
- if (host->card_detect_irq >= 0)
- free_irq(host->card_detect_irq, host);
-err_free_gpios:
- jz4740_mmc_free_gpios(pdev);
-err_gpio_bulk_free:
- jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-err_iounmap:
- iounmap(host->base);
-err_release_mem_region:
- release_mem_region(host->mem->start, resource_size(host->mem));
-err_clk_put:
- clk_put(host->clk);
-err_free_host:
- platform_set_drvdata(pdev, NULL);
- mmc_free_host(mmc);
-
- return ret;
-}
-
-static int __devexit jz4740_mmc_remove(struct platform_device *pdev)
-{
- struct jz4740_mmc_host *host = platform_get_drvdata(pdev);
-
- del_timer_sync(&host->timeout_timer);
- jz4740_mmc_set_irq_enabled(host, 0xff, false);
- jz4740_mmc_reset(host);
-
- mmc_remove_host(host->mmc);
-
- free_irq(host->irq, host);
- if (host->card_detect_irq >= 0)
- free_irq(host->card_detect_irq, host);
-
- jz4740_mmc_free_gpios(pdev);
- jz_gpio_bulk_free(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-
- iounmap(host->base);
- release_mem_region(host->mem->start, resource_size(host->mem));
-
- clk_put(host->clk);
-
- platform_set_drvdata(pdev, NULL);
- mmc_free_host(host->mmc);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-
-static int jz4740_mmc_suspend(struct device *dev)
-{
- struct jz4740_mmc_host *host = dev_get_drvdata(dev);
-
- mmc_suspend_host(host->mmc);
-
- jz_gpio_bulk_suspend(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-
- return 0;
-}
-
-static int jz4740_mmc_resume(struct device *dev)
-{
- struct jz4740_mmc_host *host = dev_get_drvdata(dev);
-
- jz_gpio_bulk_resume(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
-
- mmc_resume_host(host->mmc);
-
- return 0;
-}
-
-const struct dev_pm_ops jz4740_mmc_pm_ops = {
- .suspend = jz4740_mmc_suspend,
- .resume = jz4740_mmc_resume,
- .poweroff = jz4740_mmc_suspend,
- .restore = jz4740_mmc_resume,
-};
-
-#define JZ4740_MMC_PM_OPS (&jz4740_mmc_pm_ops)
-#else
-#define JZ4740_MMC_PM_OPS NULL
-#endif
-
-static struct platform_driver jz4740_mmc_driver = {
- .probe = jz4740_mmc_probe,
- .remove = __devexit_p(jz4740_mmc_remove),
- .driver = {
- .name = "jz4740-mmc",
- .owner = THIS_MODULE,
- .pm = JZ4740_MMC_PM_OPS,
- },
-};
-
-module_platform_driver(jz4740_mmc_driver);
-
-MODULE_DESCRIPTION("JZ4740 SD/MMC controller driver");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.c b/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.c
deleted file mode 100755
index 150b7b12..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.c
+++ /dev/null
@@ -1,2837 +0,0 @@
-/*++
-linux/drivers/mmc/host/mmc_atsmb.c
-
-Copyright (c) 2008 WonderMedia Technologies, Inc.
-
-This program is free software: you can redistribute it and/or modify it under the
-terms of the GNU General Public License as published by the Free Software Foundation,
-either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-PARTICULAR PURPOSE. See the GNU General Public License for more details.
-You should have received a copy of the GNU General Public License along with
-this program. If not, see <http://www.gnu.org/licenses/>.
-
-WonderMedia Technologies, Inc.
-10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
---*/
-
-//#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sd.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/sdio.h>
-#include <linux/completion.h>
-#include <linux/pagemap.h>
-#include <linux/dma-mapping.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/memory.h>
-#include <mach/hardware.h>
-#include <asm/scatterlist.h>
-#include <asm/sizes.h>
-#include "mmc_atsmb.h"
-//#include <mach/multicard.h>
-#include <mach/irqs.h>
-#include <linux/regulator/consumer.h>
-
-#define mprintk
-
-#if 0
-#define DBG(host, fmt, args...) \
- printk("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args)
-#endif
-#define ATSMB_TIMEOUT_TIME (HZ*2)
-
-
-static struct delayed_work mmc_work;
-
-static int g_atsmb_regulator;
-static struct regulator *atsmb_regulator;
-
-
-//add by jay,for modules support
-static u64 wmt_sdmmc_dma_mask = 0xffffffffUL;
-static struct resource wmt_sdmmc_resources[] = {
- [0] = {
- .start = SD0_SDIO_MMC_BASE_ADDR,
- .end = (SD0_SDIO_MMC_BASE_ADDR + 0x3FF),
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_SDC0,
- .end = IRQ_SDC0,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
- .start = IRQ_SDC0_DMA,
- .end = IRQ_SDC0_DMA,
- .flags = IORESOURCE_IRQ,
- },
- /*2008/10/6 RichardHsu-s*/
- [3] = {
- .start = IRQ_PMC_WAKEUP,
- .end = IRQ_PMC_WAKEUP,
- .flags = IORESOURCE_IRQ,
- },
- /*2008/10/6 RichardHsu-e*/
-};
-
-struct kobject *atsmb_kobj;
-struct mmc_host *mmc_host_attr = NULL;
-//
-static void atsmb_release(struct device * dev) {}
-
-/*#ifdef CONFIG_MMC_DEBUG*/
-#define MORE_INFO
-#if 0
-#define DBG(x...) printk(KERN_ALERT x)
-#define DBGR(x...) do { } while (0)
-#else
-#define DBG(x...) do { } while (0)
-#define DBGR(x...) do { } while (0)
-#endif
-
-/* when Read CRC error occur, and clear read CRC error by software reset.*/
-void atsmb_copy_reg(int direct)
-{
- static u8 CTL, CMD_IDX, RSP_TYPE, BUS_MODE, INT_MASK_0, INT_MASK_1, SD_STS_0, SD_STS_1, SD_STS_2, SD_STS_3;
- static u8 EXT_BUS_MODE, EXT_CTL_1, EXT_CTL_2, MAN_TUNE_VAL, SD_WRI_TUNE;
- static u8 RSP_0, RSP_1, RSP_2, RSP_3, RSP_4, RSP_5, RSP_6, RSP_7;
- static u8 RSP_8, RSP_9, RSP_10, RSP_11, RSP_12, RSP_13, RSP_14, RSP_15;
- static u8 RSP_TOUT, CLK_SEL, EXT_CTL;
- static u16 BLK_LEN, BLK_CNT, SHDW_BLKLEN, TIMER_VAL, CTL2;
- static u32 CMD_ARG, CURBLK_CNT;
-
- /*direct 0: copy register to memory; 1: copy memory to register.*/
- if (direct == 0) {
- CTL = *ATSMB0_CTL;
- CMD_IDX = *ATSMB0_CMD_IDX;
- RSP_TYPE = *ATSMB0_RSP_TYPE;
- CMD_ARG = *ATSMB0_CMD_ARG;
- BUS_MODE = *ATSMB0_BUS_MODE;
- EXT_BUS_MODE = *ATSMB0_EXT_BUS_MODE;
- CTL2 = *ATSMB0_CTL2;
- BLK_LEN = *ATSMB0_BLK_LEN;
- BLK_CNT = *ATSMB0_BLK_CNT;
- RSP_0 = *ATSMB0_RSP_0;
- RSP_1 = *ATSMB0_RSP_1;
- RSP_2 = *ATSMB0_RSP_2;
- RSP_3 = *ATSMB0_RSP_3;
- RSP_4 = *ATSMB0_RSP_4;
- RSP_5 = *ATSMB0_RSP_5;
- RSP_6 = *ATSMB0_RSP_6;
- RSP_7 = *ATSMB0_RSP_7;
- RSP_8 = *ATSMB0_RSP_8;
- RSP_9 = *ATSMB0_RSP_9;
- RSP_10 = *ATSMB0_RSP_10;
- RSP_11 = *ATSMB0_RSP_11;
- RSP_12 = *ATSMB0_RSP_12;
- RSP_13 = *ATSMB0_RSP_13;
- RSP_14 = *ATSMB0_RSP_14;
- RSP_15 = *ATSMB0_RSP_15;
- CURBLK_CNT = *ATSMB0_CURBLK_CNT;
- INT_MASK_0 = *ATSMB0_INT_MASK_0;
- INT_MASK_1 = *ATSMB0_INT_MASK_1;
- SD_STS_0 = *ATSMB0_SD_STS_0;
- SD_STS_1 = *ATSMB0_SD_STS_1;
- SD_STS_2 = *ATSMB0_SD_STS_2;
- SD_STS_3 = *ATSMB0_SD_STS_3;
- RSP_TOUT = *ATSMB0_RSP_TOUT;
- CLK_SEL = *ATSMB0_CLK_SEL;
- EXT_CTL = *ATSMB0_EXT_CTL;
- EXT_CTL_1 = *ATSMB0_EXT_CTL_1;
- EXT_CTL_2 = *ATSMB0_EXT_CTL_2;
- SHDW_BLKLEN = *ATSMB0_SHDW_BLKLEN;
- MAN_TUNE_VAL = *ATSMB0_MAN_TUNE_VAL;
- SD_WRI_TUNE = *ATSMB0_SD_WRI_TUNE;
- TIMER_VAL = *ATSMB0_TIMER_VAL;
- } else {
- *ATSMB0_CTL = CTL;
- *ATSMB0_CMD_IDX = CMD_IDX;
- *ATSMB0_RSP_TYPE = RSP_TYPE;
- *ATSMB0_CMD_ARG = CMD_ARG;
- *ATSMB0_BUS_MODE = BUS_MODE;
- *ATSMB0_EXT_BUS_MODE = EXT_BUS_MODE;
- *ATSMB0_CTL2 = CTL2;
- *ATSMB0_BLK_LEN = BLK_LEN;
- *ATSMB0_BLK_CNT = BLK_CNT;
- *ATSMB0_RSP_0 = RSP_0;
- *ATSMB0_RSP_1 = RSP_1;
- *ATSMB0_RSP_2 = RSP_2;
- *ATSMB0_RSP_3 = RSP_3;
- *ATSMB0_RSP_4 = RSP_4;
- *ATSMB0_RSP_5 = RSP_5;
- *ATSMB0_RSP_6 = RSP_6;
- *ATSMB0_RSP_7 = RSP_7;
- *ATSMB0_RSP_8 = RSP_8;
- *ATSMB0_RSP_9 = RSP_9;
- *ATSMB0_RSP_10 = RSP_10;
- *ATSMB0_RSP_11 = RSP_11;
- *ATSMB0_RSP_12 = RSP_12;
- *ATSMB0_RSP_13 = RSP_13;
- *ATSMB0_RSP_14 = RSP_14;
- *ATSMB0_RSP_15 = RSP_15;
- *ATSMB0_CURBLK_CNT = CURBLK_CNT;
- *ATSMB0_INT_MASK_0 = INT_MASK_0;
- *ATSMB0_INT_MASK_1 = INT_MASK_1;
- *ATSMB0_SD_STS_0 = SD_STS_0;
- *ATSMB0_SD_STS_1 = SD_STS_1;
- *ATSMB0_SD_STS_2 = SD_STS_2;
- *ATSMB0_SD_STS_3 = SD_STS_3;
- *ATSMB0_RSP_TOUT = RSP_TOUT;
- *ATSMB0_CLK_SEL = CLK_SEL;
- *ATSMB0_EXT_CTL = EXT_CTL;
- *ATSMB0_EXT_CTL_1 = EXT_CTL_1;
- *ATSMB0_EXT_CTL_2 = EXT_CTL_2;
- *ATSMB0_SHDW_BLKLEN = SHDW_BLKLEN;
- *ATSMB0_MAN_TUNE_VAL = MAN_TUNE_VAL;
- *ATSMB0_SD_WRI_TUNE = SD_WRI_TUNE;
- *ATSMB0_TIMER_VAL = TIMER_VAL;
- }
-}
-
-#if 0
-void atsmb_dump_reg(void)
-{
- u8 CTL, CMD_IDX, RSP_TYPE, BUS_MODE, INT_MASK_0, INT_MASK_1, SD_STS_0, SD_STS_1, SD_STS_2, SD_STS_3;
- u8 EXT_BUS_MODE, EXT_CTL_1, EXT_CTL_2, MAN_TUNE_VAL, SD_WRI_TUNE;
- u8 RSP_0, RSP_1, RSP_2, RSP_3, RSP_4, RSP_5, RSP_6, RSP_7;
- u8 RSP_8, RSP_9, RSP_10, RSP_11, RSP_12, RSP_13, RSP_14, RSP_15;
- u8 RSP_TOUT, CLK_SEL, EXT_CTL;
- u16 BLK_LEN, BLK_CNT, SHDW_BLKLEN, TIMER_VAL, CTL2;
- u32 CMD_ARG, PDMA_GCR, PDMA_IER, PDMA_ISR, PDMA_DESPR, PDMA_RBR, PDMA_DAR, PDMA_BAR, PDMA_CPR, PDMA_CCR;
- u32 CURBLK_CNT;
-
- CTL = *ATSMB0_CTL;
- CMD_IDX = *ATSMB0_CMD_IDX;
- RSP_TYPE = *ATSMB0_RSP_TYPE;
- CMD_ARG = *ATSMB0_CMD_ARG;
- BUS_MODE = *ATSMB0_BUS_MODE;
- EXT_BUS_MODE = *ATSMB0_EXT_BUS_MODE;
- CTL2 = *ATSMB0_CTL2;
- BLK_LEN = *ATSMB0_BLK_LEN;
- BLK_CNT = *ATSMB0_BLK_CNT;
- RSP_0 = *ATSMB0_RSP_0;
- RSP_1 = *ATSMB0_RSP_1;
- RSP_2 = *ATSMB0_RSP_2;
- RSP_3 = *ATSMB0_RSP_3;
- RSP_4 = *ATSMB0_RSP_4;
- RSP_5 = *ATSMB0_RSP_5;
- RSP_6 = *ATSMB0_RSP_6;
- RSP_7 = *ATSMB0_RSP_7;
- RSP_8 = *ATSMB0_RSP_8;
- RSP_9 = *ATSMB0_RSP_9;
- RSP_10 = *ATSMB0_RSP_10;
- RSP_11 = *ATSMB0_RSP_11;
- RSP_12 = *ATSMB0_RSP_12;
- RSP_13 = *ATSMB0_RSP_13;
- RSP_14 = *ATSMB0_RSP_14;
- RSP_15 = *ATSMB0_RSP_15;
- CURBLK_CNT = *ATSMB0_CURBLK_CNT;
- INT_MASK_0 = *ATSMB0_INT_MASK_0;
- INT_MASK_1 = *ATSMB0_INT_MASK_1;
- SD_STS_0 = *ATSMB0_SD_STS_0;
- SD_STS_1 = *ATSMB0_SD_STS_1;
- SD_STS_2 = *ATSMB0_SD_STS_2;
- SD_STS_3 = *ATSMB0_SD_STS_3;
- RSP_TOUT = *ATSMB0_RSP_TOUT;
- CLK_SEL = *ATSMB0_CLK_SEL;
- EXT_CTL = *ATSMB0_EXT_CTL;
- EXT_CTL_1 = *ATSMB0_EXT_CTL_1;
- EXT_CTL_2 = *ATSMB0_EXT_CTL_2;
- SHDW_BLKLEN = *ATSMB0_SHDW_BLKLEN;
- MAN_TUNE_VAL = *ATSMB0_MAN_TUNE_VAL;
- SD_WRI_TUNE = *ATSMB0_SD_WRI_TUNE;
- TIMER_VAL = *ATSMB0_TIMER_VAL;
-
- PDMA_GCR = *ATSMB0_PDMA_GCR;
- PDMA_IER = *ATSMB0_PDMA_IER;
- PDMA_ISR = *ATSMB0_PDMA_ISR;
- PDMA_DESPR = *ATSMB0_PDMA_DESPR;
- PDMA_RBR = *ATSMB0_PDMA_RBR;
- PDMA_DAR = *ATSMB0_PDMA_DAR;
- PDMA_BAR = *ATSMB0_PDMA_BAR;
- PDMA_CPR = *ATSMB0_PDMA_CPR;
- PDMA_CCR = *ATSMB0_PDMA_CCR;
-
- DBGR("\n+---------------------------Registers----------------------------+\n");
-
- DBGR("%16s = 0x%8x |", "CTL", CTL);
- DBGR("%16s = 0x%8x\n", "CMD_IDX", CMD_IDX);
-
- DBGR("%16s = 0x%8x |", "RSP_TYPE", RSP_TYPE);
- DBGR("%16s = 0x%8x\n", "CMD_ARG", CMD_ARG);
-
- DBGR("%16s = 0x%8x |", "BUS_MODE", BUS_MODE);
- DBGR("%16s = 0x%8x\n", "EXT_BUS_MODE", EXT_BUS_MODE);
-
- DBGR("%16s = 0x%8x |", "CTL2", CTL2);
- DBGR("%16s = 0x%8x\n", "BLK_LEN", BLK_LEN);
-
- DBGR("%16s = 0x%8x |", "BLK_CNT", BLK_CNT);
- DBGR("%16s = 0x%8x\n", "RSP_0", RSP_0);
-
- DBGR("%16s = 0x%8x |", "RSP_1", RSP_1);
- DBGR("%16s = 0x%8x\n", "RSP_2", RSP_2);
-
- DBGR("%16s = 0x%8x |", "RSP_3", RSP_3);
- DBGR("%16s = 0x%8x\n", "RSP_4", RSP_4);
-
- DBGR("%16s = 0x%8x |", "RSP_5", RSP_5);
- DBGR("%16s = 0x%8x\n", "RSP_6", RSP_6);
-
- DBGR("%16s = 0x%8x |", "RSP_7", RSP_7);
- DBGR("%16s = 0x%8x\n", "RSP_8", RSP_8);
-
- DBGR("%16s = 0x%8x |", "RSP_9", RSP_9);
- DBGR("%16s = 0x%8x\n", "RSP_10", RSP_10);
-
- DBGR("%16s = 0x%8x |", "RSP_11", RSP_11);
- DBGR("%16s = 0x%8x\n", "RSP_12", RSP_12);
-
- DBGR("%16s = 0x%8x |", "RSP_13", RSP_13);
- DBGR("%16s = 0x%8x\n", "RSP_14", RSP_14);
-
- DBGR("%16s = 0x%8x\n", "RSP_15", RSP_15);
-
- DBGR("%16s = 0x%8x |", "CURBLK_CNT", CURBLK_CNT);
- DBGR("%16s = 0x%8x\n", "INT_MASK_0", INT_MASK_0);
-
- DBGR("%16s = 0x%8x |", "INT_MASK_1", INT_MASK_1);
- DBGR("%16s = 0x%8x\n", "SD_STS_0", SD_STS_0);
-
- DBGR("%16s = 0x%8x |", "SD_STS_1", SD_STS_1);
- DBGR("%16s = 0x%8x\n", "SD_STS_2", SD_STS_2);
-
- DBGR("%16s = 0x%8x |", "SD_STS_3", SD_STS_3);
- DBGR("%16s = 0x%8x\n", "RSP_TOUT", RSP_TOUT);
-
- DBGR("%16s = 0x%8x |", "CLK_SEL", CLK_SEL);
- DBGR("%16s = 0x%8x\n", "EXT_CTL", EXT_CTL);
-
- DBGR("%16s = 0x%8x |", "EXT_CTL_1", EXT_CTL_1);
- DBGR("%16s = 0x%8x\n", "EXT_CTL_2", EXT_CTL_2);
-
- DBGR("%16s = 0x%8x |", "SHDW_BLKLEN", SHDW_BLKLEN);
- DBGR("%16s = 0x%8x\n", "MAN_TUNE_VAL", MAN_TUNE_VAL);
-
- DBGR("%16s = 0x%8x |", "SD_WRI_TUNE", SD_WRI_TUNE);
- DBGR("%16s = 0x%8x\n", "TIMER_VAL", TIMER_VAL);
-
- DBGR("%16s = 0x%8x |", "PDMA_GCR", PDMA_GCR);
- DBGR("%16s = 0x%8x\n", "PDMA_IER", PDMA_IER);
-
- DBGR("%16s = 0x%8x |", "PDMA_ISR", PDMA_ISR);
- DBGR("%16s = 0x%8x\n", "PDMA_DESPR", PDMA_DESPR);
-
- DBGR("%16s = 0x%8x |", "PDMA_RBR", PDMA_RBR);
- DBGR("%16s = 0x%8x\n", "PDMA_DAR", PDMA_DAR);
-
- DBGR("%16s = 0x%8x |", "PDMA_BAR", PDMA_BAR);
- DBGR("%16s = 0x%8x\n", "PDMA_CPR", PDMA_CPR);
-
- DBGR("%16s = 0x%8x |", "PDMA_CCR", PDMA_CCR);
- DBGR("\n+----------------------------------------------------------------+\n");
-}
-#else
-void atsmb_dump_reg(void) {}
-#endif
-
-unsigned int fmax0 = 515633;
-unsigned int MMC0_DRIVER_VERSION;
-int SD0_function = 0; /*0: normal SD/MMC card reader , 1: internal SDIO wifi*/
-int SDXC0_function;
-static int SD0_detect_pol = 0;
-static int SD0_detect_pulldown = 0;
-static int SD0_speed = 0;
-//add by kevin guan
-int SD0_ro_disable = 0;
-
-int SCC_ID(void){
- unsigned short val;
-
- val = REG16_VAL(SYSTEM_CFG_CTRL_BASE_ADDR + 0x2);
- return val;
-}
-
-int get_chip_version(void) /*2008/05/01 janshiue modify for A1 chip*/
-{
- u32 tmp;
-
- tmp = REG32_VAL(SYSTEM_CFG_CTRL_BASE_ADDR);
- tmp = ((tmp & 0xF00) >> 4) + 0x90 + ((tmp & 0xFF) - 1);
- return tmp;
-}
-
-void get_driver_version(void)
-{
- if (SCC_ID() == 0x3426) {
- if (get_chip_version() < 0xA1)
- MMC0_DRIVER_VERSION = MMC_DRV_3426_A0;
- else if (get_chip_version() == 0xA1)
- MMC0_DRIVER_VERSION = MMC_DRV_3426_A1;
- else
- MMC0_DRIVER_VERSION = MMC_DRV_3426_A2;
- } else if (SCC_ID() == 0x3437) {
- if (get_chip_version() < 0xA1)
- MMC0_DRIVER_VERSION = MMC_DRV_3437_A0;
- else
- MMC0_DRIVER_VERSION = MMC_DRV_3437_A1;
- } else if (SCC_ID() == 0x3429) {
- MMC0_DRIVER_VERSION = MMC_DRV_3429;
- } else if (SCC_ID() == 0x3451) {
- if (get_chip_version() < 0xA1)
- MMC0_DRIVER_VERSION = MMC_DRV_3451_A0;
- } else if (SCC_ID() == 0x3465) {
- MMC0_DRIVER_VERSION = MMC_DRV_3465;
- } else if (SCC_ID() == 0x3445) {
- MMC0_DRIVER_VERSION = MMC_DRV_3445;
- } else if (SCC_ID() == 0x3481) {
- MMC0_DRIVER_VERSION = MMC_DRV_3481;
- } else if (SCC_ID() == 0x3498) {
- MMC0_DRIVER_VERSION = MMC_DRV_3498;
- }
-}
-/*2008/10/6 RichardHsu-e*/
-
-/**********************************************************************
-Name : atsmb_alloc_desc
-Function : To config PDMA descriptor setting.
-Calls :
-Called by :
-Parameter :
-Author : Janshiue Wu
-History :
-***********************************************************************/
-static inline int atsmb_alloc_desc(struct atsmb_host *host,
- unsigned int bytes)
-{
- void *DescPool = NULL;
- DBG("[%s] s\n",__func__);
-
- DescPool = dma_alloc_coherent(host->mmc->parent, bytes, &(host->DescPhyAddr), GFP_KERNEL);
- if (!DescPool) {
- DBG("can't allocal desc pool=%8X %8X\n", DescPool, host->DescPhyAddr);
- DBG("[%s] e1\n",__func__);
- return -1;
- }
- DBG("allocal desc pool=%8X %8X\n", DescPool, host->DescPhyAddr);
- host->DescVirAddr = (unsigned long *)DescPool;
- host->DescSize = bytes;
- DBG("[%s] e2\n",__func__);
- return 0;
-}
-
-/**********************************************************************
-Name : atsmb_config_desc
-Function : To config PDMA descriptor setting.
-Calls :
-Called by :
-Parameter :
-Author : Janshiue Wu
-History :
-***********************************************************************/
-static inline void atsmb_config_desc(unsigned long *DescAddr,
- unsigned long *BufferAddr,
- unsigned long Blk_Cnt)
-{
-
- int i = 0 ;
- unsigned long *CurDes = DescAddr;
- DBG("[%s] s\n",__func__);
-
- /* the first Descriptor store for 1 Block data
- * (512 bytes)
- */
- for (i = 0 ; i < 3 ; i++) {
- atsmb_init_short_desc(CurDes, 0x80, BufferAddr, 0);
- BufferAddr += 0x20;
- CurDes += sizeof(struct SD_PDMA_DESC_S)/4;
- }
- if (Blk_Cnt > 1) {
- atsmb_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 0);
- BufferAddr += 0x20;
- CurDes += sizeof(struct SD_PDMA_DESC_L)/4;
- /* the following Descriptor store the rest Blocks data
- * (Blk_Cnt - 1) * 512 bytes
- */
- atsmb_init_long_desc(CurDes, (Blk_Cnt - 1) * 512,
- BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 1);
- } else {
- atsmb_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 1);
- }
- DBG("[%s] e\n",__func__);
-}
-/**********************************************************************
-Name : atsmb_config_dma
-Function : To set des/src address, byte count to transfer, and DMA channel settings,
- and DMA ctrl. register.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static inline void atsmb_config_dma(unsigned long config_dir,
- unsigned long dma_mask,
- struct atsmb_host *host)
-{
-
- DBG("[%s] s\n",__func__);
- /* Enable DMA */
- *ATSMB0_PDMA_GCR = SD_PDMA_GCR_DMA_EN;
- *ATSMB0_PDMA_GCR = SD_PDMA_GCR_SOFTRESET;
- *ATSMB0_PDMA_GCR = SD_PDMA_GCR_DMA_EN;
- /*open interrupt*/
- *ATSMB0_PDMA_IER = SD_PDMA_IER_INT_EN;
- /*Make sure host could co-work with DMA*/
- *ATSMB0_SD_STS_2 |= ATSMB_CLK_FREEZ_EN;
-
- /*Set timer timeout value*/
- /*If clock is 390KHz*/
- if (host->current_clock < 400000)
- *ATSMB0_TIMER_VAL = 0x200; /*1024*512*(1/390K) second*/
- else
- *ATSMB0_TIMER_VAL = 0x1fff; /*why not to be 0xffff?*/
-
- /*clear all DMA INT status for safety*/
- *ATSMB0_PDMA_ISR |= SD_PDMA_IER_INT_STS;
-
- /* hook desc */
- *ATSMB0_PDMA_DESPR = host->DescPhyAddr;
- if (config_dir == DMA_CFG_WRITE)
- *ATSMB0_PDMA_CCR &= SD_PDMA_CCR_IF_to_peripheral;
- else
- *ATSMB0_PDMA_CCR |= SD_PDMA_CCR_peripheral_to_IF;
-
- host->DmaIntMask = dma_mask; /*save success event*/
-
- *ATSMB0_PDMA_CCR |= SD_PDMA_CCR_RUN;
- DBG("[%s] e\n",__func__);
-}
-
-/**********************************************************************
-Name : atsmb_set_dma_end
-Function : To set all descriptor end bit for removing card when PDMA
- don't transfer data done. let PDMA transfer done
-Calls :
-Called by :
-Parameter :
-Author : Eason Chien
-History : 2013/05/16
-***********************************************************************/
-void atsmb_set_dma_end(unsigned long *DescAddr, unsigned int bytes)
-{
- int i = 0;
- struct SD_PDMA_DESC_S *CurDes_S;
- CurDes_S = (struct SD_PDMA_DESC_S *) DescAddr;
- DBG("[%s] s\n", __func__);
- DBG("[%s] byte = %d, size of %d\n", __func__, bytes, sizeof(struct SD_PDMA_DESC_S));
-
- CurDes_S += 255;
-
- for (i = 255; i >=0 ;i--) {
- /* Set end bit of all descriptor and let PDMA finish as soon as possible */
- CurDes_S->end = 1;
- DBG("[%s] %d CurDes 0x%x, 0x%x, e=%x\n", __func__, i, CurDes_S, *CurDes_S);
- CurDes_S -= 1;
- }
- DBG("[%s] e\n", __func__);
-}
-
-/**********************************************************************
-Name : atsmb_prep_cmd
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static inline void atsmb_prep_cmd(struct atsmb_host *host,
- u32 opcode,
- u32 arg,
- unsigned int flags,
- u16 blk_len,
- u16 blk_cnt,
- unsigned char int_maks_0,
- unsigned char int_mask_1,
- unsigned char cmd_type,
- unsigned char op)
-{
- DBG("[%s] s\n",__func__);
- DBG("[%s] s opcode = %u arg = 0x%x flags = 0x%x\n",__func__,opcode,arg,flags);
- /*set cmd operation code and arguments.*/
- host->opcode = opcode;
- *ATSMB0_CMD_IDX = opcode; /* host->opcode is set for further use in ISR.*/
- *ATSMB0_CMD_ARG = arg;
-
-#if 0 /* Fixme to support SPI mode, James Tian*/
- if ((flags && MMC_RSP_NONE) == MMC_RSP_NONE)
- *ATSMB0_RSP_TYPE = ATMSB_TYPE_R0;
- else if ((flags && MMC_RSP_R1) == MMC_RSP_R1)
- *ATSMB0_RSP_TYPE = ATMSB_TYPE_R1;
- else if ((flags && MMC_RSP_R1B) == MMC_RSP_R1B)
- *ATSMB0_RSP_TYPE = ATMSB_TYPE_R1b;
- else if ((flags && MMC_RSP_R2) == MMC_RSP_R2)
- *ATSMB0_RSP_TYPE = ATMSB_TYPE_R2;
- else if ((flags && MMC_RSP_R3) == MMC_RSP_R3)
- *ATSMB0_RSP_TYPE = ATMSB_TYPE_R3;
- else if ((flags && MMC_RSP_R6) == MMC_RSP_R6)
- *ATSMB0_RSP_TYPE = ((opcode != SD_SEND_IF_COND) ? ATMSB_TYPE_R6 : ATMSB_TYPE_R7);
- else
- *ATSMB0_RSP_TYPE = ATMSB_TYPE_R0;
-#endif
-
-#if 1
- /*set cmd response type*/
- switch (flags) {
- case MMC_RSP_NONE | MMC_CMD_AC:
- case MMC_RSP_NONE | MMC_CMD_BC:
- *ATSMB0_RSP_TYPE = ATMSB_TYPE_R0;
- break;
- case MMC_RSP_R1 | MMC_CMD_ADTC:
- case MMC_RSP_R1 | MMC_CMD_AC:
- *ATSMB0_RSP_TYPE = ATMSB_TYPE_R1;
- break;
- case MMC_RSP_R1B | MMC_CMD_AC:
- *ATSMB0_RSP_TYPE = ATMSB_TYPE_R1b;
- break;
- case MMC_RSP_R2 | MMC_CMD_BCR:
- case MMC_RSP_R2 | MMC_CMD_AC:
- *ATSMB0_RSP_TYPE = ATMSB_TYPE_R2;
- break;
- case MMC_RSP_R3 | MMC_CMD_BCR:
- *ATSMB0_RSP_TYPE = ATMSB_TYPE_R3;
- break;
- case MMC_RSP_R6 | MMC_CMD_BCR: /*MMC_RSP_R6 = MMC_RSP_R7.*/
- *ATSMB0_RSP_TYPE = ((opcode != SD_SEND_IF_COND) ?
- ATMSB_TYPE_R6 : ATMSB_TYPE_R7);
- break;
- case MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC:
- case MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC:
- *ATSMB0_RSP_TYPE = ATMSB_TYPE_R5;
- break;
- case MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR:
- *ATSMB0_RSP_TYPE = ATMSB_TYPE_R4;
- break;
- default:
- *ATSMB0_RSP_TYPE = ATMSB_TYPE_R0;
- break;
- }
-#endif
- /*SDIO cmd 52 , 53*/
- if ((opcode == SD_IO_RW_DIRECT) ||
- (opcode == SD_IO_RW_EXTENDED)) {
- *ATSMB0_RSP_TYPE = ATMSB_TYPE_R5;
- *ATSMB0_RSP_TYPE |= BIT6;
- }
- /*SDIO cmd 5*/
- if ((opcode == SD_IO_SEND_OP_COND) &&
- ((flags & (MMC_RSP_PRESENT|
- MMC_RSP_136|
- MMC_RSP_CRC|
- MMC_RSP_BUSY|
- MMC_RSP_OPCODE)) == MMC_RSP_R4)) {
- *ATSMB0_RSP_TYPE = ATMSB_TYPE_R4;
- *ATSMB0_RSP_TYPE |= BIT6;
- }
-
- /*reset Response FIFO*/
- *ATSMB0_CTL |= 0x08;
-
- /* SD Host enable Clock */
- *ATSMB0_BUS_MODE |= ATSMB_CST;
-
- /*Set Cmd-Rsp Timeout to be maximum value.*/
- *ATSMB0_RSP_TOUT = 0xFE;
-
- /*clear all status registers for safety*/
- *ATSMB0_SD_STS_0 |= 0xff;
- *ATSMB0_SD_STS_1 |= 0xff;
- *ATSMB0_SD_STS_2 |= 0xff;
- //*ATSMB0_SD_STS_2 |= 0x7f;
- *ATSMB0_SD_STS_3 |= 0xff;
-
- //set block length and block count for cmd requesting data
- *ATSMB0_BLK_LEN &=~(0x0fff);
- *ATSMB0_BLK_LEN |= blk_len;
- //*ATSMB0_SHDW_BLKLEN = blk_len;
- *ATSMB0_BLK_CNT = blk_cnt;
-
-
- *ATSMB0_INT_MASK_0 |= int_maks_0;
- *ATSMB0_INT_MASK_1 |= int_mask_1;
-
- //Set Auto stop for Multi-block access
- if(cmd_type == 3 || cmd_type == 4) {
- //auto stop command set.
- *ATSMB0_EXT_CTL |= 0x01;
-
-/*
- * Enable transaction abort.
- * When CRC error occurs, CMD 12 would be automatically issued.
- * That is why we cannot enable R/W CRC error INTs.
- * If we enable CRC error INT, we would handle this INT in ISR and then issue CMD 12 via software.
- */
-/* Don't auto issue stop command when write command error,
-* because auto stop command can freezs PDMA. msut let PDMA transfer done.
-* 2013/05/15 by Eason
-*/
- if (cmd_type == 4)
- *ATSMB0_BLK_LEN |= 0x0800;
- }
-
- /*Set read or write*/
- if (op == 1)
- *ATSMB0_CTL &= ~(0x04);
- else if (op == 2)
- *ATSMB0_CTL |= 0x04;
-
- /*for Non data access command, command type is 0.*/
- *ATSMB0_CTL &= 0x0F;
- *ATSMB0_CTL |= (cmd_type<<4);
- DBG("[%s] e\n",__func__);
-}
-
-static inline void atsmb_issue_cmd(void)
-{
- *ATSMB0_CTL |= ATSMB_START;
- wmb();
-}
-/**********************************************************************
-Name : atsmb_request_end
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static void
-atsmb_request_end(struct atsmb_host *host, struct mmc_request *mrq)
-{
- DBG("[%s] s\n",__func__);
- /*
- * Need to drop the host lock here; mmc_request_done may call
- * back into the driver...
- */
- //kevin delete spin lock
- //spin_unlock(&host->lock);
- /*DBG("100");*/
- mmc_request_done(host->mmc, mrq);
- /*DBG("101\n");*/
- //kevin delete spin lock
- //spin_lock(&host->lock);
- DBG("[%s] e\n",__func__);
-}
-
-/**********************************************************************
-Name : atsmb_data_done
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-void atsmb_wait_done(void *data)
-{
- struct atsmb_host *host = (struct atsmb_host *) data;
- DBG("[%s] s\n",__func__);
-
- WARN_ON(host->done_data == NULL);
- complete(host->done_data);
- host->done_data = NULL;
- host->done = NULL;
- DBG("[%s] e\n",__func__);
-}
-
-/**********************************************************************
-Name : atsmb_start_data
-Function : If we start data, there must be only four cases.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static void atsmb_start_data(struct atsmb_host *host)
-{
- DECLARE_COMPLETION(complete);
- unsigned char cmd_type = 0;
- unsigned char op = 0; /*0: non-operation; 1:read; 2: write*/
- unsigned char mask_0 = 0;
- unsigned char mask_1 = 0;
- unsigned long dma_mask = 0;
-
- struct mmc_data *data = host->data;
- struct mmc_command *cmd = host->cmd;
-
- struct scatterlist *sg = NULL;
- unsigned int sg_len = 0;
-
- unsigned int total_blks = 0; /*total block number to transfer*/
- u32 card_addr = 0;
- unsigned long dma_len = 0;
- unsigned long total_dma_len = 0;
- dma_addr_t dma_phy = 0; /* physical address used for DMA*/
- unsigned int dma_times = 0; /*times dma need to transfer*/
- unsigned int dma_loop = 0;
- unsigned int sg_num = 0;
- int loop_cnt = 10000;
- unsigned int sg_transfer_len = 0; /*record each time dma transfer sg length */
-
- DBG("[%s] s\n",__func__);
- data->bytes_xfered = 0;
- cmd->error = 0;
- data->error = 0;
-
- /*for loop*/
- sg = data->sg;
- sg_len = data->sg_len;
-
- dma_times = (sg_len / MAX_DESC_NUM);
- if (sg_len % MAX_DESC_NUM)
- dma_times++;
- DBG("dma_times = %d sg_len = %d sg = %x\n", dma_times, sg_len, sg);
- card_addr = cmd->arg; /*may be it is block-addressed, or byte-addressed.*/
- total_blks = data->blocks;
- dma_map_sg(&(host->mmc->class_dev), sg, sg_len,
- ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-
-
- for (dma_loop = 1 ; dma_loop <= dma_times; dma_loop++, sg_len -= sg_transfer_len) {
- DBG("dma_loop = %d sg_len = %d sg_transfer_len = %d\n", dma_loop, sg_len, sg_transfer_len);
- if (dma_loop < dma_times)
- sg_transfer_len = MAX_DESC_NUM;
- else
- sg_transfer_len = sg_len;
- DBG("sg_transfer_len = %d\n", sg_transfer_len);
- /*
- *Firstly, check and wait till card is in the transfer state.
- *For our hardware, we can not consider
- *the card has successfully tranfered its state from data/rcv to trans,
- *when auto stop INT occurs.
- */
- loop_cnt = 10000;
- do {
- if (host->cmd->opcode == SD_IO_RW_EXTENDED)
- break;
- loop_cnt--;
- WARN_ON(loop_cnt == 0);
- host->done_data = &complete;
- host->done = &atsmb_wait_done;
- host->soft_timeout = 1;
- atsmb_prep_cmd(host,
- MMC_SEND_STATUS,
- (host->mmc->card->rca)<<16,
- MMC_RSP_R1 | MMC_CMD_AC,
- 0,
- 0,
- 0, /*mask_0*/
- ATSMB_RSP_DONE_EN
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN,
- 0, /*cmd type*/
- 0); /*read or write*/
- atsmb_issue_cmd();
- DBG("%16s = 0x%8x |", "INT_MASK_1", *ATSMB0_INT_MASK_1);
- DBG("%16s = 0x%8x \n", "SD_STS_1", *ATSMB0_SD_STS_1);
- /*ISR would completes it.*/
- wait_for_completion_timeout(&complete, ATSMB_TIMEOUT_TIME);
-
- WARN_ON(host->soft_timeout == 1);
- if (host->soft_timeout == 1) {
- DBG("%s soft_timeout.\n", __func__);
- atsmb_dump_reg();
- }
- if (cmd->error != MMC_ERR_NONE) {
- cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("Getting Status failed.\n");
- goto end;
- }
- } while ((cmd->resp[0] & 0x1f00) != 0x900 && loop_cnt > 0); /*wait for trans state.*/
-
- /*
- * Now, we can safely issue read/write command.
- * We can not consider this request as multi-block acess or single one via opcode,
- * as request is splitted into sgs.
- * Some sgs may be single one, some sgs may be multi one.
- */
-
- dma_phy = sg_dma_address(sg);
- dma_len = sg_dma_len(sg);
- DBG("dma_len = %d data->blksz = %d sg_len = %d\n", dma_len, data->blksz, sg_len);
- /*SDIO read/write*/
- if (host->cmd->opcode == SD_IO_RW_EXTENDED) {
- /*Single Block read/write*/
- if ((dma_len / (data->blksz)) == 1 && (sg_len == 1)) {
- /* read operation*/
- if (data->flags & MMC_DATA_READ) {
- host->opcode = SD_IO_RW_EXTENDED;
- cmd_type = 2;
- op = 1;
- mask_0 = 0; /*BLOCK_XFER_DONE INT skipped, we use DMA TC INT*/
- mask_1 = (//ATSMB_SDIO_EN
- ATSMB_READ_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = SD_PDMA_CCR_Evt_success;
- DBG("[%s]SR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
- __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
- } else {
- /* write operation*/
- host->opcode = SD_IO_RW_EXTENDED;
- cmd_type = 1;
- op = 2;
- /*====That is what we want===== DMA TC INT skipped*/
- mask_0 = ATSMB_BLOCK_XFER_DONE_EN;
- mask_1 = (//ATSMB_SDIO_EN
- ATSMB_WRITE_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = 0;
- DBG("[%s]SW opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
- __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
- }
- } else {
- /*Multiple Block read/write*/
- /* read operation*/
- if (data->flags & MMC_DATA_READ) {
- host->opcode = SD_IO_RW_EXTENDED;
- cmd_type = 6;
- op = 1;
- mask_0 = 0; /*MULTI_XFER_DONE_EN skipped*/
- mask_1 = (//ATSMB_SDIO_EN /*====That is what we want=====*/
- ATSMB_READ_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = SD_PDMA_CCR_Evt_success;
- DBG("[%s]MR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
- __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
- } else {
- /* write operation*/
- host->opcode = SD_IO_RW_EXTENDED;
- cmd_type = 5;
- op = 2;
- mask_0 = ATSMB_MULTI_XFER_DONE_EN;//ATSMB_BLOCK_XFER_DONE_EN; /*MULTI_XFER_DONE INT skipped*/
- mask_1 = (//ATSMB_SDIO_EN /*====That is what we want=====*/
- ATSMB_WRITE_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = 0;
- DBG("[%s]MR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
- __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
- }
- }
-
- } else {
- if ((dma_len / (data->blksz)) == 1 && (sg_len == 1)) {
- if (data->flags & MMC_DATA_READ) {/* read operation*/
- host->opcode = MMC_READ_SINGLE_BLOCK;
- cmd_type = 2;
- op = 1;
- mask_0 = 0; /*BLOCK_XFER_DONE INT skipped, we use DMA TC INT*/
- mask_1 = (ATSMB_READ_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = SD_PDMA_CCR_Evt_success;
- } else {/*write operation*/
- host->opcode = MMC_WRITE_BLOCK;
- cmd_type = 1;
- op = 2;
- /*====That is what we want===== DMA TC INT skipped*/
- mask_0 = ATSMB_BLOCK_XFER_DONE_EN;
- mask_1 = (ATSMB_WRITE_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = 0;
- }
- } else { /*more than one*/
- if (data->flags&MMC_DATA_READ) {/* read operation*/
- host->opcode = MMC_READ_MULTIPLE_BLOCK;
- cmd_type = 4;
- op = 1;
- mask_0 = 0; /*MULTI_XFER_DONE_EN skipped*/
- mask_1 = (ATSMB_AUTO_STOP_EN /*====That is what we want=====*/
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = 0;
- } else {/*write operation*/
- host->opcode = MMC_WRITE_MULTIPLE_BLOCK;
- cmd_type = 3;
- op = 2;
- mask_0 = 0; /*MULTI_XFER_DONE INT skipped*/
- mask_1 = (ATSMB_AUTO_STOP_EN /*====That is what we want=====*/
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = 0;
- }
- }
- }
- /*To controller every sg done*/
- host->done_data = &complete;
- host->done = &atsmb_wait_done;
- /*sleep till ISR wakes us*/
- host->soft_timeout = 1; /*If INT comes early than software timer, it would be cleared.*/
-
- total_dma_len = 0;
- DBG("host->DescVirAddr = %x host->DescSize=%x\n", host->DescVirAddr, host->DescSize);
- memset(host->DescVirAddr, 0, host->DescSize);
- for (sg_num = 0 ; sg_num < sg_transfer_len ; sg++, sg_num++) {
-
- /*
- * Now, we can safely issue read/write command.
- * We can not consider this request as multi-block acess or single one via opcode,
- * as request is splitted into sgs.
- * Some sgs may be single one, some sgs may be multi one.
- */
-
- dma_phy = sg_dma_address(sg);
- dma_len = sg_dma_len(sg);
- total_dma_len = total_dma_len + dma_len;
- DBG("sg_num=%d sg_transfer_len=%d sg=%x sg_len=%d total_dma_len=%d dma_len=%d\n",
- sg_num, sg_transfer_len, sg, sg_len, total_dma_len, dma_len);
- /*2009/01/15 janshiue add*/
- if (sg_num < sg_transfer_len - 1) {
- /* means the last descporitor */
- atsmb_init_short_desc(
- host->DescVirAddr + (sg_num * sizeof(struct SD_PDMA_DESC_S)/4),
- dma_len, (unsigned long *)dma_phy, 0);
- } else {
- atsmb_init_short_desc(
- host->DescVirAddr + (sg_num * sizeof(struct SD_PDMA_DESC_S)/4),
- dma_len, (unsigned long *)dma_phy, 1);
- }
- /*2009/01/15 janshiue add*/
-
- }
- /*operate our hardware*/
- atsmb_prep_cmd(host,
- host->opcode,
- /*arg, may be byte addressed, may be block addressed.*/
- card_addr,
- cmd->flags,
- data->blksz - 1, /* in fact, it is useless.*/
- /* for single one, it is useless. but for multi one, */
- /* it would be used to tell auto stop function whether it is done.*/
- total_dma_len/(data->blksz),
- mask_0,
- mask_1,
- cmd_type,
- op);
-
- atsmb_config_dma((op == 1) ? DMA_CFG_READ : DMA_CFG_WRITE,
- dma_mask,
- host);
-
- atsmb_issue_cmd();
- wait_for_completion_timeout(&complete,
- ATSMB_TIMEOUT_TIME*sg_transfer_len); /*ISR would completes it.*/
-
- /* When the address of request plus length equal card bound,
- * force this stop command response as pass. Eason 2012/4/20 */
- if (cmd->resp[0] == 0x80000b00) {
- /*This caes used for SD2.0 and after MMC4.1 version*/
- if (card_addr+(total_dma_len/data->blksz) == host->mmc->card->csd.capacity) {
- cmd->resp[0] = 0x00000b00;
- /*printk("card_addr = %08X, card_length = %08X,card capacity = %08X\n",
- card_addr,(total_dma_len/data->blksz),host->mmc->card->csd.capacity);
- printk("card_resp[0]=%08X, addr = %08X\n",cmd->resp[0],cmd->resp);*/
- }
-
- /* This caes used for SD1.0 and before MMC 4.1 */
- if ((card_addr/data->blksz)+(total_dma_len/data->blksz) == host->mmc->card->csd.capacity) {
- cmd->resp[0] = 0x00000b00;
- /*printk("Eason test: cmd->arg = %08X, data->blksz = %08X, length = %08X\n",
- card_addr,data->blksz,(total_dma_len/data->blksz));*/
- }
- }
-
- if (host->soft_timeout == 1) {
- atsmb_dump_reg();
- //*ATSMB0_BUS_MODE |= ATSMB_SFTRST;
- *ATSMB0_PDMA_GCR = SD_PDMA_GCR_SOFTRESET;
- /*disable INT */
- *ATSMB0_INT_MASK_0 &= ~(ATSMB_BLOCK_XFER_DONE_EN | ATSMB_MULTI_XFER_DONE_EN);
- *ATSMB0_INT_MASK_1 &= ~(ATSMB_WRITE_CRC_ERR_EN|ATSMB_READ_CRC_ERR_EN|ATSMB_RSP_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN|ATSMB_AUTO_STOP_EN|ATSMB_RSP_TIMEOUT_EN|ATSMB_RSP_DONE_EN);
-
- cmd->error = -ETIMEDOUT;
- data->error = -ETIMEDOUT;
- }
-
- WARN_ON(host->soft_timeout == 1);
-
- /*check everything goes okay or not*/
- if (cmd->error != MMC_ERR_NONE
- || data->error != MMC_ERR_NONE) {
- DBG("CMD or Data failed error=%X DescVirAddr=%8X dma_phy=%8X dma_mask = %x\n",
- cmd->error, host->DescVirAddr, dma_phy, host->DmaIntMask);
- goto end;
- }
-// card_addr += total_dma_len>>(mmc_card_blockaddr(host->mmc->card_selected) ? 9 : 0);
- card_addr += total_dma_len>>(mmc_card_blockaddr(host->mmc->card) ? 9 : 0); //zhf: modified by James Tian
- data->bytes_xfered += total_dma_len;
-
-
- }
-// dma_unmap_sg(&(host->mmc->class_dev), data->sg, data->sg_len,
-// ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-
- WARN_ON(total_blks != (data->bytes_xfered / data->blksz));
- host->opcode = 0;
-end:
- dma_unmap_sg(&(host->mmc->class_dev), data->sg, data->sg_len,
- ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
- spin_lock(&host->lock);
- atsmb_request_end(host, host->mrq);
- spin_unlock(&host->lock);
- DBG("[%s] e\n",__func__);
-}
-
-
-/**********************************************************************
-Name : atsmb_cmd_with_data_back
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static void atsmb_cmd_with_data_back(struct atsmb_host *host)
-{
- DECLARE_COMPLETION(complete);
-
- struct scatterlist *sg = NULL;
- unsigned int sg_len = 0;
- DBG("[%s] s\n",__func__);
- /*for loop*/
- sg = host->data->sg;
- sg_len = host->data->sg_len;
- /*To controller every sg done*/
- host->done_data = &complete;
- host->done = &atsmb_wait_done;
- dma_map_sg(&(host->mmc->class_dev), sg, sg_len, DMA_FROM_DEVICE);
-
- /*2009/01/15 janshiue add*/
- memset(host->DescVirAddr, 0, host->DescSize);
- atsmb_init_long_desc(host->DescVirAddr, sg_dma_len(sg), (unsigned long *)sg_dma_address(sg), 0, 1);
- /*2009/01/15 janshiue add*/
- /*prepare for cmd*/
- atsmb_prep_cmd(host, /*host*/
- host->cmd->opcode, /*opcode*/
- host->cmd->arg, /*arg*/
- host->cmd->flags, /*flags*/
- sg_dma_len(sg)-1, /*block length*/
- 0, /*block size: It looks like useless*/
- 0, /*int_mask_0*/
- (ATSMB_RSP_CRC_ERR_EN|ATSMB_RSP_TIMEOUT_EN
- |ATSMB_READ_CRC_ERR_EN |ATSMB_DATA_TIMEOUT_EN), /*int_mask_1*/
- 2, /*cmd_type*/
- 1); /*op*/
-
- atsmb_config_dma(DMA_CFG_READ,
- SD_PDMA_CCR_Evt_success,
- host);
- atsmb_issue_cmd();
- /*ISR would completes it.*/
- wait_for_completion_timeout(&complete, ATSMB_TIMEOUT_TIME);
-
- dma_unmap_sg(&(host->mmc->class_dev), host->data->sg, host->data->sg_len,
- ((host->data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
- spin_lock(&host->lock);
- atsmb_request_end(host, host->mrq);
- spin_unlock(&host->lock);
- DBG("[%s] e\n",__func__);
-}
-/**********************************************************************
-Name : atsmb_start_cmd
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static void atsmb_start_cmd(struct atsmb_host *host)
-{
- unsigned char int_mask_0,int_mask_1;
- int_mask_0 = 0;
- int_mask_1 = ATSMB_RSP_DONE_EN|ATSMB_RSP_CRC_ERR_EN|ATSMB_RSP_TIMEOUT_EN;
-
- DBG("[%s] s\n",__func__);
-
- atsmb_prep_cmd(host,
- host->cmd->opcode,
- host->cmd->arg,
- host->cmd->flags,
- 0, /*useless*/
- 0, /*useless*/
- int_mask_0, /*mask_0*/
- int_mask_1, /*mask_1*/
- 0, /*cmd type*/
- 0); /*read or write*/
- atsmb_issue_cmd();
- DBG("[%s] e\n",__func__);
-}
-/**********************************************************************
-Name : atsmb_fmt_check_rsp
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static inline void atsmb_fmt_check_rsp(struct atsmb_host *host)
-{
-
- u8 tmp_resp[4] = {0};
- int i, j, k;
- DBG("[%s] s\n",__func__);
- if (host->cmd->flags != (MMC_RSP_R2 | MMC_CMD_AC)
- && host->cmd->flags != (MMC_RSP_R2 | MMC_CMD_BCR)) {
- for (j = 0, k = 1; j < 4; j++, k++)
- tmp_resp[j] = *(REG8_PTR(_RSP_0 + MMC_ATSMB0_BASE+k));
-
- host->cmd->resp[0] = (tmp_resp[0] << 24) |
- (tmp_resp[1]<<16) | (tmp_resp[2]<<8) | (tmp_resp[3]);
- } else {
- for (i = 0, k = 1; i < 4; i++) { /*R2 has 4 u32 response.*/
- for (j = 0; j < 4; j++) {
- if (k < 16)
- tmp_resp[j] = *(REG8_PTR(_RSP_0 + MMC_ATSMB0_BASE+k));
- else /* k =16*/
- tmp_resp[j] = *(ATSMB0_RSP_0);
- k++;
- }
- host->cmd->resp[i] = (tmp_resp[0]<<24) | (tmp_resp[1]<<16) |
- (tmp_resp[2]<<8) | (tmp_resp[3]);
- }
- }
-
- /*
- * For the situation that we need response,
- * but response registers give us all zeros, we consider this operation timeout.
- */
- if (host->cmd->flags != (MMC_RSP_NONE | MMC_CMD_AC)
- && host->cmd->flags != (MMC_RSP_NONE | MMC_CMD_BC)) {
- if (host->cmd->resp[0] == 0 && host->cmd->resp[1] == 0
- && host->cmd->resp[2] == 0 && host->cmd->resp[3] == 0) {
- host->cmd->error = -ETIMEDOUT; //zhf: modified by James Tian
- }
- }
- DBG("[%s] e\n",__func__);
-}
-/**********************************************************************
-Name : atsmb_get_slot_status
-Function : Our host only supports one slot.
-Calls :
-Called by :
-Parameter :
-returns : 1: in slot; 0: not in slot.
-Author : Leo Lee
-History :
-***********************************************************************/
-static int atsmb_get_slot_status(struct mmc_host *mmc)
-{
-// struct atsmb_host *host = mmc_priv(mmc);
- unsigned char status_0 = 0;
-// unsigned long flags;
- unsigned long ret = 0;
- DBG("[%s] s\n",__func__);
-// spin_lock_irqsave(&host->lock, flags); // Vincent Li mark out for CONFIG_PREEMPT_RT
- status_0 = *ATSMB0_SD_STS_0;
-// spin_unlock_irqrestore(&host->lock, flags); // Vincent Li mark out for CONFIG_PREEMPT_RT
- /* after WM3400 A1 ATSMB_CARD_IN_SLOT_GPI = 1 means not in slot*/
- if (MMC0_DRIVER_VERSION >= MMC_DRV_3426_A0) {
- if(SD0_detect_pol)
- ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 1 : 0);
- else
- ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 0 : 1);
-
- DBG("[%s] e1\n",__func__);
- return ret;
- } else {
- ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 1 : 0);
- DBG("[%s] e2\n",__func__);
- return ret;
- }
- DBG("[%s] e3\n",__func__);
- return 0;
-}
-
-/**********************************************************************
-Name : atsmb_init_short_desc
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Janshiue Wu
-History :
-***********************************************************************/
-int atsmb_init_short_desc(unsigned long *DescAddr, unsigned int ReqCount, unsigned long *BufferAddr, int End)
-{
- struct SD_PDMA_DESC_S *CurDes_S;
- DBG("[%s] s\n",__func__);
- CurDes_S = (struct SD_PDMA_DESC_S *) DescAddr;
- CurDes_S->ReqCount = ReqCount;
- CurDes_S->i = 0;
- CurDes_S->format = 0;
- CurDes_S->DataBufferAddr = BufferAddr;
- if (End) {
- CurDes_S->end = 1;
- CurDes_S->i = 1;
- }
- DBG("[%s] e\n",__func__);
- return 0;
-}
-
-/**********************************************************************
-Name : atsmb_init_long_desc
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Janshiue Wu
-History :
-***********************************************************************/
-int atsmb_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount,
- unsigned long *BufferAddr, unsigned long *BranchAddr, int End)
-{
- struct SD_PDMA_DESC_L *CurDes_L;
- DBG("[%s] s\n",__func__);
- CurDes_L = (struct SD_PDMA_DESC_L *) DescAddr;
- CurDes_L->ReqCount = ReqCount;
- CurDes_L->i = 0;
- CurDes_L->format = 1;
- CurDes_L->DataBufferAddr = BufferAddr;
- CurDes_L->BranchAddr = BranchAddr;
- if (End) {
- CurDes_L->end = 1;
- CurDes_L->i = 1;
- }
- DBG("[%s] e\n",__func__);
- return 0;
-}
-
-/**********************************************************************
-Name : atsmb_dma_isr
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static irqreturn_t atsmb_dma_isr(int irq, void *dev_id)
-{
-
- struct atsmb_host *host = dev_id;
- u8 status_0, status_1, status_2, status_3;
- u32 pdma_event_code = 0;
- DBG("[%s] s\n",__func__);
-
- disable_irq_nosync(irq);
- spin_lock(&host->lock);
- /*Get INT status*/
- status_0 = *ATSMB0_SD_STS_0;
- status_1 = *ATSMB0_SD_STS_1;
- status_2 = *ATSMB0_SD_STS_2;
- status_3 = *ATSMB0_SD_STS_3;
- /* after WM3426 A0 using PDMA */
- if (MMC0_DRIVER_VERSION >= MMC_DRV_3426_A0) {
-
- pdma_event_code = *ATSMB0_PDMA_CCR & SD_PDMA_CCR_EvtCode;
-
- /* clear INT status to notify HW clear EventCode*/
- *ATSMB0_PDMA_ISR |= SD_PDMA_IER_INT_STS;
-
- /*printk("dma_isr event code = %X\n", *ATSMB0_PDMA_CCR);*/
- /*We expect cmd with data sending back or read single block cmd run here.*/
- if (pdma_event_code == SD_PDMA_CCR_Evt_success) {
- /*means need to update the data->error and cmd->error*/
- if (host->DmaIntMask == SD_PDMA_CCR_Evt_success) {
- if (host->data != NULL) {
- host->data->error = MMC_ERR_NONE;
- host->cmd->error = MMC_ERR_NONE;
- } else {
- DBG("dma_isr host->data is NULL\n");
- /*disable INT*/
- *ATSMB0_PDMA_IER &= ~SD_PDMA_IER_INT_EN;
- goto out;
- }
- }
- /*else do nothing*/
- DBG("dma_isr PDMA OK\n");
- /*atsmb_dump_reg();*/
- }
- /*But unluckily, we should also be prepare for all kinds of error situation.*/
- else {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("** dma_isr PDMA fail** event code = %X\n", *ATSMB0_PDMA_CCR);
- atsmb_dump_reg();
- }
-
- if (host->DmaIntMask == SD_PDMA_CCR_Evt_success)
- atsmb_fmt_check_rsp(host);
-
- /*disable INT*/
- *ATSMB0_PDMA_IER &= ~SD_PDMA_IER_INT_EN;
- }
-
- /*wake up some one who is sleeping.*/
- if ((pdma_event_code != SD_PDMA_CCR_Evt_success) || (host->DmaIntMask == SD_PDMA_CCR_Evt_success)) {
- if (host->done_data) {/* We only use done_data when requesting data.*/
- host->soft_timeout = 0;
- host->done(host);
- } else
- atsmb_request_end(host, host->mrq); /*for cmd with data sending back.*/
- }
-
-out:
- spin_unlock(&host->lock);
- enable_irq(irq);
- DBG("[%s] e\n",__func__);
- return IRQ_HANDLED;
-}
-
-/**********************************************************************
-Name : atsmb_regular_isr
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-//static irqreturn_t atsmb_regular_isr(int irq, void *dev_id, struct pt_regs *regs)
-irqreturn_t atsmb_regular_isr(int irq, void *dev_id)
-{
-
- struct atsmb_host *host = dev_id;
- u8 status_0, status_1, status_2, status_3,mask_0,mask_1;
- u32 pdma_sts;
-
- DBG("[%s] s\n",__func__);
- WARN_ON(host == NULL);
-
- disable_irq_nosync(irq);
- spin_lock(&host->lock);
-
- /*Get INT status*/
- status_0 = *ATSMB0_SD_STS_0;
- status_1 = *ATSMB0_SD_STS_1;
- status_2 = *ATSMB0_SD_STS_2;
- status_3 = *ATSMB0_SD_STS_3;
-
- mask_0 = *ATSMB0_INT_MASK_0;
- mask_1 = *ATSMB0_INT_MASK_1;
- /*******************************************************
- card insert interrupt
- ********************************************************/
- if ((status_0 & ATSMB_DEVICE_INSERT) /*Status Set and IRQ enabled*/
- /*To aviod the situation that we intentionally disable IRQ to do rescan.*/
- && (*ATSMB0_INT_MASK_0 & 0x80)) {
-
- if (host->mmc->ops->get_slot_status(host->mmc)) {
- host->mmc->scan_retry = 3;
- host->mmc->card_scan_status = false;
- } else {
- host->mmc->scan_retry = 0;
- host->mmc->card_scan_status = false;
- }
-
- mmc_detect_change(host->mmc, HZ/2);
- /*Taipei Side Request: Disable INSERT IRQ when doing rescan.*/
- //*ATSMB0_INT_MASK_0 &= (~0x80);/* or 40?*/ //zhf: marked by James Tian
- /*Then we clear the INT status*/
- //iowrite32(ATSMB_DEVICE_INSERT, host->base+_SD_STS_0);
- *ATSMB0_SD_STS_0 |= ATSMB_DEVICE_INSERT;
- spin_unlock(&host->lock);
- enable_irq(irq);
- DBG("[%s] e1\n",__func__);
- return IRQ_HANDLED;
- }
-
- if ((status_1 & mask_1)& ATSMB_SDIO_INT) {
- spin_unlock(&host->lock);
- mmc_signal_sdio_irq(host->mmc);
-
- if (((status_1 & mask_1) == ATSMB_SDIO_INT) && ((status_0 & mask_0) == 0)) {
-
- enable_irq(irq);
- DBG("[%s] e2\n",__func__);
-
- return IRQ_HANDLED;
- }
- spin_lock(&host->lock);
- }
- pdma_sts = *ATSMB0_PDMA_CCR;
-
- if (((status_0 & mask_0) | (status_1 & mask_1)) == 0) {
- spin_unlock(&host->lock);
- enable_irq(irq);
- DBG("[%s] e3\n",__func__);
- return IRQ_HANDLED;
- }
- /*******************************************************
- command interrupt.
- *******************************************************/
- /*for write single block*/
- if (host->opcode == MMC_WRITE_BLOCK) {
- if ((status_0 & ATSMB_BLOCK_XFER_DONE)
- && (status_1 & ATSMB_RSP_DONE)) {
- host->data->error = MMC_ERR_NONE;
- host->cmd->error = MMC_ERR_NONE;
- /* okay, what we want.*/
- } else {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err1\n",__func__);
- atsmb_dump_reg();
- }
- } else if (host->opcode == MMC_WRITE_MULTIPLE_BLOCK
- || host->opcode == MMC_READ_MULTIPLE_BLOCK) {
- if ((status_1 & (ATSMB_AUTO_STOP|ATSMB_RSP_DONE))
- && (status_0 & ATSMB_MULTI_XFER_DONE)) {
- /*If CRC error occurs, I think this INT would not occrs.*/
- /*okay, that is what we want.*/
- host->data->error = MMC_ERR_NONE;
- host->cmd->error = MMC_ERR_NONE;
- } else {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err2\n",__func__);
- atsmb_dump_reg();
-
- }
- } else if (host->opcode == MMC_READ_SINGLE_BLOCK) {/* we want DMA TC, run here, must be error.*/
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err3\n",__func__);
- atsmb_dump_reg();
- } else if (host->opcode == SD_IO_RW_EXTENDED){
- /*Write operation*/
- if (*ATSMB0_CTL & BIT2) {
- if ((*ATSMB0_CTL & 0xf0) == 0x10) { /*single block write*/
- if ((status_0 & ATSMB_BLOCK_XFER_DONE)
- && (status_1 & ATSMB_RSP_DONE)) {
- host->data->error = MMC_ERR_NONE;
- host->cmd->error = MMC_ERR_NONE;
- /* okay, what we want.*/
- } else {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err4 status_0 = %x status_1 = %x\n",__func__,status_0,status_1);
- }
-
- } else if ((*ATSMB0_CTL & 0xf0) == 0x50) {
- if ((status_0 & ATSMB_MULTI_XFER_DONE)
- && (status_1 & ATSMB_RSP_DONE)) {
- host->data->error = MMC_ERR_NONE;
- host->cmd->error = MMC_ERR_NONE;
- /* okay, what we want.*/
- } else {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err4-2 status_0 = %x status_1 = %x\n",__func__,status_0,status_1);
- }
- } else {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err4-3 status_0 = %x status_1 = %x\n",__func__,status_0,status_1);
- }
- }
- else {
- /*Read operation*/
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err5\n",__func__);
- }
-
-
- } else {
-/* command, not request data*/
-/* the command which need data sending back,*/
-/* like switch_function, send_ext_csd, send_scr, send_num_wr_blocks.*/
-/* NOTICE: we also send status before reading or writing data, so SEND_STATUS should be excluded.*/
- if (host->data && host->opcode != MMC_SEND_STATUS) {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err6\n",__func__);
- atsmb_dump_reg();
- } else { /* Just command, no need data sending back.*/
- if (status_1 & ATSMB_RSP_DONE) {
- /*Firstly, check data-response is busy or not.*/
- if (host->cmd->flags == (MMC_RSP_R1B | MMC_CMD_AC)) {
- int i = 10000;
-
- while (status_2 & ATSMB_RSP_BUSY) {
- status_2 = *ATSMB0_SD_STS_2;
- if (--i == 0)
- break;
- DBG(" IRQ:Status_2 = %d, busy!\n", status_2);
- }
- if (i == 0)
- printk("[MMC driver] Error :SD data-response always busy!");
- }
-#if 1
-/*for our host, even no card in slot, for SEND_STATUS also returns no error.*/
-/*The protocol layer depends on SEND_STATUS to check whether card is in slot or not.*/
-/*In fact, we can also avoid this situation by checking the response whether they are all zeros.*/
- if (!atsmb_get_slot_status(host->mmc) && host->opcode == MMC_SEND_STATUS) {
- host->cmd->retries = 0; /* No retry.*/
-// host->cmd->error = MMC_ERR_INVALID;
- host->cmd->error = -EINVAL;
- } else
-#endif
- host->cmd->error = MMC_ERR_NONE;
- } else {
- if (status_1 & ATSMB_RSP_TIMEOUT) {/* RSP_Timeout .*/
-// host->cmd->error = MMC_ERR_TIMEOUT;
- host->cmd->error = -ETIMEDOUT;
- DBG("[%s] err7\n",__func__);
- } else {/*or RSP CRC error*/
-// host->cmd->error = MMC_ERR_BADCRC;
- host->cmd->error = -EILSEQ;
- DBG("[%s] err8\n",__func__);
- }
- atsmb_dump_reg();
- }
- }
- }
- atsmb_fmt_check_rsp(host);
-
- /*disable INT */
- *ATSMB0_INT_MASK_0 &= ~(ATSMB_BLOCK_XFER_DONE_EN | ATSMB_MULTI_XFER_DONE_EN);
- *ATSMB0_INT_MASK_1 &= ~(ATSMB_WRITE_CRC_ERR_EN|ATSMB_READ_CRC_ERR_EN|ATSMB_RSP_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN|ATSMB_AUTO_STOP_EN|ATSMB_RSP_TIMEOUT_EN|ATSMB_RSP_DONE_EN);
-
-
- /*clear INT status. In fact, we will clear again before issuing new command.*/
- *ATSMB0_SD_STS_0 |= status_0;
- *ATSMB0_SD_STS_1 |= status_1;
-
- /* when read CRC error occur, and the status can't write one to clear.
- * To clear read CRC error status , can do software reset. This is HW bug. 2013/3/21*/
- if ((*ATSMB0_SD_STS_1 & BIT6) == 0x40) {
- DBG("[%s] host0 CMD%d Read CRC error occur\n",__func__,host->cmd->opcode);
- /* Save SD card register */
- atsmb_copy_reg(0);
- /* Software reset */
- *ATSMB0_BUS_MODE |= BIT7;
- /* restore SD card register */
- atsmb_copy_reg(1);
- }
-
- if (*ATSMB0_PDMA_ISR & SD_PDMA_IER_INT_STS)
- *ATSMB0_PDMA_ISR |= SD_PDMA_IER_INT_STS;
-
- /*wake up some one who is sleeping.*/
- if (host->done_data) { /* We only use done_data when requesting data.*/
- host->soft_timeout = 0;
- host->done(host);
- } else
- atsmb_request_end(host, host->mrq); /*for cmd without data.*/
-
- spin_unlock(&host->lock);
- enable_irq(irq);
- DBG("[%s] e4\n",__func__);
- return IRQ_HANDLED;
-}
-EXPORT_SYMBOL(atsmb_regular_isr);
-
-/**********************************************************************
-Name : atsmb_get_ro
-Function :.
-Calls :
-Called by :
-Parameter :
-returns : 0 : write protection is disabled. 1: write protection is enabled.
-Author : Leo Lee
-History :
-***********************************************************************/
-int atsmb_get_ro(struct mmc_host *mmc)
-{
- struct atsmb_host *host = mmc_priv(mmc);
- unsigned char status_0 = 0;
- unsigned long flags;
- unsigned long ret = 0;
- DBG("[%s] s\n",__func__);
- //add by kevin guan
- if(SD0_ro_disable)
- return 0;
- spin_lock_irqsave(&host->lock, flags);
- status_0 = *ATSMB0_SD_STS_0;
- spin_unlock_irqrestore(&host->lock, flags);
- DBG("[%s]\nstatus_0 = 0x%x\n", __func__,status_0);
- ret = ((status_0 & ATSMB_WRITE_PROTECT) ? 0 : 1);
- DBG("[%s] e\n",__func__);
- return ret;
-}
-/**********************************************************************
-Name : atsmb_dump_host_regs
-Function :
-Calls :
-Called by :
-Parameter :
-returns :
-Author : Leo Lee
-History :
-***********************************************************************/
-void atsmb_dump_host_regs(struct mmc_host *mmc)
-{
- DBG("[%s] s\n",__func__);
- atsmb_dump_reg();
- DBG("[%s] e\n",__func__);
-}
-EXPORT_SYMBOL(atsmb_dump_host_regs);
-
-/**********************************************************************
-Name : atsmb_enable_sdio_irq
-Function :
-Calls :
-Called by :
-Parameter :
-returns :
-Author : Tommy Huang
-History :
-***********************************************************************/
-static void atsmb_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
- struct atsmb_host *host = mmc_priv(mmc);
- unsigned long flags;
-
- DBG("[%s] s enable = %d *ATSMB0_INT_MASK_1 = %x\n",__func__,enable,*ATSMB0_INT_MASK_1);
- spin_lock_irqsave(&host->lock, flags);
-
- if (enable) {
- *ATSMB0_INT_MASK_1 |= ATSMB_SDIO_EN;
- } else {
- *ATSMB0_INT_MASK_1 &= ~ATSMB_SDIO_EN;
- }
-
- spin_unlock_irqrestore(&host->lock, flags);
- DBG("[%s] e\n",__func__);
-
-}
-/**********************************************************************
-Name : atsmb_request
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static void atsmb_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
-
- struct atsmb_host *host = mmc_priv(mmc);
- DBG("[%s] s\n",__func__);
-
- /* May retry process comes here.*/
- host->mrq = mrq;
- host->data = mrq->data;
- host->cmd = mrq->cmd;
- host->done_data = NULL;
- host->done = NULL;
-
- /*for data request*/
- if (host->data) {
- if (host->cmd->opcode == MMC_WRITE_BLOCK
- || host->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK
- || host->cmd->opcode == MMC_READ_SINGLE_BLOCK
- || host->cmd->opcode == MMC_READ_MULTIPLE_BLOCK
- || host->cmd->opcode == SD_IO_RW_EXTENDED) {
- atsmb_start_data(host);
- } else {
- atsmb_cmd_with_data_back(host);
- }
- } else {
- atsmb_start_cmd(host);
- }
- DBG("[%s] e\n",__func__);
-}
-/**********************************************************************
-Name : atsmb_set_clock
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Eason Chien
-History :2012/7/19
-***********************************************************************/
-static int atsmb_set_clock(struct mmc_host *mmc, unsigned int clock)
-{
- int clock_multiplier = 1;
- DBG("clock = %u\n",clock);
-
- if (*ATSMB0_EXT_BUS_MODE & BIT4) /*Enable DDR50*/
- clock_multiplier = 2;
-
- if(SD0_speed){
- if (clock == mmc->f_min) {
- DBG("[%s]ATSMB Host 390KHz\n", __func__);
- if ((*ATSMB0_CTL2 & BIT3) == 0) {
- DBG("[%s] 1.8V clock = %u\n",__func__,clock);
- DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
- }
- return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 1, 390);
- }
- else if (clock >= 208000000) {
- DBG("[%s]ATSMB Host 208MHz\n", __func__);
- if ((*ATSMB0_CTL2 & BIT3) == 0) {
- DBG("[%s] 1.8V clock = %u\n",__func__,clock);
-
- /*Set DPCTL 010 DNCTL 001*/
- SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19);
- SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18);
-
-
- DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
- DBG("[%s] *DPCTL = 0x%x DPCTL = 0x%x\n",
- __func__, SD0_DPCTL_4BYTE_ADDR, SD0_DPCTL_4BYTE_VAL);
- DBG("[%s] *DNCTL = 0x%x DNCTL = 0x%x\n",
- __func__, SD0_DNCTL_4BYTE_ADDR, SD0_DNCTL_4BYTE_VAL);
- }
- return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 80);
- } else if (clock >= 100000000) {
- DBG("[%s]ATSMB Host 100MHz\n", __func__);
- if ((*ATSMB0_CTL2 & BIT3) == 0) {
- DBG("[%s] 1.8V clock = %u\n",__func__,clock);
-
- /*Set DPCTL 010 DNCTL 001*/
- SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19);
- SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18);
-
- DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
- }
- return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 80);
- } else if (clock >= 50000000) {
- DBG("[%s]ATSMB Host 50MHz\n", __func__);
- if ((*ATSMB0_CTL2 & BIT3) == 0) {
- DBG("[%s] 1.8V clock = %u\n",__func__,clock);
-
- /*Set DPCTL 010 DNCTL 001*/
- SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19);
- SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18);
- DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
- }
- return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 45 * clock_multiplier);
- } else if ((clock >= 25000000) && (clock < 50000000)) {
- if ((*ATSMB0_CTL2 & BIT3) == 0) {
- DBG("[%s] 1.8V clock = %u\n",__func__,clock);
-
- /*Set DPCTL 010 DNCTL 001*/
- SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19);
- SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18);
- DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
- }
- DBG("[%s]ATSMB Host 25MHz\n", __func__);
- return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 24 * clock_multiplier);
- } else if ((clock >= 20000000) && (clock < 25000000)) {
- DBG("[%s]ATSMB Host 20MHz\n", __func__);
- if ((*ATSMB0_CTL2 & BIT3) == 0) {
- DBG("[%s] 1.8V clock = %u\n",__func__,clock);
-
- /*Set DPCTL 010 DNCTL 001*/
- SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19);
- SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18);
- DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
- }
- return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 20 * clock_multiplier);
- } else {
- DBG("[%s]ATSMB Host 390KHz\n", __func__);
- if ((*ATSMB0_CTL2 & BIT3) == 0) {
- DBG("[%s] 1.8V clock = %u\n",__func__,clock);
-
- /*Set DPCTL 010 DNCTL 001*/
- SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19);
- SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18);
- DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
- }
- return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 1, 390 * clock_multiplier);
- }
- }else{
- if (clock == mmc->f_min) {
- DBG("[%s]ATSMB Host 390KHz\n", __func__);
- if ((*ATSMB0_CTL2 & BIT3) == 0) {
- DBG("[%s] 1.8V clock = %u\n",__func__,clock);
- DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
- }
- return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 1, 390);
- }else if (clock >= 25000000) {
- if ((*ATSMB0_CTL2 & BIT3) == 0) {
- DBG("[%s] 1.8V clock = %u\n",__func__,clock);
-
- /*Set DPCTL 010 DNCTL 001*/
- SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19);
- SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18);
- DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
- }
- DBG("[%s]ATSMB Host 25MHz\n", __func__);
- return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 24 * clock_multiplier);
- } else if ((clock >= 20000000) && (clock < 25000000)) {
- DBG("[%s]ATSMB Host 20MHz\n", __func__);
- if ((*ATSMB0_CTL2 & BIT3) == 0) {
- DBG("[%s] 1.8V clock = %u\n",__func__,clock);
-
- /*Set DPCTL 010 DNCTL 001*/
- SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19);
- SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18);
- DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
- }
- return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 2, 20 * clock_multiplier);
- } else {
- DBG("[%s]ATSMB Host 390KHz\n", __func__);
- if ((*ATSMB0_CTL2 & BIT3) == 0) {
- DBG("[%s] 1.8V clock = %u\n",__func__,clock);
-
- /*Set DPCTL 010 DNCTL 001*/
- SD0_DPCTL_4BYTE_VAL = (BIT1 | BIT4 | BIT7 | BIT10 | BIT13 | BIT16 | BIT19);
- SD0_DNCTL_4BYTE_VAL = (BIT0 | BIT3 | BIT6 | BIT9 | BIT12 | BIT15 | BIT18);
- DBG("[%s] *ATSMB0_CTL2 = 0x%x \n", __func__, *ATSMB0_CTL2);
- }
- return auto_pll_divisor(DEV_SDMMC0, SET_DIV, 1, 390 * clock_multiplier);
- }
- }
-}
-
-static void atsmb_enable_power(struct atsmb_host *host, unsigned long flags)
-{
- int result;
- spin_unlock_irqrestore(&host->lock, flags);
- if (g_atsmb_regulator) {
- if (regulator_is_enabled(atsmb_regulator) == 0) {
- DBG("[%s] Turn on power\n", __FUNCTION__);
- result = regulator_enable(atsmb_regulator);
- if (result != 0)
- printk(KERN_ALERT "[%s] regulator_enable FAIL\n", __FUNCTION__);
- }
- } else {
- GPIO_OD_GP13_SD0_BYTE_VAL &= ~GPIO_SD0_POWER;
- }
- spin_lock_irqsave(&host->lock, flags);
-}
-
-static void atsmb_disable_power(struct atsmb_host *host, unsigned long flags)
-{
- int result;
- spin_unlock_irqrestore(&host->lock, flags);
- if (g_atsmb_regulator) {
- if (regulator_is_enabled(atsmb_regulator) == 1) {
- DBG("[%s] Turn off power\n", __FUNCTION__);
- result = regulator_disable(atsmb_regulator);
- if (result != 0)
- printk(KERN_ALERT "[%s] regulator_disable FAIL\n", __FUNCTION__);
- }
- } else {
- GPIO_CTRL_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
- GPIO_OC_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
- /*set internal pull up*/
- PULL_CTRL_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
- /*set internal pull enable*/
- PULL_EN_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
- /*disable SD0 power*/
- GPIO_OD_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
- }
- spin_lock_irqsave(&host->lock, flags);
-}
-
-/**********************************************************************
-Name : atsmb_set_ios
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static void atsmb_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-
- struct atsmb_host *host = mmc_priv(mmc);
- unsigned long flags;
- DBG("[%s] s\n",__func__);
- spin_lock_irqsave(&host->lock, flags);
-
- if (ios->power_mode == MMC_POWER_OFF) {
- if (MMC0_DRIVER_VERSION == MMC_DRV_3498) {
- /* set all descriptor end bit for removing card when
- * PDMA don't transfer data done. let PDMA transfer done
- */
- atsmb_set_dma_end(host->DescVirAddr, host->DescSize);
-
- /* stop SD output clock */
- *ATSMB0_BUS_MODE &= ~(ATSMB_CST);
-
- /* disable SD Card power */
- /*set SD0 power pin as GPO pin*/
- atsmb_disable_power(host, flags);
-
- /* Disable Pull up/down resister of SD Bus */
- /*GPIO_PULL_CTRL_GP13_XDIO_BYTE_VAL &= ~SD0_PIN; marked by eason 2012/3/29*/
-
- /* Config SD0 to GPIO */
- GPIO_CTRL_GP13_SD0_BYTE_VAL |= SD0_PIN;
-
- /* SD0 all pins output low */
- GPIO_OD_GP13_SD0_BYTE_VAL &= ~SD0_PIN;
-
- /* Config SD0 to GPO */
- GPIO_OC_GP13_SD0_BYTE_VAL |= SD0_PIN;
-
- }
-
- } else if (ios->power_mode == MMC_POWER_UP) {
- if (MMC0_DRIVER_VERSION == MMC_DRV_3498) {
- /* disable SD Card power */
- /*set SD0 power pin as GPO pin*/
- GPIO_CTRL_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
- GPIO_OC_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
-
- /*set internal pull up*/
- PULL_CTRL_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
- /*set internal pull enable*/
- PULL_EN_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
- /*disable SD0 power*/
- GPIO_OD_GP13_SD0_BYTE_VAL |= GPIO_SD0_POWER;
-
- /* Config SD PIN share, WM3498 SD0 no share pin */
- /*PIN_SHARING_SEL_4BYTE_VAL &= ~GPIO_SD0_PinShare; */
-
- /* do not config GPIO_SD0_CD because ISR has already run,
- * config card detect will issue ISR storm.
- */
- /*
- GPIO_OD_GP12_SPI_BYTE_VAL |= GPIO_SD0_18SEL;
- GPIO_OC_GP12_SPI_BYTE_VAL |= GPIO_SD0_18SEL;
- GPIO_CTRL_GP12_SPI_BYTE_VAL |= GPIO_SD0_18SEL;
- */
- *ATSMB0_CTL2 |= BIT3; /*Set 3.3V*/
- *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/
- *ATSMB0_CTL2 &= ~(BIT0 | BIT1 | BIT2);
- *ATSMB0_EXT_BUS_MODE &= ~BIT4; /*Disable DDR50*/
-
- /*Set 18SEL as function pin*/
- GPIO_CTRL_GP12_SPI_BYTE_VAL &= ~GPIO_SD0_18SEL;
-
-
- /* Config SD to GPIO */
- GPIO_CTRL_GP13_SD0_BYTE_VAL |= SD0_PIN;
-
- /* SD all pins output low */
- GPIO_OD_GP13_SD0_BYTE_VAL &= ~SD0_PIN;
-
- /* Config SD to GPO */
- GPIO_OC_GP13_SD0_BYTE_VAL |= SD0_PIN;
-
- /* Pull up/down resister of SD Bus */
- /*Disable Clock & CMD Pull enable*/
- PULL_EN_GP13_SD0_BYTE_VAL &= ~(GPIO_SD0_Clock | GPIO_SD0_Command);
-
- /*Set CD ,WP ,DATA pin pull up*/
- if (SD0_detect_pulldown)
- PULL_CTRL_GP63_SD02_BYTE_VAL &= ~GPIO_SD0_CD;
- else
- PULL_CTRL_GP63_SD02_BYTE_VAL |= GPIO_SD0_CD;
- PULL_CTRL_GP13_SD0_BYTE_VAL |= (GPIO_SD0_Data | GPIO_SD0_WriteProtect);
-
- /*Enable CD ,WP ,DATA internal pull*/
- PULL_EN_GP63_SD02_BYTE_VAL |= GPIO_SD0_CD;
- PULL_EN_GP13_SD0_BYTE_VAL |= (GPIO_SD0_Data | GPIO_SD0_WriteProtect);
-
- /*Set SD0 PAD signal drive strength as 0*/
- SD0_DPCTL_4BYTE_VAL = 0;
- SD0_DNCTL_4BYTE_VAL = 0;
-
- spin_unlock_irqrestore(&host->lock, flags);
- msleep(100);
- spin_lock_irqsave(&host->lock, flags);
-
- /* enable SD Card Power */
- atsmb_enable_power(host, flags);
-
- /* enable SD output clock */
- *ATSMB0_BUS_MODE |= ATSMB_CST;
-
- spin_unlock_irqrestore(&host->lock, flags);
- msleep(10);
- spin_lock_irqsave(&host->lock, flags);
-
- /* Config SD0 back to function */
- GPIO_CTRL_GP13_SD0_BYTE_VAL &= ~SD0_PIN;
- GPIO_CTRL_GP63_SD02CD_BYTE_VAL &= ~GPIO_SD0_CD;
- }
- } else {
- /*nothing to do when powering on.*/
- }
-
- host->current_clock = atsmb_set_clock(mmc,ios->clock);
-
- if (ios->bus_width == MMC_BUS_WIDTH_8) {
- *ATSMB0_EXT_CTL |= BIT2;
- } else if (ios->bus_width == MMC_BUS_WIDTH_4) {
- *ATSMB0_BUS_MODE |= ATSMB_BUS_WIDTH_4;
- *ATSMB0_EXT_CTL &= ~BIT2;
- } else {
- *ATSMB0_BUS_MODE &= ~(ATSMB_BUS_WIDTH_4);
- *ATSMB0_EXT_CTL &= ~BIT2;
- }
-
-/*
-#define MMC_TIMING_LEGACY 0
-#define MMC_TIMING_MMC_HS 1
-#define MMC_TIMING_SD_HS 2
-#define MMC_TIMING_UHS_SDR12 MMC_TIMING_LEGACY
-#define MMC_TIMING_UHS_SDR25 MMC_TIMING_SD_HS
-#define MMC_TIMING_UHS_SDR50 3
-#define MMC_TIMING_UHS_SDR104 4
-#define MMC_TIMING_UHS_DDR50 5
-#define MMC_TIMING_MMC_HS200 6
-*/
- DBG("[%s]timing = 0x%x clock = %u\n", __func__, ios->timing, ios->clock);
-
- if (ios->timing == MMC_TIMING_LEGACY) {
- *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/
- *ATSMB0_CTL2 &= ~(BIT0 | BIT1 | BIT2);
- } else if (ios->timing == MMC_TIMING_MMC_HS) {
- *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/
- *ATSMB0_CTL2 &= ~(BIT0 | BIT1 | BIT2);
- } else if (ios->timing == MMC_TIMING_SD_HS) {
- *ATSMB0_EXT_CTL |= BIT7; /*HIGH SPEED MODE*/
- *ATSMB0_CTL2 &= ~(BIT0 | BIT1 | BIT2);
- } else if (ios->timing == MMC_TIMING_UHS_SDR12) {
- *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/
- /*UHS Mode Select = 000 SDR12*/
- *ATSMB0_CTL2 &= ~(BIT0 | BIT1 | BIT2);
- } else if (ios->timing == MMC_TIMING_UHS_SDR25) {
- *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/
- /*UHS Mode Select = 001 SDR25*/
- *ATSMB0_CTL2 |= BIT0;
- *ATSMB0_CTL2 &= ~(BIT1 | BIT2);
- } else if (ios->timing == MMC_TIMING_UHS_SDR50) {
- *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/
- /*UHS Mode Select = 010 SDR50*/
- *ATSMB0_CTL2 |= BIT1;
- *ATSMB0_CTL2 &= ~(BIT0 | BIT2);
- } else if (ios->timing == MMC_TIMING_UHS_SDR104) {
- *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/
- /*UHS Mode Select = 011 SDR104*/
- *ATSMB0_CTL2 |= (BIT0 | BIT1);
- *ATSMB0_CTL2 &= ~BIT2;
- } else if (ios->timing == MMC_TIMING_UHS_DDR50) {
- *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/
- /*UHS Mode Select = 100 DDR50*/
- *ATSMB0_CTL2 |= BIT2;
- *ATSMB0_CTL2 &= ~(BIT0 | BIT1);
- *ATSMB0_EXT_BUS_MODE |= BIT4; /*Enable DDR50*/
- /* enable SD output clock */
- *ATSMB0_BUS_MODE &= ~ATSMB_CST;
- spin_unlock_irqrestore(&host->lock, flags);
- msleep(1);
- spin_lock_irqsave(&host->lock, flags);
-
- *ATSMB0_EXT_BUS_MODE |= BIT4; /*Enable DDR50*/
- /* enable SD output clock */
- *ATSMB0_BUS_MODE |= ATSMB_CST;
- } else
- *ATSMB0_EXT_CTL &= ~BIT7; /*Disable High Speed Mode*/
-
-/* spin_unlock_irqrestore(&host->lock, flags);
- msleep(100);
- spin_lock_irqsave(&host->lock, flags); */
-
- DBG("[%s] *ATSMB0_CTL2 = 0x%x *ATSMB0_EXT_CTL = 0x%x *ATSMB0_EXT_BUS_MODE = 0x%x\n",
- __func__, *ATSMB0_CTL2, *ATSMB0_EXT_CTL, *ATSMB0_EXT_BUS_MODE);
- spin_unlock_irqrestore(&host->lock, flags);
- DBG("[%s] e\n",__func__);
-}
-
-int atsmb_start_signal_voltage_switch(struct mmc_host *host, struct mmc_ios *ios)
-{
- DBG("[%s] s\n",__func__);
-
- if(ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
- /*Set CMD ,DATA0~3 pin as GPO low*/
- /* SD0 all pins output low */
- GPIO_OD_GP13_SD0_BYTE_VAL &= ~(GPIO_SD0_Command | GPIO_SD0_Data);
- /* Config SD0 to GPO */
- GPIO_OC_GP13_SD0_BYTE_VAL |= (GPIO_SD0_Command | GPIO_SD0_Data);;
- /* Config SD0 to GPIO */
- GPIO_CTRL_GP13_SD0_BYTE_VAL |= (GPIO_SD0_Command | GPIO_SD0_Data);
-
-
- /*Wait for 1ms*/
- msleep(1);
-
- /*Stop Clock*/
- *ATSMB0_BUS_MODE &= ~(ATSMB_CST);
-
-
- /*Enable clock & Set 1.8V*/
- *ATSMB0_CTL2 &= ~BIT3;
-
- /*Wait for 10ms*/
- msleep(100);
-
- /*Enable Clock*/
- *ATSMB0_BUS_MODE |= ATSMB_CST;
-
-
- /*Set CMD DATA0~3 pin as function pin*/
- GPIO_CTRL_GP13_SD0_BYTE_VAL &= ~GPIO_SD0_Command;
- GPIO_CTRL_GP13_SD0_BYTE_VAL &= ~GPIO_SD0_Data;
-
-
- DBG("Set SD0 1.8v = 0x%x\n",ios->signal_voltage);
-
- return 0;
- } else if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330){
- *ATSMB0_CTL2 |= BIT3;
- DBG("Set SD0 3.3v = 0x%x\n",ios->signal_voltage);
- return 0;
- }
-
- printk("Set voltage error = 0x%x\n",ios->signal_voltage);
- return -EIO;
- DBG("[%s] e\n",__func__);
-}
-
-static const struct mmc_host_ops atsmb_ops = {
- .request = atsmb_request,
- .set_ios = atsmb_set_ios,
- .get_ro = atsmb_get_ro,
- .get_slot_status = atsmb_get_slot_status,
- .dump_host_regs = atsmb_dump_host_regs,
- .enable_sdio_irq = atsmb_enable_sdio_irq,
- .start_signal_voltage_switch = atsmb_start_signal_voltage_switch,
-};
-
-extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
-
-/**********************************************************************
-Name :atsmb_probe
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static int __init atsmb_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct mmc_host *mmc_host = NULL;
- struct atsmb_host *atsmb_host = NULL;
- struct resource *resource = NULL;
- int irq[2] = {0};
- int ret = 0;
-
- DBG("[%s] s\n",__func__);
- if (!pdev) {
- ret = -EINVAL; /* Invalid argument */
- goto the_end;
- }
-
- /*Enable SD host clock*/
- auto_pll_divisor(DEV_SDMMC0, CLK_ENABLE, 0, 0);
-
- if (MMC0_DRIVER_VERSION == MMC_DRV_3498) {
- /* Pull up/down resister of SD CD */
- if(SD0_detect_pulldown)
- PULL_CTRL_GP63_SD02_BYTE_VAL &= ~GPIO_SD0_CD; /*pull down CD*/
- else
- PULL_CTRL_GP63_SD02_BYTE_VAL |= GPIO_SD0_CD; /*pull up CD*/
- PULL_EN_GP63_SD02_BYTE_VAL |= GPIO_SD0_CD;
-
- /* config CardDetect pin to SD function */
- GPIO_CTRL_GP63_SD02CD_BYTE_VAL &= ~GPIO_SD0_CD;
- }
-
-
- resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!resource) {
- ret = -ENXIO; /* No such device or address */
- printk(KERN_ALERT "[MMC/SD driver] Getting platform resources failed!\n");
- goto the_end;
- }
-#if 0
- if (!request_mem_region(resource->start, SZ_1K, MMC0_DRIVER_NAME)) {
- ret = -EBUSY;
- printk(KERN_ALERT "[MMC/SD driver] Request memory region failed!\n");
- goto the_end ;
- }
-#endif
- irq[0] = platform_get_irq(pdev, 0); /*get IRQ for device*/;
- irq[1] = platform_get_irq(pdev, 1); /*get IRQ for dma*/;
-
- if (irq[0] == NO_IRQ || irq[1] == NO_IRQ) {
- ret = -ENXIO;/* No such device or address */
- printk(KERN_ALERT "[MMC/SD driver] Get platform IRQ failed!\n");
- goto rls_region;
- }
-
- /*allocate a standard msp_host structure attached with a atsmb structure*/
- mmc_host = mmc_alloc_host(sizeof(struct atsmb_host), dev);
- if (!mmc_host) {
- ret = -ENOMEM;
- printk(KERN_ALERT "[MMC/SD driver] Allocating driver's data failed!\n");
- goto rls_region;
- }
- mmc_host->wmt_host_index = 0; /*to identify host number*/
-
- dev_set_drvdata(dev, (void *)mmc_host); /* mmc_host is driver data for the atsmb dev.*/
- atsmb_host = mmc_priv(mmc_host);
-
- mmc_host->ops = &atsmb_ops;
-
- mmc_host->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
-
- mmc_host->f_min = 390425; /*390.425Hz = 400MHz/64/16*/
- mmc_host->f_max = 100000000; /* Set max frequency 100MHz*/
-
- if (SDXC0_function == 1) {
- mmc_host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SDIO_IRQ
- | MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR;
- /* |MMC_CAP_8_BIT_DATA;*/ //zhf: marked by James Tian
- } else {
- mmc_host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SDIO_IRQ;
- /* |MMC_CAP_8_BIT_DATA;*/ //zhf: marked by James Tian
- }
-
- mmc_host->max_segs = 128; /*we use software sg. so we could manage even larger number.*/
-
- /*1MB per each request */
- /*we have a 16 bit block number register, and block length is 512 bytes.*/
- mmc_host->max_req_size = 16*512*(mmc_host->max_segs);
- mmc_host->max_seg_size = 65024; /* 0x7F*512 PDMA one descriptor can transfer 64K-1 byte*/
- mmc_host->max_blk_size = 2048; /* our block length register is 11 bits.*/
- mmc_host->max_blk_count = (mmc_host->max_req_size)/512;
-
- /*set the specified host -- ATSMB*/
-#ifdef CONFIG_MMC_UNSAFE_RESUME
- mmc_host->card_attath_status = card_attach_status_unchange;
-#endif
- sema_init(&mmc_host->req_sema,1); /*initial request semaphore*/
-#if 0
- atsmb_host->base = ioremap(resource->start, SZ_1K);
- if (!atsmb_host->base) {
- printk(KERN_ALERT "[MMC/SD driver] IO remap failed!\n");
- ret = -ENOMEM;
- goto fr_host;
- }
-#endif
- atsmb_host->base = (void *)resource->start;
- atsmb_host->mmc = mmc_host;
- spin_lock_init(&atsmb_host->lock);
- atsmb_host->res = resource;/* for atsmb_remove*/
-
- /*disable all interrupt and clear status by resetting controller.*/
- *ATSMB0_BUS_MODE |= ATSMB_SFTRST;
- *ATSMB0_BLK_LEN &= ~(0xa000);
- *ATSMB0_SD_STS_0 |= 0xff;
- *ATSMB0_SD_STS_1 |= 0xff;
-
- /* WM3437 A0 default not output clock, after SFTRST need to enable SD clock */
- //if (MMC0_DRIVER_VERSION >= MMC_DRV_3437_A0) /* including 3429 */
- *ATSMB0_BUS_MODE |= ATSMB_CST;
-
- atsmb_host->regular_irq = irq[0];
- atsmb_host->dma_irq = irq[1];
-
- ret = request_irq(atsmb_host->regular_irq,
- atsmb_regular_isr,
- IRQF_SHARED, //SA_SHIRQ, /*SA_INTERRUPT, * that is okay?*/ //zhf: modified by James Tian, should be IRQF_SHARED?
- MMC0_DRIVER_NAME,
- (void *)atsmb_host);
- if (ret) {
- printk(KERN_ALERT "[MMC/SD driver] Failed to register regular ISR!\n");
- goto unmap;
- }
-
- ret = request_irq(atsmb_host->dma_irq,
- atsmb_dma_isr,
- IRQF_DISABLED, // SA_INTERRUPT, //zhf: modified by James Tian
- MMC0_DRIVER_NAME,
- (void *)atsmb_host);
- if (ret) {
- printk(KERN_ALERT "[MMC/SD driver] Failed to register DMA ISR!\n");
- goto fr_regular_isr;
- }
-
- /* config CardDetect pin to SD function */
- /*GPIO_CTRL_GP63_SD02CD_BYTE_VAL &= ~GPIO_SD0_CD; add by eason 2012/3/29*/
-
- /*wait card detect status change*/
- //msleep(10);
-
- /*enable card insertion interrupt and enable DMA and its Global INT*/
- *ATSMB0_BLK_LEN |= (0xa000); /* also, we enable GPIO to detect card.*/
- *ATSMB0_SD_STS_0 |= 0xff;
- *ATSMB0_INT_MASK_0 |= 0x80; /*or 0x40?*/
-
- /*allocation dma descriptor*/
- ret = atsmb_alloc_desc(atsmb_host, sizeof(struct SD_PDMA_DESC_S) * MAX_DESC_NUM);
- if (ret == -1) {
- printk(KERN_ALERT "[MMC/SD driver] Failed to allocate DMA descriptor!\n");
- goto fr_dma_isr;
- }
- printk(KERN_INFO "WMT ATSMB (AHB To SD/MMC Bus) controller registered!\n");
-
- if (SD0_function == SDIO_WIFI)
- mmc_add_host(mmc_host,false);
- else
- mmc_add_host(mmc_host,true);
-
- mmc_host_attr = mmc_host;
-
- DBG("[%s] e1\n",__func__);
- return 0;
-
-fr_dma_isr:
- free_irq(atsmb_host->dma_irq, atsmb_host);
-fr_regular_isr:
- free_irq(atsmb_host->regular_irq, atsmb_host);
-unmap:
- //iounmap(atsmb_host->base);
-//fr_host:
- dev_set_drvdata(dev, NULL);
- mmc_free_host(mmc_host);
-rls_region:
- //release_mem_region(resource->start, SZ_1K);
-the_end:
- printk(KERN_ALERT "[MMC/SD driver] ATSMB0 probe Failed!\n") ;
- DBG("[%s] e2\n",__func__);
- return ret;
-}
-/**********************************************************************
-Name : atsmb_remove
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static int atsmb_remove(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct mmc_host *mmc_host = (struct mmc_host *)dev_get_drvdata(dev);
- struct atsmb_host *atsmb_host;
-
- DBG("[%s] s\n",__func__);
- atsmb_host = mmc_priv(mmc_host);
- if (!mmc_host || !atsmb_host) {
- printk(KERN_ALERT "[MMC/SD driver] ATSMB0 remove method failed!\n");
- DBG("[%s] e1\n",__func__);
- return -ENXIO;
- }
- mmc_remove_host(mmc_host);
-
- /*disable interrupt by resetting controller -- for safey*/
- *ATSMB0_BUS_MODE |= ATSMB_SFTRST;
- *ATSMB0_BLK_LEN &= ~(0xa000);
- *ATSMB0_SD_STS_0 |= 0xff;
- *ATSMB0_SD_STS_1 |= 0xff;
-
- (void)free_irq(atsmb_host->regular_irq, atsmb_host);
- (void)free_irq(atsmb_host->dma_irq, atsmb_host);
- (void)iounmap(atsmb_host->base);
- (void)release_mem_region(atsmb_host->res->start, SZ_1K);
- dev_set_drvdata(dev, NULL);
- /*free dma descriptor*/
- dma_free_coherent(atsmb_host->mmc->parent, atsmb_host->DescSize,
- atsmb_host->DescVirAddr, atsmb_host->DescPhyAddr);
- (void)mmc_free_host(mmc_host);/* also free atsmb_host.*/
- DBG("[%s] e2\n",__func__);
- return 0;
-}
-
-/**********************************************************************
-Name : atsmb_shutdown
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Tommy Huang
-History :
-***********************************************************************/
-static void atsmb_shutdown(struct platform_device *pdev)
-{
- /*atsmb_shutdown don't be used now.*/
- /*struct device *dev = &pdev->dev;
- struct mmc_host *mmc_host = (struct mmc_host *)dev_get_drvdata(dev);*/
-
- DBG("[%s] s\n",__func__);
- if (SD0_function != SDIO_WIFI) {
- /*Disable card detect interrupt*/
- *ATSMB0_INT_MASK_0 &= ~0x80;
- }
- DBG("[%s] e\n",__func__);
-
-}
-
-/**********************************************************************
-Name : atsmb_suspend
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-#ifdef CONFIG_PM
-static int atsmb_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct device *dev = &pdev->dev;
- struct mmc_host *mmc = (struct mmc_host *)dev_get_drvdata(dev);
- int ret = 0;
- DBG("[%s] s\n",__func__);
-
- if (mmc) {
- /*struct atsmb_host *host = mmc_priv(mmc);*/
- ret = mmc_suspend_host(mmc);
- if (ret == 0) {
- /*disable all interrupt and clear status by resetting controller. */
- *ATSMB0_BUS_MODE |= ATSMB_SFTRST;
- *ATSMB0_BLK_LEN &= ~(0xa000);
- *ATSMB0_SD_STS_0 |= 0xff;
- *ATSMB0_SD_STS_1 |= 0xff;
-
- }
- /*disable source clock*/
- auto_pll_divisor(DEV_SDMMC0, CLK_DISABLE, 0, 0);
-#ifdef CONFIG_MMC_UNSAFE_RESUME
- /*clean SD card attatch status change*/
- PMCWS_VAL |= BIT19;
- mmc->card_attath_status = card_attach_status_unchange;
-#endif
- }
-
- DBG("[%s] e\n",__func__);
- return ret;
-}
-/**********************************************************************
-Name : atsmb_resume
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static int atsmb_resume(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct mmc_host *mmc = (struct mmc_host *)dev_get_drvdata(dev);
- int ret = 0;
- DBG("[%s] s\n",__func__);
-
- /*
- * enable interrupt, DMA, etc.
- * Supply power to slot.
- */
- if (mmc) {
- /*enable source clock*/
- auto_pll_divisor(DEV_SDMMC0, CLK_ENABLE, 0, 0);
-
- udelay(1);
- /*enable card insertion interrupt and enable DMA and its Global INT*/
- *ATSMB0_BUS_MODE |= ATSMB_SFTRST;
- *ATSMB0_BLK_LEN |= (0xa000);
- *ATSMB0_INT_MASK_0 |= 0x80; /* or 40?*/
-#ifdef CONFIG_MMC_UNSAFE_RESUME
- /*modify SD card attatch status change*/
- if ((PMCWS_VAL & BIT19) && !mmc->bus_dead) {
- /*card change when suspend mode*/
- mmc->card_attath_status = card_attach_status_change;
- /*clean SD card attatch status change*/
- PMCWS_VAL |= BIT19;
- }
-#endif
- ret = mmc_resume_host(mmc);
- }
-
- DBG("[%s] e\n",__func__);
- return ret;
-}
-#else
-#define atsmb_suspend NULL
-#define atsmb_resume NULL
-#endif
-
-static struct platform_driver atsmb_driver = {
- .driver.name = "sdmmc",
- //.probe = atsmb_probe,
- .remove = atsmb_remove,
- .shutdown = atsmb_shutdown,
- .suspend = atsmb_suspend,
- .resume = atsmb_resume,
-};
-
-static struct platform_device wmt_sdmmc_device = {
- .name = "sdmmc",
- .id = 0,
- .dev = {
- .dma_mask = &wmt_sdmmc_dma_mask,
- .coherent_dma_mask = ~0,
- .release = atsmb_release,
- },
- .num_resources = ARRAY_SIZE(wmt_sdmmc_resources),
- .resource = wmt_sdmmc_resources,
-};
-
-
-static ssize_t atsmb_state_show(struct kobject *kobj, struct kobj_attribute *attr,
- char *buf)
-{
- int ret = 0;
- int card_state;
-
- DBG("[%s] s\n",__func__);
- if (mmc_host_attr->card != NULL)
- card_state = 1;
- else
- card_state = 0;
- DBG("[%s]card_state = %d\n",__func__,card_state);
- ret = sprintf(buf, "%d\n", card_state);
- DBG("[%s] e\n",__func__);
- return ret;
-}
-
-static ssize_t atsmb_state_store(struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n)
-{
- int val;
- DBG("[%s] s\n",__func__);
- if (sscanf(buf, "%d", &val) == 1) {
- DBG("[%s] val = %d\n",__func__,val);
- if ((val == 1) && (mmc_host_attr->card == NULL)) {
- DBG("[%s]add card\n",__func__);
- mmc_detect_change(mmc_host_attr, 0);
- msleep(500);
- } else if ((val == 0) && (mmc_host_attr->card != NULL)) {
- DBG("[%s]remove card\n",__func__);
- mmc_force_remove_card(mmc_host_attr);
- }
- DBG("[%s] e1\n",__func__);
- return n;
- }
- DBG("[%s] e2\n",__func__);
- return -EINVAL;
-}
-
-static struct kobj_attribute atsmb_state_attr = { \
- .attr = { \
- .name = __stringify(state), \
- .mode = 0755, \
- }, \
- .show = atsmb_state_show, \
- .store = atsmb_state_store, \
-};
-
-static struct attribute * g[] = {
- &atsmb_state_attr.attr,
- NULL,
-};
-
-static struct attribute_group attr_group = {
- .attrs = g,
-};
- //kevin add to check tf card stats every 1 sec
-
-static void wmt_mmc_work(struct work_struct *work)
-{
-
- static int card_state_save = -1;
- if(mmc_host_attr!=NULL){
- struct atsmb_host *host = mmc_priv(mmc_host_attr);
- int card_state;
- if (mmc_host_attr->card != NULL)
- card_state = 1;
- else
- card_state = 0;
-
-
- //printk("check %d %d\n",atsmb_get_slot_status(host->mmc),card_state);
- if(atsmb_get_slot_status(host->mmc)!=card_state){
- //the second time error,goto detect or remove card
- if(card_state_save == card_state){
-
- //printk("xxxxxxxxxxxxxxxxxxxxxxxxcatch error %dxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n",card_state);
- mmc_detect_change(mmc_host_attr, 0);
-
- }
- //mark status error
- card_state_save =card_state;
- }else
- card_state_save = -1;
-
- }
- schedule_delayed_work(&mmc_work, 1*HZ);
-}
-static int __init atsmb_init(void)
-{
- int ret;
-
- int retval;
- unsigned char buf[80];
- int varlen = 80;
- char *varname = "wmt.sd0.param";
- int temp = 0, sd_enable = 1; /*0 :disable 1:enable*/
- unsigned char colon;
- DBG("[%s] s\n",__func__);
-
-#ifdef CONFIG_MTD_WMT_SF
- /*Read system param to identify host function 0: SD/MMC 1:SDIO wifi*/
- retval = wmt_getsyspara(varname, buf, &varlen);
- if (retval == 0) {
- sscanf(buf,"%x%c%d%c%d%c%d%c%d", &temp, &colon, &SD0_function,&colon,&SD0_detect_pol,&colon,&SD0_detect_pulldown,&colon,&SD0_speed);
- printk(KERN_ALERT "wmt.sd0.param = %x%c%d%c%d%c%d%c%d\n", temp, colon, SD0_function,colon,SD0_detect_pol,colon,SD0_detect_pulldown,colon,SD0_speed);
- sd_enable = temp & 0xf;
- SDXC0_function = (temp >> 4) & 0xf;
- printk(KERN_ALERT "SD0 ebable = %x, SDXC = %x, function = %x\n",
- sd_enable, SDXC0_function, SD0_function);
-
- if (SD0_function < 0 || SD0_function >= SD_MAX_FUN) {
- sd_enable = 1;
- SD0_function = 0;
- printk(KERN_ALERT "wmt.sd0.param func err\n");
- }
- if (colon != ':') {
- sd_enable = 1;
- printk(KERN_ALERT "wmt.sd0.param colon err\n");
- }
-
- } else {
- printk(KERN_ALERT "Default wmt.sd0.param = %x:%d\n", temp, SD0_function);
- }
-
- //add by kevin guan
- retval = wmt_getsyspara("wmt.sd0.ro.disable", buf, &varlen);
- if (retval == 0) {
- sscanf(buf,"%d", &SD0_ro_disable);
- printk(KERN_ALERT "SD0_ro_disable %d\n",SD0_ro_disable);
- }
-
-#endif
- /*SD function disable*/
- if (sd_enable != 1) {
- return -ENODEV;
- }
-
-
- get_driver_version();
-
- if (platform_device_register(&wmt_sdmmc_device))//add by jay,for modules support
- return -1;
- //ret = platform_driver_register(&atsmb_driver);
-
- /* Register regulator for SD host power switch */
- atsmb_regulator = regulator_get(NULL, "ldo4");
- if (IS_ERR(atsmb_regulator))
- g_atsmb_regulator = 0;
- else
- g_atsmb_regulator = 1;
- printk("[SD/MMC]use_regulator = %d\n", g_atsmb_regulator);
-
- /* Force to disable ldo4 regulator, because Power switch is turned on, default */
- if (g_atsmb_regulator) {
- ret = regulator_force_disable(atsmb_regulator);
- if (ret != 0)
- printk(KERN_ALERT "[%s] get regulator Fail, ret = %d\n", __FUNCTION__, ret);
- }
-
- ret = platform_driver_probe(&atsmb_driver, atsmb_probe);
-
- atsmb_kobj = kobject_create_and_add("mmc0", NULL);
- if (!atsmb_kobj)
- return -ENOMEM;
-
-
- {
- //add by kevin guan
- int detect_disable = 0;
- retval = wmt_getsyspara("wmt.sd0.detect.disable", buf, &varlen);
- if (retval == 0) {
- sscanf(buf,"%d", &detect_disable);
- printk(KERN_ALERT "detect_disable %d\n",detect_disable);
- }
-
- if(detect_disable){
- //tf slot without detect pin.
- //do nothing;
- }else{
- //kevin add to check tf card stats every 1 sec
- INIT_DELAYED_WORK(&mmc_work, wmt_mmc_work);
- schedule_delayed_work(&mmc_work, 1*HZ);
- }
- }
-
- return sysfs_create_group(atsmb_kobj, &attr_group);
-
- DBG("[%s] e\n",__func__);
- return ret;
-}
-
-static void __exit atsmb_exit(void)
-{
- DBG("[%s] s\n",__func__);
- (void)platform_driver_unregister(&atsmb_driver);
- (void)platform_device_unregister(&wmt_sdmmc_device);//add by jay,for modules support
- DBG("[%s] e\n",__func__);
-}
-
-module_init(atsmb_init);
-module_exit(atsmb_exit);
-module_param(fmax0, uint, 0444);
-
-MODULE_AUTHOR("WonderMedia Technologies, Inc.");
-MODULE_DESCRIPTION("WMT [AHB to SD/MMC Bridge] driver");
-MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.h b/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.h
deleted file mode 100755
index 845b1116..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb.h
+++ /dev/null
@@ -1,691 +0,0 @@
-/*++
-linux/drivers/mmc/host/mmc_atsmb.h
-
-Copyright (c) 2008 WonderMedia Technologies, Inc.
-
-This program is free software: you can redistribute it and/or modify it under the
-terms of the GNU General Public License as published by the Free Software Foundation,
-either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-PARTICULAR PURPOSE. See the GNU General Public License for more details.
-You should have received a copy of the GNU General Public License along with
-this program. If not, see <http://www.gnu.org/licenses/>.
-
-WonderMedia Technologies, Inc.
-10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
---*/
-
-
-
-#ifndef __MMC_ATSMB_H
-#define __MMC_ATSMB_H
-
-#define MMC0_DRIVER_NAME "sdmmc"
-#define MMC1_DRIVER_NAME "sdmmc1"
-#define MMC2_DRIVER_NAME "sdmmc2"
-
-
-
-#define MMC_ERR_NONE 0 /* Only for Android kernel 2.6.29, in MVL5, this variable is defined in mmc.h */
-#define MMC_ERR_FAILED 4 /* Only for Android kernel 2.6.29, in MVL5, this variable is defined in mmc.h */
-/***************Driver version****************/
-#define MMC_DRV_3357_A0_A3 0
-#define MMC_DRV_3357_A4_A7 1
-#define MMC_DRV_3358 2
-#define MMC_DRV_3359 3
-#define MMC_DRV_3400_A0 4
-#define MMC_DRV_3400_A1 5
-#define MMC_DRV_3426_A0 6
-#define MMC_DRV_3426_A1 7
-#define MMC_DRV_3426_A2 8
-#define MMC_DRV_3437_A0 9
-#define MMC_DRV_3437_A1 10
-#define MMC_DRV_3429 11
-#define MMC_DRV_3451_A0 12
-#define MMC_DRV_3465 13
-#define MMC_DRV_3445 14
-#define MMC_DRV_3481 15
-#define MMC_DRV_3498 16
-/************** INT and Base address*****************/
-/*special settings for each one*/
-
-#define MMC_ATSMB0_BASE SD0_SDIO_MMC_BASE_ADDR
-#define MMC_ATMSB0_END (SD0_SDIO_MMC_BASE_ADDR + 0x3FF)
-
-#define MMC_ATSMB1_BASE SD1_SDIO_MMC_BASE_ADDR
-#define MMC_ATMSB1_END (SD1_SDIO_MMC_BASE_ADDR + 0x3FF)
-
-#define MMC_ATSMB2_BASE SD2_SDIO_MMC_BASE_ADDR
-#define MMC_ATMSB2_END (SD2_SDIO_MMC_BASE_ADDR + 0x3FF)
-
-
-/************** INT and Base address*****************/
-
-/* SD0 pin */
-#define GPIO_SD0_CD BIT4
-#define GPIO_SD0_Data (BIT6 | BIT5 | BIT4 | BIT3)
-#define GPIO_SD0_WriteProtect BIT2
-#define GPIO_SD0_Command BIT1
-#define GPIO_SD0_Clock BIT0
-#define GPIO_SD0_POWER BIT7
-#define GPIO_SD0_18SEL BIT4
-
-/* SD1 pin */
-#define GPIO_SD1_Data (BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0)
-#define GPIO_SD1_Command BIT1
-#define GPIO_SD1_Clock BIT0
-#define GPIO_SD1_CD BIT6
-#define GPIO_SD1_WriteProtect BIT5
-#define GPIO_SD1_POWER BIT4
-#define GPIO_SD1_RSTN BIT3
-
-/* SD2 pin */
-#define GPIO_SD2_Data (BIT3 | BIT2 | BIT1 | BIT0)
-#define GPIO_SD2_Command BIT4
-#define GPIO_SD2_Clock BIT5
-#define GPIO_SD2_CD BIT0
-#define GPIO_SD2_WriteProtect BIT7
-#define GPIO_SD2_POWER BIT6
-
-/* SDIO Power pin */
-#define SDIO_WIFI_PWR BIT2
-#define SDIO_WIFI_INT BIT3
-#define SOIO_WIFI_WAKE_FUN BIT27
-
-#define SD0_PIN (GPIO_SD0_Clock | GPIO_SD0_Command | GPIO_SD0_WriteProtect | GPIO_SD0_Data)
-#define SD1_PIN (GPIO_SD1_Clock | GPIO_SD1_Command | GPIO_SD1_WriteProtect | GPIO_SD1_RSTN)
-#define SD2_PIN (GPIO_SD2_Clock | GPIO_SD2_Command | GPIO_SD2_WriteProtect | GPIO_SD2_Data)
-
-/* PIN share switch */
-#define GPIO_SD1_PinShare BIT11
-#define GPIO_SD2_PinShare BIT28
-
-#define SD0_CARD_PWR BIT1
-#define SD1_CARD_PWR BIT2
-#define SD2_CARD_PWR BIT3
-
-/* IO Deive Strength and Slew Rate*/
-#define SD0_IO_Slew_Rate BIT1
-#define SD0_IO_Drive_Strength BIT0
-
-
-
-/*common settings*/
-
-#define NR_SG 128
-
-/*=============================================*/
-/* WMT ATSMB Register Offset*/
-/*=============================================*/
-#define _CTL 0x00 /* 1 byte*/
-#define _CMD_IDX 0x01 /* 1 byte*/
-#define _RSP_TYPE 0x02 /* 1 byte*/
-
-#define _CMD_ARG 0x04 /* 4 bytes*/
-#define _BUS_MODE 0x08 /* 1 byte*/
-#define _EXT_BUS_MODE 0x09 /* 1 byte*/
-#define _CTL2 0x0a /* 2 bytes*/
-#define _BLK_LEN 0x0c /* 2 bytes*/
-#define _BLK_CNT 0x0e /* 2 bytes*/
-#define _RSP_0 0x10 /* 1 bytes*/
-#define _RSP_1 0x11 /* 1 bytes*/
-#define _RSP_2 0x12 /* 1 bytes*/
-#define _RSP_3 0x13 /* 1 bytes*/
-#define _RSP_4 0x14 /* 1 bytes*/
-#define _RSP_5 0x15 /* 1 bytes*/
-#define _RSP_6 0x16 /* 1 bytes*/
-#define _RSP_7 0x17 /* 1 bytes*/
-#define _RSP_8 0x18 /* 1 bytes*/
-#define _RSP_9 0x19 /* 1 bytes*/
-#define _RSP_10 0x1a /* 1 bytes*/
-#define _RSP_11 0x1b /* 1 bytes*/
-#define _RSP_12 0x1c /* 1 bytes*/
-#define _RSP_13 0x1d /* 1 bytes*/
-#define _RSP_14 0x1e /* 1 bytes*/
-#define _RSP_15 0x1f /* 1 bytes*/
-
-#define _CURBLK_CNT 0x20 /* 4 bytes*/
-#define _INT_MASK_0 0x24 /* 1 byte*/
-#define _INT_MASK_1 0x25 /* 1 byte*/
-
-#define _SD_STS_0 0x28 /* 1 byte*/
-#define _SD_STS_1 0x29 /* 1 byte*/
-#define _SD_STS_2 0x2a /* 1 byte*/
-#define _SD_STS_3 0x2b /* 1 byte*/
-#define _RSP_TOUT 0x2c /* 1 byte*/
-
-#define _CLK_SEL 0x30 /* 1 byte*/ /*Not used*/
-
-#define _EXT_CTL 0x34 /* 1 byte*/
-#define _EXT_CTL_1 0x35 /* 1 byte*/
-#define _EXT_CTL_2 0x36 /* 1 byte*/
-
-#define _SHDW_BLKLEN 0x38 /* 2 bytes*/
-#define _MAN_TUNE_VAL 0x3a /* 1 byte*/
-#define _SD_WRI_TUNE 0x3b /* 1 byte*/
-#define _TIMER_VAL 0x3c /* 2 bytes*/
-
-
-#define _PDMA_GCR 0x100
-#define _PDMA_IER 0x104
-#define _PDMA_ISR 0x108
-#define _PDMA_DESPR 0x10C
-#define _PDMA_RBR 0x110
-#define _PDMA_DAR 0x114
-#define _PDMA_BAR 0x118
-#define _PDMA_CPR 0x11C
-#define _PDMA_CCR 0X120
-
-
-/*=========================================*/
-/* SD0 PDMA related Registers */
-/*=========================================*/
-#define ATSMB0_PDMA_GCR (REG32_PTR(_PDMA_GCR + MMC_ATSMB0_BASE))
-#define ATSMB0_PDMA_IER (REG32_PTR(_PDMA_IER + MMC_ATSMB0_BASE))
-#define ATSMB0_PDMA_ISR (REG32_PTR(_PDMA_ISR + MMC_ATSMB0_BASE))
-#define ATSMB0_PDMA_DESPR (REG32_PTR(_PDMA_DESPR + MMC_ATSMB0_BASE))
-#define ATSMB0_PDMA_RBR (REG32_PTR(_PDMA_RBR + MMC_ATSMB0_BASE))
-#define ATSMB0_PDMA_DAR (REG32_PTR(_PDMA_DAR + MMC_ATSMB0_BASE))
-#define ATSMB0_PDMA_BAR (REG32_PTR(_PDMA_BAR + MMC_ATSMB0_BASE))
-#define ATSMB0_PDMA_CPR (REG32_PTR(_PDMA_CPR + MMC_ATSMB0_BASE))
-#define ATSMB0_PDMA_CCR (REG32_PTR(_PDMA_CCR + MMC_ATSMB0_BASE))
-
-
-/*=========================================*/
-/* SD0 Register pointer. */
-/*=========================================*/
-#define ATSMB0_CTL (REG8_PTR(_CTL + MMC_ATSMB0_BASE))
-#define ATSMB0_CMD_IDX (REG8_PTR(_CMD_IDX + MMC_ATSMB0_BASE))
-#define ATSMB0_RSP_TYPE (REG8_PTR(_RSP_TYPE + MMC_ATSMB0_BASE))
-#define ATSMB0_CMD_ARG (REG32_PTR(_CMD_ARG + MMC_ATSMB0_BASE))
-#define ATSMB0_BUS_MODE (REG8_PTR(_BUS_MODE + MMC_ATSMB0_BASE))
-#define ATSMB0_EXT_BUS_MODE (REG8_PTR(_EXT_BUS_MODE + MMC_ATSMB0_BASE))
-#define ATSMB0_CTL2 (REG16_PTR(_CTL2 + MMC_ATSMB0_BASE))
-#define ATSMB0_BLK_LEN (REG16_PTR(_BLK_LEN + MMC_ATSMB0_BASE))
-#define ATSMB0_BLK_CNT (REG16_PTR(_BLK_CNT + MMC_ATSMB0_BASE))
-#define ATSMB0_RSP_0 (REG8_PTR(_RSP_0 + MMC_ATSMB0_BASE))
-#define ATSMB0_RSP_1 (REG8_PTR(_RSP_1 + MMC_ATSMB0_BASE))
-#define ATSMB0_RSP_2 (REG8_PTR(_RSP_2 + MMC_ATSMB0_BASE))
-#define ATSMB0_RSP_3 (REG8_PTR(_RSP_3 + MMC_ATSMB0_BASE))
-#define ATSMB0_RSP_4 (REG8_PTR(_RSP_4 + MMC_ATSMB0_BASE))
-#define ATSMB0_RSP_5 (REG8_PTR(_RSP_5 + MMC_ATSMB0_BASE))
-#define ATSMB0_RSP_6 (REG8_PTR(_RSP_6 + MMC_ATSMB0_BASE))
-#define ATSMB0_RSP_7 (REG8_PTR(_RSP_7 + MMC_ATSMB0_BASE))
-#define ATSMB0_RSP_8 (REG8_PTR(_RSP_8 + MMC_ATSMB0_BASE))
-#define ATSMB0_RSP_9 (REG8_PTR(_RSP_9 + MMC_ATSMB0_BASE))
-#define ATSMB0_RSP_10 (REG8_PTR(_RSP_10 + MMC_ATSMB0_BASE))
-#define ATSMB0_RSP_11 (REG8_PTR(_RSP_11 + MMC_ATSMB0_BASE))
-#define ATSMB0_RSP_12 (REG8_PTR(_RSP_12 + MMC_ATSMB0_BASE))
-#define ATSMB0_RSP_13 (REG8_PTR(_RSP_13 + MMC_ATSMB0_BASE))
-#define ATSMB0_RSP_14 (REG8_PTR(_RSP_14 + MMC_ATSMB0_BASE))
-#define ATSMB0_RSP_15 (REG8_PTR(_RSP_15 + MMC_ATSMB0_BASE))
-
-#define ATSMB0_CURBLK_CNT (REG32_PTR(_CURBLK_CNT + MMC_ATSMB0_BASE))
-#define ATSMB0_INT_MASK_0 (REG8_PTR(_INT_MASK_0 + MMC_ATSMB0_BASE))
-#define ATSMB0_INT_MASK_1 (REG8_PTR(_INT_MASK_1 + MMC_ATSMB0_BASE))
-#define ATSMB0_SD_STS_0 (REG8_PTR(_SD_STS_0 + MMC_ATSMB0_BASE))
-#define ATSMB0_SD_STS_1 (REG8_PTR(_SD_STS_1 + MMC_ATSMB0_BASE))
-#define ATSMB0_SD_STS_2 (REG8_PTR(_SD_STS_2 + MMC_ATSMB0_BASE))
-#define ATSMB0_SD_STS_3 (REG8_PTR(_SD_STS_3 + MMC_ATSMB0_BASE))
-
-#define ATSMB0_RSP_TOUT (REG8_PTR(_RSP_TOUT + MMC_ATSMB0_BASE))
-#define ATSMB0_CLK_SEL (REG8_PTR(_CLK_SEL + MMC_ATSMB0_BASE))
-#define ATSMB0_EXT_CTL (REG8_PTR(_EXT_CTL + MMC_ATSMB0_BASE))
-#define ATSMB0_EXT_CTL_1 (REG8_PTR(_EXT_CTL_1 + MMC_ATSMB0_BASE))
-#define ATSMB0_EXT_CTL_2 (REG8_PTR(_EXT_CTL_2 + MMC_ATSMB0_BASE))
-
-#define ATSMB0_SHDW_BLKLEN (REG16_PTR(_SHDW_BLKLEN + MMC_ATSMB0_BASE))
-#define ATSMB0_MAN_TUNE_VAL (REG8_PTR(_MAN_TUNE_VAL + MMC_ATSMB0_BASE))
-#define ATSMB0_SD_WRI_TUNE (REG8_PTR(_SD_WRI_TUNE+ MMC_ATSMB0_BASE))
-#define ATSMB0_TIMER_VAL (REG16_PTR(_TIMER_VAL + MMC_ATSMB0_BASE))
-
-//#define ATSMB0_INT (REG8_PTR(0xd8140056))
-
-
-
-
-/*=========================================*/
-/* SD1 PDMA related Registers */
-/*=========================================*/
-#define ATSMB1_PDMA_GCR (REG32_PTR(_PDMA_GCR + MMC_ATSMB1_BASE))
-#define ATSMB1_PDMA_IER (REG32_PTR(_PDMA_IER + MMC_ATSMB1_BASE))
-#define ATSMB1_PDMA_ISR (REG32_PTR(_PDMA_ISR + MMC_ATSMB1_BASE))
-#define ATSMB1_PDMA_DESPR (REG32_PTR(_PDMA_DESPR + MMC_ATSMB1_BASE))
-#define ATSMB1_PDMA_RBR (REG32_PTR(_PDMA_RBR + MMC_ATSMB1_BASE))
-#define ATSMB1_PDMA_DAR (REG32_PTR(_PDMA_DAR + MMC_ATSMB1_BASE))
-#define ATSMB1_PDMA_BAR (REG32_PTR(_PDMA_BAR + MMC_ATSMB1_BASE))
-#define ATSMB1_PDMA_CPR (REG32_PTR(_PDMA_CPR + MMC_ATSMB1_BASE))
-#define ATSMB1_PDMA_CCR (REG32_PTR(_PDMA_CCR + MMC_ATSMB1_BASE))
-
-
-/*=========================================*/
-/* SD1 Register pointer. */
-/*=========================================*/
-#define ATSMB1_CTL (REG8_PTR(_CTL + MMC_ATSMB1_BASE))
-#define ATSMB1_CMD_IDX (REG8_PTR(_CMD_IDX + MMC_ATSMB1_BASE))
-#define ATSMB1_RSP_TYPE (REG8_PTR(_RSP_TYPE + MMC_ATSMB1_BASE))
-#define ATSMB1_CMD_ARG (REG32_PTR(_CMD_ARG + MMC_ATSMB1_BASE))
-#define ATSMB1_BUS_MODE (REG8_PTR(_BUS_MODE + MMC_ATSMB1_BASE))
-#define ATSMB1_EXT_BUS_MODE (REG8_PTR(_EXT_BUS_MODE + MMC_ATSMB1_BASE))
-#define ATSMB1_CTL2 (REG16_PTR(_CTL2 + MMC_ATSMB1_BASE))
-#define ATSMB1_BLK_LEN (REG16_PTR(_BLK_LEN + MMC_ATSMB1_BASE))
-#define ATSMB1_BLK_CNT (REG16_PTR(_BLK_CNT + MMC_ATSMB1_BASE))
-#define ATSMB1_RSP_0 (REG8_PTR(_RSP_0 + MMC_ATSMB1_BASE))
-#define ATSMB1_RSP_1 (REG8_PTR(_RSP_1 + MMC_ATSMB1_BASE))
-#define ATSMB1_RSP_2 (REG8_PTR(_RSP_2 + MMC_ATSMB1_BASE))
-#define ATSMB1_RSP_3 (REG8_PTR(_RSP_3 + MMC_ATSMB1_BASE))
-#define ATSMB1_RSP_4 (REG8_PTR(_RSP_4 + MMC_ATSMB1_BASE))
-#define ATSMB1_RSP_5 (REG8_PTR(_RSP_5 + MMC_ATSMB1_BASE))
-#define ATSMB1_RSP_6 (REG8_PTR(_RSP_6 + MMC_ATSMB1_BASE))
-#define ATSMB1_RSP_7 (REG8_PTR(_RSP_7 + MMC_ATSMB1_BASE))
-#define ATSMB1_RSP_8 (REG8_PTR(_RSP_8 + MMC_ATSMB1_BASE))
-#define ATSMB1_RSP_9 (REG8_PTR(_RSP_9 + MMC_ATSMB1_BASE))
-#define ATSMB1_RSP_10 (REG8_PTR(_RSP_10 + MMC_ATSMB1_BASE))
-#define ATSMB1_RSP_11 (REG8_PTR(_RSP_11 + MMC_ATSMB1_BASE))
-#define ATSMB1_RSP_12 (REG8_PTR(_RSP_12 + MMC_ATSMB1_BASE))
-#define ATSMB1_RSP_13 (REG8_PTR(_RSP_13 + MMC_ATSMB1_BASE))
-#define ATSMB1_RSP_14 (REG8_PTR(_RSP_14 + MMC_ATSMB1_BASE))
-#define ATSMB1_RSP_15 (REG8_PTR(_RSP_15 + MMC_ATSMB1_BASE))
-
-#define ATSMB1_CURBLK_CNT (REG32_PTR(_CURBLK_CNT + MMC_ATSMB1_BASE))
-#define ATSMB1_INT_MASK_0 (REG8_PTR(_INT_MASK_0 + MMC_ATSMB1_BASE))
-#define ATSMB1_INT_MASK_1 (REG8_PTR(_INT_MASK_1 + MMC_ATSMB1_BASE))
-#define ATSMB1_SD_STS_0 (REG8_PTR(_SD_STS_0 + MMC_ATSMB1_BASE))
-#define ATSMB1_SD_STS_1 (REG8_PTR(_SD_STS_1 + MMC_ATSMB1_BASE))
-#define ATSMB1_SD_STS_2 (REG8_PTR(_SD_STS_2 + MMC_ATSMB1_BASE))
-#define ATSMB1_SD_STS_3 (REG8_PTR(_SD_STS_3 + MMC_ATSMB1_BASE))
-
-#define ATSMB1_RSP_TOUT (REG8_PTR(_RSP_TOUT + MMC_ATSMB1_BASE))
-#define ATSMB1_CLK_SEL (REG8_PTR(_CLK_SEL + MMC_ATSMB1_BASE))
-#define ATSMB1_EXT_CTL (REG8_PTR(_EXT_CTL + MMC_ATSMB1_BASE))
-#define ATSMB1_EXT_CTL_1 (REG8_PTR(_EXT_CTL_1 + MMC_ATSMB1_BASE))
-#define ATSMB1_EXT_CTL_2 (REG8_PTR(_EXT_CTL_2 + MMC_ATSMB1_BASE))
-
-#define ATSMB1_SHDW_BLKLEN (REG16_PTR(_SHDW_BLKLEN + MMC_ATSMB1_BASE))
-#define ATSMB1_MAN_TUNE_VAL (REG8_PTR(_MAN_TUNE_VAL + MMC_ATSMB1_BASE))
-#define ATSMB1_SD_WRI_TUNE (REG8_PTR(_SD_WRI_TUNE+ MMC_ATSMB1_BASE))
-#define ATSMB1_TIMER_VAL (REG16_PTR(_TIMER_VAL + MMC_ATSMB1_BASE))
-
-
-
-/*=========================================*/
-/* SD2 PDMA related Registers */
-/*=========================================*/
-#define ATSMB2_PDMA_GCR (REG32_PTR(_PDMA_GCR + MMC_ATSMB2_BASE))
-#define ATSMB2_PDMA_IER (REG32_PTR(_PDMA_IER + MMC_ATSMB2_BASE))
-#define ATSMB2_PDMA_ISR (REG32_PTR(_PDMA_ISR + MMC_ATSMB2_BASE))
-#define ATSMB2_PDMA_DESPR (REG32_PTR(_PDMA_DESPR + MMC_ATSMB2_BASE))
-#define ATSMB2_PDMA_RBR (REG32_PTR(_PDMA_RBR + MMC_ATSMB2_BASE))
-#define ATSMB2_PDMA_DAR (REG32_PTR(_PDMA_DAR + MMC_ATSMB2_BASE))
-#define ATSMB2_PDMA_BAR (REG32_PTR(_PDMA_BAR + MMC_ATSMB2_BASE))
-#define ATSMB2_PDMA_CPR (REG32_PTR(_PDMA_CPR + MMC_ATSMB2_BASE))
-#define ATSMB2_PDMA_CCR (REG32_PTR(_PDMA_CCR + MMC_ATSMB2_BASE))
-
-
-/*=========================================*/
-/* SD2 Register pointer. */
-/*=========================================*/
-#define ATSMB2_CTL (REG8_PTR(_CTL + MMC_ATSMB2_BASE))
-#define ATSMB2_CMD_IDX (REG8_PTR(_CMD_IDX + MMC_ATSMB2_BASE))
-#define ATSMB2_RSP_TYPE (REG8_PTR(_RSP_TYPE + MMC_ATSMB2_BASE))
-#define ATSMB2_CMD_ARG (REG32_PTR(_CMD_ARG + MMC_ATSMB2_BASE))
-#define ATSMB2_BUS_MODE (REG8_PTR(_BUS_MODE + MMC_ATSMB2_BASE))
-#define ATSMB2_EXT_BUS_MODE (REG8_PTR(_EXT_BUS_MODE + MMC_ATSMB2_BASE))
-#define ATSMB2_CTL2 (REG16_PTR(_CTL2 + MMC_ATSMB2_BASE))
-#define ATSMB2_BLK_LEN (REG16_PTR(_BLK_LEN + MMC_ATSMB2_BASE))
-#define ATSMB2_BLK_CNT (REG16_PTR(_BLK_CNT + MMC_ATSMB2_BASE))
-#define ATSMB2_RSP_0 (REG8_PTR(_RSP_0 + MMC_ATSMB2_BASE))
-#define ATSMB2_RSP_1 (REG8_PTR(_RSP_1 + MMC_ATSMB2_BASE))
-#define ATSMB2_RSP_2 (REG8_PTR(_RSP_2 + MMC_ATSMB2_BASE))
-#define ATSMB2_RSP_3 (REG8_PTR(_RSP_3 + MMC_ATSMB2_BASE))
-#define ATSMB2_RSP_4 (REG8_PTR(_RSP_4 + MMC_ATSMB2_BASE))
-#define ATSMB2_RSP_5 (REG8_PTR(_RSP_5 + MMC_ATSMB2_BASE))
-#define ATSMB2_RSP_6 (REG8_PTR(_RSP_6 + MMC_ATSMB2_BASE))
-#define ATSMB2_RSP_7 (REG8_PTR(_RSP_7 + MMC_ATSMB2_BASE))
-#define ATSMB2_RSP_8 (REG8_PTR(_RSP_8 + MMC_ATSMB2_BASE))
-#define ATSMB2_RSP_9 (REG8_PTR(_RSP_9 + MMC_ATSMB2_BASE))
-#define ATSMB2_RSP_10 (REG8_PTR(_RSP_10 + MMC_ATSMB2_BASE))
-#define ATSMB2_RSP_11 (REG8_PTR(_RSP_11 + MMC_ATSMB2_BASE))
-#define ATSMB2_RSP_12 (REG8_PTR(_RSP_12 + MMC_ATSMB2_BASE))
-#define ATSMB2_RSP_13 (REG8_PTR(_RSP_13 + MMC_ATSMB2_BASE))
-#define ATSMB2_RSP_14 (REG8_PTR(_RSP_14 + MMC_ATSMB2_BASE))
-#define ATSMB2_RSP_15 (REG8_PTR(_RSP_15 + MMC_ATSMB2_BASE))
-
-#define ATSMB2_CURBLK_CNT (REG32_PTR(_CURBLK_CNT + MMC_ATSMB2_BASE))
-#define ATSMB2_INT_MASK_0 (REG8_PTR(_INT_MASK_0 + MMC_ATSMB2_BASE))
-#define ATSMB2_INT_MASK_1 (REG8_PTR(_INT_MASK_1 + MMC_ATSMB2_BASE))
-#define ATSMB2_SD_STS_0 (REG8_PTR(_SD_STS_0 + MMC_ATSMB2_BASE))
-#define ATSMB2_SD_STS_1 (REG8_PTR(_SD_STS_1 + MMC_ATSMB2_BASE))
-#define ATSMB2_SD_STS_2 (REG8_PTR(_SD_STS_2 + MMC_ATSMB2_BASE))
-#define ATSMB2_SD_STS_3 (REG8_PTR(_SD_STS_3 + MMC_ATSMB2_BASE))
-
-#define ATSMB2_RSP_TOUT (REG8_PTR(_RSP_TOUT + MMC_ATSMB2_BASE))
-#define ATSMB2_CLK_SEL (REG8_PTR(_CLK_SEL + MMC_ATSMB2_BASE))
-#define ATSMB2_EXT_CTL (REG8_PTR(_EXT_CTL + MMC_ATSMB2_BASE))
-#define ATSMB2_EXT_CTL_1 (REG8_PTR(_EXT_CTL_1 + MMC_ATSMB2_BASE))
-#define ATSMB2_EXT_CTL_2 (REG8_PTR(_EXT_CTL_2 + MMC_ATSMB2_BASE))
-
-#define ATSMB2_SHDW_BLKLEN (REG16_PTR(_SHDW_BLKLEN + MMC_ATSMB2_BASE))
-#define ATSMB2_MAN_TUNE_VAL (REG8_PTR(_MAN_TUNE_VAL + MMC_ATSMB2_BASE))
-#define ATSMB2_SD_WRI_TUNE (REG8_PTR(_SD_WRI_TUNE+ MMC_ATSMB2_BASE))
-#define ATSMB2_TIMER_VAL (REG16_PTR(_TIMER_VAL + MMC_ATSMB2_BASE))
-
-
-/*=========================================*/
-/* Register usage const*/
-/*=========================================*/
-/*================================================================================*/
-/**/
-/* SD Host Register Bit Fields*/
-/**/
-/*================================================================================*/
-/**/
-/* Control Register*/
-#define ATSMB_START 0x1
-#define ATSMB_SPISTP BIT1
-#define ATSMB_RXTX BIT2
-#define ATSMB_FFRST BIT3
-#define ATSMB_CT (BIT4|BIT5|BIT6|BIT7)
-/**/
-/* Command Index Register*/
-
-/**/
-/*Response Type Register*/
-#define ATSMB_RT (BIT0|BIT1|BIT2|BIT3)
-#define ATSMB_RY BIT4
-
-/**/
-/* Command Argument Register 0,1,2,3*/
-
-/**/
-/* Bus Mode Register*/
-#define ATSMB_SPI BIT0
-#define ATSMB_BUS_WIDTH_4 BIT1
-#define ATSMB_RW BIT2
-#define ATSMB_SPICRC BIT3
-#define ATSMB_CST BIT4
-#define ATSMB_SPICS BIT5
-#define ATSMB_SDPWR BIT6
-#define ATSMB_SFTRST BIT7
-
-/**/
-/* Block Length Register 0,1*/
-#define ATSMB_BS_L (BIT0|BIT1|BIT2|BIT3|BIT4|BIT5|BIT6|BIT7)
-#define ATSMB_BS_H (BIT8|BIT9|BIT10)
-#define ATSMB_CFD BIT4
-#define ATSMB_INTEN BIT7
-
-/**/
-/* Block Count Register 0,1*/
-
-/**/
-/* Response Register*/
-
-/**/
-/* Data Register*/
-
-/**/
-/* Interrupt Mask Register 0*/
-#define ATSMB_THIE BIT0
-#define ATSMB_TEIE BIT1
-#define ATSMB_TAIE BIT2
-#define ATSMB_RHIE BIT3
-#define ATSMB_MULTI_XFER_DONE_EN BIT4
-#define ATSMB_BLOCK_XFER_DONE_EN BIT5
-#define ATSMB_CDIE BIT6
-#define ATSMB_DEVICE_INSERT_EN BIT7
-
-/**/
-/* Interrupt Mask Register 1*/
-#define ATSMB_SDIO_EN BIT0
-#define ATSMB_RSP_DONE_EN BIT1
-#define ATSMB_RSP_TIMEOUT_EN BIT2
-#define ATSMB_AUTO_STOP_EN BIT3
-#define ATSMB_DATA_TIMEOUT_EN BIT4
-#define ATSMB_RSP_CRC_ERR_EN BIT5
-#define ATSMB_READ_CRC_ERR_EN BIT6
-#define ATSMB_WRITE_CRC_ERR_EN BIT7
-
-/**/
-/* SD Status Register 0*/
-#define ATSMB_TH BIT0
-#define ATSMB_WRITE_PROTECT BIT1 /* 1. write protected is disabled.*/
-#define ATSMB_CARD_NOT_IN_SLOT BIT2
-#define ATSMB_CARD_NOT_IN_SLOT_GPI BIT3
-#define ATSMB_MULTI_XFER_DONE BIT4
-#define ATSMB_BLOCK_XFER_DONE BIT5
-#define ATSMB_SD_CD BIT6 /* what is its purpose?*/
-#define ATSMB_DEVICE_INSERT BIT7
-
-/**/
-/* SD Status Register 1*/
-#define ATSMB_SDIO_INT BIT0
-#define ATSMB_RSP_DONE BIT1
-#define ATSMB_RSP_TIMEOUT BIT2
-#define ATSMB_AUTO_STOP BIT3
-#define ATSMB_DATA_TIMEOUT BIT4
-#define ATSMB_RSP_CRC_ERR BIT5
-#define ATSMB_READ_CRC_ERR BIT6
-#define ATSMB_WRITE_CRC_ERR BIT7
-
-/**/
-/* SD Status Register 2*/
-#define ATSMB_RSP_BUSY BIT5
-#define ATSMB_CLK_FREEZ_STS BIT6
-#define ATSMB_CLK_FREEZ_EN BIT7
-
-
-/* SD Response types*/
-#define ATMSB_TYPE_R0 0 /* NONE response*/
-#define ATMSB_TYPE_R1 1 /* Basic response format*/
-#define ATMSB_TYPE_R2 2 /* R2 response. Used by ALL_SEND_CID(CMD2),*/
-/* SEND_CID(CMD10) and SEND_CSD(CMD9)*/
-#define ATMSB_TYPE_R3 3 /* R3 response. Used by SEND_APP_OP_COND(ACMD41)*/
-#define ATMSB_TYPE_R6 6 /* R6 response. Used by SEND_RELATIVE_ADDR(CMD3)*/
-#define ATMSB_TYPE_R7 7 /* R6 response. Used by SEND_RELATIVE_ADDR(CMD3)*/
-#define ATMSB_TYPE_R1b 9
-#define ATMSB_TYPE_R5 5
-#define ATMSB_TYPE_R4 4
-
-/*
- * SD PDMA
- */
-struct SD_PDMA_REG {
- unsigned long DMA_GCR; /* Rx00 */
- unsigned long DMA_IER; /* Rx04 */
- unsigned long DMA_ISR; /* Rx08 */
- unsigned long *DMA_DESPR; /* Rx0C */
- unsigned long DMA_RBR; /* Rx10 */
- unsigned long DMA_DAR; /* Rx14 */
- unsigned long DMA_BAR; /* Rx18 */
- unsigned long DMA_CPR; /* Rx1C */
- unsigned long DMA_CCR; /* RX20 */
- unsigned long resv[5]; /* RX2C-3C */
-};
-/*
- * SD PDMA - DMA_GCR : DMA Global Control Register
- */
-#define SD_PDMA_GCR_DMA_EN 0x00000001 /* [0] -- DMA controller enable*/
-#define SD_PDMA_GCR_SOFTRESET 0x00000100 /* [8] -- Software rest*/
-
-/*
- * SD PDMA - DMA_IER : DMA Interrupt Enable Register
- */
-#define SD_PDMA_IER_INT_EN 0x00000001 /* [0] --DMA interrupt enable */
-/*
- * SD PDMA - DMA_ISR : DMA Interrupt Status Register
- */
-#define SD_PDMA_IER_INT_STS 0x00000001 /* [0] -- DMA interrupt status */
-/*
- * SD PDMA - DMA_DESPR : DMA Descriptor base address Pointer Register
- */
-
-/*
- * SD PDMA - DMA_RBR : DMA Residual Bytes Register
- */
-#define SD_PDMA_RBR_End 0x80000000 /* [0] -- DMA interrupt status */
-#define SD_PDMA_RBR_Format 0x40000000 /* [0] -- DMA interrupt status */
-/*
- * SD PDMA - DMA_DAR : DMA Data Address Register
- */
-
-/*
- * SD PDMA - DMA_BAR : DMA Rbanch Address Register
- */
-
-/*
- * SD PDMA - DMA_CPR : DMA Command Pointer Register
- */
-
-/*
- * SD PDMA - DMA_CCR : DMAContext Control Register for Channel 0
- */
-#define SD_PDMA_READ 0x00
-#define SD_PDMA_WRITE 0x01
-#define SD_PDMA_CCR_RUN 0x00000080
-#define SD_PDMA_CCR_IF_to_peripheral 0x00000000
-#define SD_PDMA_CCR_peripheral_to_IF 0x00400000
-#define SD_PDMA_CCR_EvtCode 0x0000000f
-#define SD_PDMA_CCR_Evt_no_status 0x00000000
-#define SD_PDMA_CCR_Evt_ff_underrun 0x00000001
-#define SD_PDMA_CCR_Evt_ff_overrun 0x00000002
-#define SD_PDMA_CCR_Evt_desp_read 0x00000003
-#define SD_PDMA_CCR_Evt_data_rw 0x00000004
-#define SD_PDMA_CCR_Evt_early_end 0x00000005
-#define SD_PDMA_CCR_Evt_success 0x0000000f
-
-/*
- * PDMA Descriptor short
- */
-struct SD_PDMA_DESC_S{
- unsigned long volatile ReqCount : 16; /* bit 0 -15 -Request count */
- unsigned long volatile i : 1; /* bit 16 -interrupt */
- unsigned long volatile reserve : 13; /* bit 17-29 -reserved */
- unsigned long volatile format : 1; /* bit 30 -The descriptor format */
- unsigned long volatile end : 1; /* bit 31 -End flag of descriptor list*/
- unsigned long volatile *DataBufferAddr; /* bit 31 -Data Buffer address */
-} ;
-
-/*
- * PDMA Descriptor long
- */
-struct SD_PDMA_DESC_L{
- unsigned long volatile ReqCount:16; /* bit 0-15-Request count */
- unsigned long volatile i:1; /* bit 16 -interrupt*/
- unsigned long volatile reserve:13; /* bit 17-29-reserved*/
- unsigned long volatile format:1; /* bit 30-The descriptor format */
- unsigned long volatile end:1; /* bit 31 -End flag of descriptor list*/
- unsigned long volatile *DataBufferAddr; /* bit 31-0 -Data Buffer address*/
- unsigned long volatile *BranchAddr; /* bit 31-2-Descriptor Branch address*/
- unsigned long volatile reserve0; /* bit 31-0-reserved*/
-};
-
-
-/**/
-/* DMA usage const for Rx08[Config]*/
-/**/
-#define DMA_CFG_WRITE 0x0
-#define DMA_CFG_READ 0x10000
-/*
-#define DMA_CFG_8B 0x00
-#define DMA_CFG_16B 0x01
-#define DMA_CFG_32B 0x02
-
-#define DMA_CFG_SINGLE 0x00
-#define DMA_CFG_INC4 0x10
-#define DMA_CFG_INC8 0x20
-
-#define DMA_CFG_DATA 0x100
-#define DMA_CFG_PRIVILEDGE 0x200
-#define DMA_CFG_BUFFER 0x400
-#define DMA_CFG_CACHE 0x800
-
-#define DMA_CFG_INC 0x1000
-#define DMA_CFG_READ 0x10000
-#define DMA_CFG_WRITE 0x0
-
-#define DMA_CFG_NOINT 0x0
-#define DMA_CFG_ENTCINT 0x100000
-#define DMA_CFG_ENXFERINT 0x200000
-#define DMA_CFG_ENERRINT 0x400000
-#define DMA_CFG_ENFIFOINT 0x800000
-
-//
-// DMA usage const for RxC[Control]
-//
-#define DMA_CTL_ENABLE 0x1
-#define DMA_CTL_SOFTREQ 0x10
-
-//
-// DMA usage const for Rx10[Status]
-//
-#define DMA_STS_TC 0x1
-#define DMA_STS_AHB_ERROR 0x4
-#define DMA_STS_FIFO_EMPTY 0x8
-#define DMA_STS_BULK_COMPLETE 0x2
-*/
-/*=========================================*/
-/* structure definition.*/
-/*=========================================*/
-struct atsmb_host {
- struct mmc_host *mmc;
- spinlock_t lock;
- struct resource *res;
- void *base;
- int regular_irq;
- int dma_irq;
- /* 2009/01/13 janshiue-s */
- unsigned long *DescVirAddr;
- dma_addr_t DescPhyAddr;
- unsigned int DescSize;
- unsigned long *BufVirAddr;
- dma_addr_t BufPhyAddr;
- unsigned long DmaIntMask;
- /* 2009/01/13 janshiue-s */
- struct mmc_request *mrq;
- struct mmc_command *cmd;
- struct mmc_data *data;
- u32 pwr;
- struct mmc_platform_data *plat;
- unsigned int sg_len;
- /* pio stuff */
- struct scatterlist *sg_ptr;
- unsigned int sg_off;
- unsigned int size;
- /* to support sg, we need little loops when requesting data*/
- u32 opcode;
- /*this code may different from the one in command. Eg. When we are accessing data*/
- unsigned char soft_timeout;
- void *done_data; /* completion data */
- void (*done)(void *data);/* completion function */
- int current_clock;
-
-};
-
-#define MAX_DESC_NUM 256
-
-enum WMT_SD_FUN {
- SD_MMC,
- SDIO_WIFI,
- SD_MAX_FUN
-};
-
-int atsmb_init_short_desc(unsigned long *DescAddr, unsigned int ReqCount,
- unsigned long *BufferAddr, int End);
-int atsmb_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount,
- unsigned long *BufferAddr, unsigned long *BranchAddr, int End);
-
-int atsmb1_init_short_desc(unsigned long *DescAddr, unsigned int ReqCount,
- unsigned long *BufferAddr, int End);
-int atsmb1_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount,
- unsigned long *BufferAddr, unsigned long *BranchAddr, int End);
-
-int atsmb2_init_short_desc(unsigned long *DescAddr, unsigned int ReqCount,
- unsigned long *BufferAddr, int End);
-int atsmb2_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount,
- unsigned long *BufferAddr, unsigned long *BranchAddr, int End);
-
-
-#endif /* __MMC_ATSMB_H */
diff --git a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb1.c b/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb1.c
deleted file mode 100755
index 2cfefbcd..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb1.c
+++ /dev/null
@@ -1,2405 +0,0 @@
-/*++
-linux/drivers/mmc/host/mmc_atsmb1.c
-
-Copyright (c) 2008 WonderMedia Technologies, Inc.
-
-This program is free software: you can redistribute it and/or modify it under the
-terms of the GNU General Public License as published by the Free Software Foundation,
-either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-PARTICULAR PURPOSE. See the GNU General Public License for more details.
-You should have received a copy of the GNU General Public License along with
-this program. If not, see <http://www.gnu.org/licenses/>.
-
-WonderMedia Technologies, Inc.
-10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
---*/
-
-//#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sd.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/sdio.h>
-#include <linux/completion.h>
-#include <linux/pagemap.h>
-#include <linux/dma-mapping.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/memory.h>
-#include <mach/hardware.h>
-#include <asm/scatterlist.h>
-#include <asm/sizes.h>
-#include "mmc_atsmb.h"
-//#include <mach/multicard.h>
-#include <mach/irqs.h>
-
-#define mprintk
-
-/* chcek emmc card is fist boot, 1:fisrt boot, 0:suspend/resume */
-int atsmb1_first_boot;
-#if 0
-#define DBG(host, fmt, args...) \
- pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args)
-#endif
-#define ATSMB_TIMEOUT_TIME (HZ*2)
-
-//add by jay,for modules support
-static u64 wmt_sdmmc1_dma_mask = 0xffffffffUL;
-static struct resource wmt_sdmmc1_resources[] = {
- [0] = {
- .start = SD1_SDIO_MMC_BASE_ADDR,
- .end = (SD1_SDIO_MMC_BASE_ADDR + 0x3FF),
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_SDC1,
- .end = IRQ_SDC1,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
- .start = IRQ_SDC1_DMA,
- .end = IRQ_SDC1_DMA,
- .flags = IORESOURCE_IRQ,
- },
- /*2008/10/6 RichardHsu-s*/
- [3] = {
- .start = IRQ_PMC_WAKEUP,
- .end = IRQ_PMC_WAKEUP,
- .flags = IORESOURCE_IRQ,
- },
- /*2008/10/6 RichardHsu-e*/
-};
-
-
-//
-static void atsmb1_release(struct device * dev) {}
-
-/*#ifdef CONFIG_MMC_DEBUG*/
-#define MORE_INFO
-#if 0
-#define DBG(x...) printk(KERN_ALERT x)
-#define DBGR(x...) printk(KERN_ALERT x)
-#else
-#define DBG(x...) do { } while (0)
-#define DBGR(x...) do { } while (0)
-#endif
-
-/* when Read CRC error occur, and clear read CRC error by software reset.*/
-void atsmb1_copy_reg(int direct)
-{
- static u8 CTL, CMD_IDX, RSP_TYPE, BUS_MODE, INT_MASK_0, INT_MASK_1, SD_STS_0, SD_STS_1, SD_STS_2, SD_STS_3;
- static u8 EXT_BUS_MODE, EXT_CTL_1, EXT_CTL_2, MAN_TUNE_VAL, SD_WRI_TUNE;
- static u8 RSP_0, RSP_1, RSP_2, RSP_3, RSP_4, RSP_5, RSP_6, RSP_7;
- static u8 RSP_8, RSP_9, RSP_10, RSP_11, RSP_12, RSP_13, RSP_14, RSP_15;
- static u8 RSP_TOUT, CLK_SEL, EXT_CTL;
- static u16 BLK_LEN, BLK_CNT, SHDW_BLKLEN, TIMER_VAL, CTL2;
- static u32 CMD_ARG, CURBLK_CNT;
-
- /*direct 0: copy register to memory; 1: copy memory to register.*/
- if (direct == 0) {
- CTL = *ATSMB1_CTL;
- CMD_IDX = *ATSMB1_CMD_IDX;
- RSP_TYPE = *ATSMB1_RSP_TYPE;
- CMD_ARG = *ATSMB1_CMD_ARG;
- BUS_MODE = *ATSMB1_BUS_MODE;
- EXT_BUS_MODE = *ATSMB1_EXT_BUS_MODE;
- CTL2 = *ATSMB1_CTL2;
- BLK_LEN = *ATSMB1_BLK_LEN;
- BLK_CNT = *ATSMB1_BLK_CNT;
- RSP_0 = *ATSMB1_RSP_0;
- RSP_1 = *ATSMB1_RSP_1;
- RSP_2 = *ATSMB1_RSP_2;
- RSP_3 = *ATSMB1_RSP_3;
- RSP_4 = *ATSMB1_RSP_4;
- RSP_5 = *ATSMB1_RSP_5;
- RSP_6 = *ATSMB1_RSP_6;
- RSP_7 = *ATSMB1_RSP_7;
- RSP_8 = *ATSMB1_RSP_8;
- RSP_9 = *ATSMB1_RSP_9;
- RSP_10 = *ATSMB1_RSP_10;
- RSP_11 = *ATSMB1_RSP_11;
- RSP_12 = *ATSMB1_RSP_12;
- RSP_13 = *ATSMB1_RSP_13;
- RSP_14 = *ATSMB1_RSP_14;
- RSP_15 = *ATSMB1_RSP_15;
- CURBLK_CNT = *ATSMB1_CURBLK_CNT;
- INT_MASK_0 = *ATSMB1_INT_MASK_0;
- INT_MASK_1 = *ATSMB1_INT_MASK_1;
- SD_STS_0 = *ATSMB1_SD_STS_0;
- SD_STS_1 = *ATSMB1_SD_STS_1;
- SD_STS_2 = *ATSMB1_SD_STS_2;
- SD_STS_3 = *ATSMB1_SD_STS_3;
- RSP_TOUT = *ATSMB1_RSP_TOUT;
- CLK_SEL = *ATSMB1_CLK_SEL;
- EXT_CTL = *ATSMB1_EXT_CTL;
- EXT_CTL_1 = *ATSMB1_EXT_CTL_1;
- EXT_CTL_2 = *ATSMB1_EXT_CTL_2;
- SHDW_BLKLEN = *ATSMB1_SHDW_BLKLEN;
- MAN_TUNE_VAL = *ATSMB1_MAN_TUNE_VAL;
- SD_WRI_TUNE = *ATSMB1_SD_WRI_TUNE;
- TIMER_VAL = *ATSMB1_TIMER_VAL;
- } else {
- *ATSMB1_CTL = CTL;
- *ATSMB1_CMD_IDX = CMD_IDX;
- *ATSMB1_RSP_TYPE = RSP_TYPE;
- *ATSMB1_CMD_ARG = CMD_ARG;
- *ATSMB1_BUS_MODE = BUS_MODE;
- *ATSMB1_EXT_BUS_MODE = EXT_BUS_MODE;
- *ATSMB1_CTL2 = CTL2;
- *ATSMB1_BLK_LEN = BLK_LEN;
- *ATSMB1_BLK_CNT = BLK_CNT;
- *ATSMB1_RSP_0 = RSP_0;
- *ATSMB1_RSP_1 = RSP_1;
- *ATSMB1_RSP_2 = RSP_2;
- *ATSMB1_RSP_3 = RSP_3;
- *ATSMB1_RSP_4 = RSP_4;
- *ATSMB1_RSP_5 = RSP_5;
- *ATSMB1_RSP_6 = RSP_6;
- *ATSMB1_RSP_7 = RSP_7;
- *ATSMB1_RSP_8 = RSP_8;
- *ATSMB1_RSP_9 = RSP_9;
- *ATSMB1_RSP_10 = RSP_10;
- *ATSMB1_RSP_11 = RSP_11;
- *ATSMB1_RSP_12 = RSP_12;
- *ATSMB1_RSP_13 = RSP_13;
- *ATSMB1_RSP_14 = RSP_14;
- *ATSMB1_RSP_15 = RSP_15;
- *ATSMB1_CURBLK_CNT = CURBLK_CNT;
- *ATSMB1_INT_MASK_0 = INT_MASK_0;
- *ATSMB1_INT_MASK_1 = INT_MASK_1;
- *ATSMB1_SD_STS_0 = SD_STS_0;
- *ATSMB1_SD_STS_1 = SD_STS_1;
- *ATSMB1_SD_STS_2 = SD_STS_2;
- *ATSMB1_SD_STS_3 = SD_STS_3;
- *ATSMB1_RSP_TOUT = RSP_TOUT;
- *ATSMB1_CLK_SEL = CLK_SEL;
- *ATSMB1_EXT_CTL = EXT_CTL;
- *ATSMB1_EXT_CTL_1 = EXT_CTL_1;
- *ATSMB1_EXT_CTL_2 = EXT_CTL_2;
- *ATSMB1_SHDW_BLKLEN = SHDW_BLKLEN;
- *ATSMB1_MAN_TUNE_VAL = MAN_TUNE_VAL;
- *ATSMB1_SD_WRI_TUNE = SD_WRI_TUNE;
- *ATSMB1_TIMER_VAL = TIMER_VAL;
- }
-}
-
-#if 0
-void atsmb1_dump_reg(struct atsmb_host *host)
-{
- u8 CTL, CMD_IDX, RSP_TYPE, BUS_MODE, INT_MASK_0, INT_MASK_1, SD_STS_0, SD_STS_1, SD_STS_2, SD_STS_3;
- u8 EXT_BUS_MODE, EXT_CTL_1, EXT_CTL_2, MAN_TUNE_VAL, SD_WRI_TUNE;
- u8 RSP_0, RSP_1, RSP_2, RSP_3, RSP_4, RSP_5, RSP_6, RSP_7;
- u8 RSP_8, RSP_9, RSP_10, RSP_11, RSP_12, RSP_13, RSP_14, RSP_15;
- u8 RSP_TOUT, CLK_SEL, EXT_CTL;
- u16 BLK_LEN, BLK_CNT, SHDW_BLKLEN, TIMER_VAL, CTL2;
- u32 CMD_ARG, PDMA_GCR, PDMA_IER, PDMA_ISR, PDMA_DESPR, PDMA_RBR, PDMA_DAR, PDMA_BAR, PDMA_CPR, PDMA_CCR;
- u32 CURBLK_CNT;
-
- CTL = *ATSMB1_CTL;
- CMD_IDX = *ATSMB1_CMD_IDX;
- RSP_TYPE = *ATSMB1_RSP_TYPE;
- CMD_ARG = *ATSMB1_CMD_ARG;
- BUS_MODE = *ATSMB1_BUS_MODE;
- EXT_BUS_MODE = *ATSMB1_EXT_BUS_MODE;
- CTL2 = *ATSMB1_CTL2;
- BLK_LEN = *ATSMB1_BLK_LEN;
- BLK_CNT = *ATSMB1_BLK_CNT;
- RSP_0 = *ATSMB1_RSP_0;
- RSP_1 = *ATSMB1_RSP_1;
- RSP_2 = *ATSMB1_RSP_2;
- RSP_3 = *ATSMB1_RSP_3;
- RSP_4 = *ATSMB1_RSP_4;
- RSP_5 = *ATSMB1_RSP_5;
- RSP_6 = *ATSMB1_RSP_6;
- RSP_7 = *ATSMB1_RSP_7;
- RSP_8 = *ATSMB1_RSP_8;
- RSP_9 = *ATSMB1_RSP_9;
- RSP_10 = *ATSMB1_RSP_10;
- RSP_11 = *ATSMB1_RSP_11;
- RSP_12 = *ATSMB1_RSP_12;
- RSP_13 = *ATSMB1_RSP_13;
- RSP_14 = *ATSMB1_RSP_14;
- RSP_15 = *ATSMB1_RSP_15;
- CURBLK_CNT = *ATSMB1_CURBLK_CNT;
- INT_MASK_0 = *ATSMB1_INT_MASK_0;
- INT_MASK_1 = *ATSMB1_INT_MASK_1;
- SD_STS_0 = *ATSMB1_SD_STS_0;
- SD_STS_1 = *ATSMB1_SD_STS_1;
- SD_STS_2 = *ATSMB1_SD_STS_2;
- SD_STS_3 = *ATSMB1_SD_STS_3;
- RSP_TOUT = *ATSMB1_RSP_TOUT;
- CLK_SEL = *ATSMB1_CLK_SEL;
- EXT_CTL = *ATSMB1_EXT_CTL;
- EXT_CTL_1 = *ATSMB1_EXT_CTL_1;
- EXT_CTL_2 = *ATSMB1_EXT_CTL_2;
- SHDW_BLKLEN = *ATSMB1_SHDW_BLKLEN;
- MAN_TUNE_VAL = *ATSMB1_MAN_TUNE_VAL;
- SD_WRI_TUNE = *ATSMB1_SD_WRI_TUNE;
- TIMER_VAL = *ATSMB1_TIMER_VAL;
-
- PDMA_GCR = *ATSMB1_PDMA_GCR;
- PDMA_IER = *ATSMB1_PDMA_IER;
- PDMA_ISR = *ATSMB1_PDMA_ISR;
- PDMA_DESPR = *ATSMB1_PDMA_DESPR;
- PDMA_RBR = *ATSMB1_PDMA_RBR;
- PDMA_DAR = *ATSMB1_PDMA_DAR;
- PDMA_BAR = *ATSMB1_PDMA_BAR;
- PDMA_CPR = *ATSMB1_PDMA_CPR;
- PDMA_CCR = *ATSMB1_PDMA_CCR;
-
- DBGR("\n+---------------------------Registers----------------------------+\n");
-
- DBGR("%16s = 0x%8x |", "CTL", CTL);
- DBGR("%16s = 0x%8x\n", "CMD_IDX", CMD_IDX);
-
- DBGR("%16s = 0x%8x |", "RSP_TYPE", RSP_TYPE);
- DBGR("%16s = 0x%8x\n", "CMD_ARG", CMD_ARG);
-
- DBGR("%16s = 0x%8x |", "BUS_MODE", BUS_MODE);
- DBGR("%16s = 0x%8x\n", "EXT_BUS_MODE", EXT_BUS_MODE);
-
- DBGR("%16s = 0x%8x |", "CTL2", CTL2);
- DBGR("%16s = 0x%8x\n", "BLK_LEN", BLK_LEN);
-
- DBGR("%16s = 0x%8x |", "BLK_CNT", BLK_CNT);
- DBGR("%16s = 0x%8x\n", "RSP_0", RSP_0);
-
- DBGR("%16s = 0x%8x |", "RSP_1", RSP_1);
- DBGR("%16s = 0x%8x\n", "RSP_2", RSP_2);
-
- DBGR("%16s = 0x%8x |", "RSP_3", RSP_3);
- DBGR("%16s = 0x%8x\n", "RSP_4", RSP_4);
-
- DBGR("%16s = 0x%8x |", "RSP_5", RSP_5);
- DBGR("%16s = 0x%8x\n", "RSP_6", RSP_6);
-
- DBGR("%16s = 0x%8x |", "RSP_7", RSP_7);
- DBGR("%16s = 0x%8x\n", "RSP_8", RSP_8);
-
- DBGR("%16s = 0x%8x |", "RSP_9", RSP_9);
- DBGR("%16s = 0x%8x\n", "RSP_10", RSP_10);
-
- DBGR("%16s = 0x%8x |", "RSP_11", RSP_11);
- DBGR("%16s = 0x%8x\n", "RSP_12", RSP_12);
-
- DBGR("%16s = 0x%8x |", "RSP_13", RSP_13);
- DBGR("%16s = 0x%8x\n", "RSP_14", RSP_14);
-
- DBGR("%16s = 0x%8x\n", "RSP_15", RSP_15);
-
- DBGR("%16s = 0x%8x |", "CURBLK_CNT", CURBLK_CNT);
- DBGR("%16s = 0x%8x\n", "INT_MASK_0", INT_MASK_0);
-
- DBGR("%16s = 0x%8x |", "INT_MASK_1", INT_MASK_1);
- DBGR("%16s = 0x%8x\n", "SD_STS_0", SD_STS_0);
-
- DBGR("%16s = 0x%8x |", "SD_STS_1", SD_STS_1);
- DBGR("%16s = 0x%8x\n", "SD_STS_2", SD_STS_2);
-
- DBGR("%16s = 0x%8x |", "SD_STS_3", SD_STS_3);
- DBGR("%16s = 0x%8x\n", "RSP_TOUT", RSP_TOUT);
-
- DBGR("%16s = 0x%8x |", "CLK_SEL", CLK_SEL);
- DBGR("%16s = 0x%8x\n", "EXT_CTL", EXT_CTL);
-
- DBGR("%16s = 0x%8x |", "EXT_CTL_1", EXT_CTL_1);
- DBGR("%16s = 0x%8x\n", "EXT_CTL_2", EXT_CTL_2);
-
- DBGR("%16s = 0x%8x |", "SHDW_BLKLEN", SHDW_BLKLEN);
- DBGR("%16s = 0x%8x\n", "MAN_TUNE_VAL", MAN_TUNE_VAL);
-
- DBGR("%16s = 0x%8x |", "SD_WRI_TUNE", SD_WRI_TUNE);
- DBGR("%16s = 0x%8x\n", "TIMER_VAL", TIMER_VAL);
-
- DBGR("%16s = 0x%8x |", "PDMA_GCR", PDMA_GCR);
- DBGR("%16s = 0x%8x\n", "PDMA_IER", PDMA_IER);
-
- DBGR("%16s = 0x%8x |", "PDMA_ISR", PDMA_ISR);
- DBGR("%16s = 0x%8x\n", "PDMA_DESPR", PDMA_DESPR);
-
- DBGR("%16s = 0x%8x |", "PDMA_RBR", PDMA_RBR);
- DBGR("%16s = 0x%8x\n", "PDMA_DAR", PDMA_DAR);
-
- DBGR("%16s = 0x%8x |", "PDMA_BAR", PDMA_BAR);
- DBGR("%16s = 0x%8x\n", "PDMA_CPR", PDMA_CPR);
-
- DBGR("%16s = 0x%8x |", "PDMA_CCR", PDMA_CCR);
- DBGR("\n+----------------------------------------------------------------+\n");
-}
-#else
-void atsmb1_dump_reg(struct atsmb_host *host) {}
-#endif
-
-unsigned int fmax1 = 515633;
-unsigned int MMC1_DRIVER_VERSION;
-int SD1_function = 0; /*0: normal SD/MMC card reader*/
-int SDXC1_function;
-
-
-int SCC1_ID(void){
- unsigned short val;
-
- val = REG16_VAL(SYSTEM_CFG_CTRL_BASE_ADDR + 0x2);
- return val;
-}
-
-int get_chip_version1(void) /*2008/05/01 janshiue modify for A1 chip*/
-{
- u32 tmp;
-
- tmp = REG32_VAL(SYSTEM_CFG_CTRL_BASE_ADDR);
- tmp = ((tmp & 0xF00) >> 4) + 0x90 + ((tmp & 0xFF) - 1);
- return tmp;
-}
-
-void get_driver_version1(void)
-{
- if (SCC1_ID() == 0x3426) {
- if (get_chip_version1() < 0xA1)
- MMC1_DRIVER_VERSION = MMC_DRV_3426_A0;
- else if (get_chip_version1() == 0xA1)
- MMC1_DRIVER_VERSION = MMC_DRV_3426_A1;
- else
- MMC1_DRIVER_VERSION = MMC_DRV_3426_A2;
- } else if (SCC1_ID() == 0x3437) {
- if (get_chip_version1() < 0xA1)
- MMC1_DRIVER_VERSION = MMC_DRV_3437_A0;
- else
- MMC1_DRIVER_VERSION = MMC_DRV_3437_A1;
- } else if (SCC1_ID() == 0x3429) {
- MMC1_DRIVER_VERSION = MMC_DRV_3429;
- } else if (SCC1_ID() == 0x3451) {
- if (get_chip_version1() < 0xA1)
- MMC1_DRIVER_VERSION = MMC_DRV_3451_A0;
- } else if (SCC1_ID() == 0x3465) {
- MMC1_DRIVER_VERSION = MMC_DRV_3465;
- } else if (SCC1_ID() == 0x3445) {
- MMC1_DRIVER_VERSION = MMC_DRV_3445;
- } else if (SCC1_ID() == 0x3481) {
- MMC1_DRIVER_VERSION = MMC_DRV_3481;
- } else if (SCC1_ID() == 0x3498) {
- MMC1_DRIVER_VERSION = MMC_DRV_3498;
- }
-}
-/*2008/10/6 RichardHsu-e*/
-
-/**********************************************************************
-Name : atsmb1_alloc_desc
-Function : To config PDMA descriptor setting.
-Calls :
-Called by :
-Parameter :
-Author : Janshiue Wu
-History :
-***********************************************************************/
-static inline int atsmb1_alloc_desc(struct atsmb_host *host,
- unsigned int bytes)
-{
- void *DescPool = NULL;
- DBG("[%s] s\n",__func__);
-
- DescPool = dma_alloc_coherent(host->mmc->parent, bytes, &(host->DescPhyAddr), GFP_KERNEL);
- if (!DescPool) {
- DBG("can't allocal desc pool=%8X %8X\n", DescPool, host->DescPhyAddr);
- DBG("[%s] e1\n",__func__);
- return -1;
- }
- DBG("allocal desc pool=%8X %8X\n", DescPool, host->DescPhyAddr);
- host->DescVirAddr = (unsigned long *)DescPool;
- host->DescSize = bytes;
- DBG("[%s] e2\n",__func__);
- return 0;
-}
-
-/**********************************************************************
-Name : atsmb1_config_desc
-Function : To config PDMA descriptor setting.
-Calls :
-Called by :
-Parameter :
-Author : Janshiue Wu
-History :
-***********************************************************************/
-static inline void atsmb1_config_desc(unsigned long *DescAddr,
- unsigned long *BufferAddr,
- unsigned long Blk_Cnt)
-{
-
- int i = 0 ;
- unsigned long *CurDes = DescAddr;
- DBG("[%s] s\n",__func__);
-
- /* the first Descriptor store for 1 Block data
- * (512 bytes)
- */
- for (i = 0 ; i < 3 ; i++) {
- atsmb1_init_short_desc(CurDes, 0x80, BufferAddr, 0);
- BufferAddr += 0x20;
- CurDes += sizeof(struct SD_PDMA_DESC_S)/4;
- }
- if (Blk_Cnt > 1) {
- atsmb1_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 0);
- BufferAddr += 0x20;
- CurDes += sizeof(struct SD_PDMA_DESC_L)/4;
- /* the following Descriptor store the rest Blocks data
- * (Blk_Cnt - 1) * 512 bytes
- */
- atsmb1_init_long_desc(CurDes, (Blk_Cnt - 1) * 512,
- BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 1);
- } else {
- atsmb1_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 1);
- }
- DBG("[%s] e\n",__func__);
-}
-/**********************************************************************
-Name : atsmb1_config_dma
-Function : To set des/src address, byte count to transfer, and DMA channel settings,
- and DMA ctrl. register.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static inline void atsmb1_config_dma(unsigned long config_dir,
- unsigned long dma_mask,
- struct atsmb_host *host)
-{
- DBG("[%s] s\n",__func__);
-
- /* Enable DMA */
- *ATSMB1_PDMA_GCR = SD_PDMA_GCR_DMA_EN;
- *ATSMB1_PDMA_GCR = SD_PDMA_GCR_SOFTRESET;
- *ATSMB1_PDMA_GCR = SD_PDMA_GCR_DMA_EN;
- /*open interrupt*/
- *ATSMB1_PDMA_IER = SD_PDMA_IER_INT_EN;
- /*Make sure host could co-work with DMA*/
- *ATSMB1_SD_STS_2 |= ATSMB_CLK_FREEZ_EN;
- /*Set timer timeout value*/
-
- /*If clock is 390KHz*/
- if (host->current_clock < 400000)
- *ATSMB1_TIMER_VAL = 0x200; /*1024*512*(1/390K) second*/
- else
- *ATSMB1_TIMER_VAL = 0x1fff; /*why not to be 0xffff?*/
-
- /*clear all DMA INT status for safety*/
- *ATSMB1_PDMA_ISR |= SD_PDMA_IER_INT_STS;
-
- /* hook desc */
- *ATSMB1_PDMA_DESPR = host->DescPhyAddr;
- if (config_dir == DMA_CFG_WRITE)
- *ATSMB1_PDMA_CCR &= SD_PDMA_CCR_IF_to_peripheral;
- else
- *ATSMB1_PDMA_CCR |= SD_PDMA_CCR_peripheral_to_IF;
-
- host->DmaIntMask = dma_mask; /*save success event*/
-
- *ATSMB1_PDMA_CCR |= SD_PDMA_CCR_RUN;
- DBG("[%s] e\n",__func__);
-}
-
-/**********************************************************************
-Name : atsmb1_prep_cmd
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static inline void atsmb1_prep_cmd(struct atsmb_host *host,
- u32 opcode,
- u32 arg,
- unsigned int flags,
- u16 blk_len,
- u16 blk_cnt,
- unsigned char int_maks_0,
- unsigned char int_mask_1,
- unsigned char cmd_type,
- unsigned char op)
-{
- DBG("[%s] s\n",__func__);
-
- /*set cmd operation code and arguments.*/
- host->opcode = opcode;
- *ATSMB1_CMD_IDX = opcode; /* host->opcode is set for further use in ISR.*/
- *ATSMB1_CMD_ARG = arg;
-
-#if 0 /* Fixme to support SPI mode, James Tian*/
- if ((flags && MMC_RSP_NONE) == MMC_RSP_NONE)
- *ATSMB1_RSP_TYPE = ATMSB_TYPE_R0;
- else if ((flags && MMC_RSP_R1) == MMC_RSP_R1)
- *ATSMB1_RSP_TYPE = ATMSB_TYPE_R1;
- else if ((flags && MMC_RSP_R1B) == MMC_RSP_R1B)
- *ATSMB1_RSP_TYPE = ATMSB_TYPE_R1b;
- else if ((flags && MMC_RSP_R2) == MMC_RSP_R2)
- *ATSMB1_RSP_TYPE = ATMSB_TYPE_R2;
- else if ((flags && MMC_RSP_R3) == MMC_RSP_R3)
- *ATSMB1_RSP_TYPE = ATMSB_TYPE_R3;
- else if ((flags && MMC_RSP_R6) == MMC_RSP_R6)
- *ATSMB1_RSP_TYPE = ((opcode != SD_SEND_IF_COND) ? ATMSB_TYPE_R6 : ATMSB_TYPE_R7);
- else
- *ATSMB1_RSP_TYPE = ATMSB_TYPE_R0;
-#endif
-
-#if 1
- /*set cmd response type*/
- switch (flags) {
- case MMC_RSP_NONE | MMC_CMD_AC:
- case MMC_RSP_NONE | MMC_CMD_BC:
- *ATSMB1_RSP_TYPE = ATMSB_TYPE_R0;
- break;
- case MMC_RSP_R1 | MMC_CMD_ADTC:
- case MMC_RSP_R1 | MMC_CMD_AC:
- *ATSMB1_RSP_TYPE = ATMSB_TYPE_R1;
- break;
- case MMC_RSP_R1B | MMC_CMD_AC:
- *ATSMB1_RSP_TYPE = ATMSB_TYPE_R1b;
- break;
- case MMC_RSP_R2 | MMC_CMD_BCR:
- case MMC_RSP_R2 | MMC_CMD_AC:
- *ATSMB1_RSP_TYPE = ATMSB_TYPE_R2;
- break;
- case MMC_RSP_R3 | MMC_CMD_BCR:
- *ATSMB1_RSP_TYPE = ATMSB_TYPE_R3;
- break;
- case MMC_RSP_R6 | MMC_CMD_BCR: /*MMC_RSP_R6 = MMC_RSP_R7.*/
- *ATSMB1_RSP_TYPE = ((opcode != SD_SEND_IF_COND) ?
- ATMSB_TYPE_R6 : ATMSB_TYPE_R7);
- break;
- case MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC:
- case MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC:
- *ATSMB1_RSP_TYPE = ATMSB_TYPE_R5;
- break;
- case MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR:
- *ATSMB1_RSP_TYPE = ATMSB_TYPE_R4;
- break;
- default:
- *ATSMB1_RSP_TYPE = ATMSB_TYPE_R0;
- break;
- }
-#endif
- /*SDIO cmd 52 , 53*/
- if ((opcode == SD_IO_RW_DIRECT) ||
- (opcode == SD_IO_RW_EXTENDED)) {
- *ATSMB1_RSP_TYPE = ATMSB_TYPE_R5;
- *ATSMB1_RSP_TYPE |= BIT6;
- }
- /*SDIO cmd 5*/
- if ((opcode == SD_IO_SEND_OP_COND) &&
- ((flags & (MMC_RSP_PRESENT|
- MMC_RSP_136|
- MMC_RSP_CRC|
- MMC_RSP_BUSY|
- MMC_RSP_OPCODE)) == MMC_RSP_R4)) {
- *ATSMB1_RSP_TYPE = ATMSB_TYPE_R4;
- *ATSMB1_RSP_TYPE |= BIT6;
- }
-
- /*reset Response FIFO*/
- *ATSMB1_CTL |= 0x08;
-
- /* SD Host enable Clock */
- *ATSMB1_BUS_MODE |= ATSMB_CST;
-
- /*Set Cmd-Rsp Timeout to be maximum value.*/
- *ATSMB1_RSP_TOUT = 0xFE;
-
- /*clear all status registers for safety*/
- *ATSMB1_SD_STS_0 |= 0xff;
- *ATSMB1_SD_STS_1 |= 0xff;
- *ATSMB1_SD_STS_2 |= 0xff;
- //*ATSMB1_SD_STS_2 |= 0x7f;
- *ATSMB1_SD_STS_3 |= 0xff;
-
- //set block length and block count for cmd requesting data
- *ATSMB1_BLK_LEN &=~(0x07ff);
- *ATSMB1_BLK_LEN |= blk_len;
- //*ATSMB1_SHDW_BLKLEN = blk_len;
- *ATSMB1_BLK_CNT = blk_cnt;
-
-
- *ATSMB1_INT_MASK_0 |= int_maks_0;
- *ATSMB1_INT_MASK_1 |= int_mask_1;
-
- //Set Auto stop for Multi-block access
- if(cmd_type == 3 || cmd_type == 4)
- {
- //auto stop command set.
- *ATSMB1_EXT_CTL |= 0x01;
-
-/*
- * Enable transaction abort.
- * When CRC error occurs, CMD 12 would be automatically issued.
- * That is why we cannot enable R/W CRC error INTs.
- * If we enable CRC error INT, we would handle this INT in ISR and then issue CMD 12 via software.
- */
- *ATSMB1_BLK_LEN |= 0x0800;
- }
-
- /*Set read or write*/
- if (op == 1)
- *ATSMB1_CTL &= ~(0x04);
- else if (op == 2)
- *ATSMB1_CTL |= 0x04;
-
- /*for Non data access command, command type is 0.*/
- *ATSMB1_CTL &= 0x0F;
- *ATSMB1_CTL |= (cmd_type<<4);
- DBG("[%s] e\n",__func__);
-}
-
-static inline void atsmb1_issue_cmd(void)
-{
- *ATSMB1_CTL |= ATSMB_START;
- wmb();
-}
-/**********************************************************************
-Name : atsmb1_request_end
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static void
-atsmb1_request_end(struct atsmb_host *host, struct mmc_request *mrq)
-{
- DBG("[%s] s\n",__func__);
- /*
- * Need to drop the host lock here; mmc_request_done may call
- * back into the driver...
- */
- spin_unlock(&host->lock);
- /*DBG("100");*/
- mmc_request_done(host->mmc, mrq);
- /*DBG("101\n");*/
- spin_lock(&host->lock);
- DBG("[%s] e\n",__func__);
-}
-
-/**********************************************************************
-Name : atsmb1_data_done
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-void atsmb1_wait_done(void *data)
-{
- struct atsmb_host *host = (struct atsmb_host *) data;
- DBG("[%s] s\n",__func__);
-
- WARN_ON(host->done_data == NULL);
- complete(host->done_data);
- host->done_data = NULL;
- host->done = NULL;
- DBG("[%s] e\n",__func__);
-}
-
-/**********************************************************************
-Name : atsmb1_start_data
-Function : If we start data, there must be only four cases.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static void atsmb1_start_data(struct atsmb_host *host)
-{
- DECLARE_COMPLETION(complete);
- unsigned char cmd_type = 0;
- unsigned char op = 0; /*0: non-operation; 1:read; 2: write*/
- unsigned char mask_0 = 0;
- unsigned char mask_1 = 0;
- unsigned long dma_mask = 0;
-
- struct mmc_data *data = host->data;
- struct mmc_command *cmd = host->cmd;
-
- struct scatterlist *sg = NULL;
- unsigned int sg_len = 0;
-
- unsigned int total_blks = 0; /*total block number to transfer*/
- u32 card_addr = 0;
- unsigned long dma_len = 0;
- unsigned long total_dma_len = 0;
- dma_addr_t dma_phy = 0; /* physical address used for DMA*/
- unsigned int dma_times = 0; /*times dma need to transfer*/
- unsigned int dma_loop = 0;
- unsigned int sg_num = 0;
- int loop_cnt = 10000;
- unsigned int sg_transfer_len = 0; /*record each time dma transfer sg length */
-
- DBG("[%s] s\n",__func__);
- data->bytes_xfered = 0;
- cmd->error = 0;
- data->error = 0;
-
- /*for loop*/
- sg = data->sg;
- sg_len = data->sg_len;
-
- dma_times = (sg_len / MAX_DESC_NUM);
- if (sg_len % MAX_DESC_NUM)
- dma_times++;
- DBG("dma_times = %d sg_len = %d sg = %x\n", dma_times, sg_len, sg);
- card_addr = cmd->arg; /*may be it is block-addressed, or byte-addressed.*/
- total_blks = data->blocks;
- dma_map_sg(&(host->mmc->class_dev), sg, sg_len,
- ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-
-
- for (dma_loop = 1 ; dma_loop <= dma_times; dma_loop++, sg_len -= sg_transfer_len) {
- DBG("dma_loop = %d sg_len = %d sg_transfer_len = %d\n", dma_loop, sg_len, sg_transfer_len);
- if (dma_loop < dma_times)
- sg_transfer_len = MAX_DESC_NUM;
- else
- sg_transfer_len = sg_len;
- DBG("sg_transfer_len = %d\n", sg_transfer_len);
- /*
- *Firstly, check and wait till card is in the transfer state.
- *For our hardware, we can not consider
- *the card has successfully tranfered its state from data/rcv to trans,
- *when auto stop INT occurs.
- */
- loop_cnt = 10000;
- do {
- if (host->cmd->opcode == SD_IO_RW_EXTENDED)
- break;
- loop_cnt--;
- WARN_ON(loop_cnt == 0);
- host->done_data = &complete;
- host->done = &atsmb1_wait_done;
- host->soft_timeout = 1;
- atsmb1_prep_cmd(host,
- MMC_SEND_STATUS,
- (host->mmc->card->rca)<<16,
- MMC_RSP_R1 | MMC_CMD_AC,
- 0,
- 0,
- 0, /*mask_0*/
- ATSMB_RSP_DONE_EN
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN,
- 0, /*cmd type*/
- 0); /*read or write*/
- atsmb1_issue_cmd();
- DBG("%16s = 0x%8x |", "INT_MASK_1", *ATSMB1_INT_MASK_1);
- DBG("%16s = 0x%8x \n", "SD_STS_1", *ATSMB1_SD_STS_1);
- /*ISR would completes it.*/
- wait_for_completion_timeout(&complete, ATSMB_TIMEOUT_TIME);
-
- WARN_ON(host->soft_timeout == 1);
- if (host->soft_timeout == 1) {
- DBG("%s soft_timeout.\n", __func__);
- atsmb1_dump_reg(host);
- }
- if (cmd->error != MMC_ERR_NONE) {
- cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("Getting Status failed.\n");
- goto end;
- }
- } while ((cmd->resp[0] & 0x1f00) != 0x900 && loop_cnt > 0); /*wait for trans state.*/
-
- /*
- * Now, we can safely issue read/write command.
- * We can not consider this request as multi-block acess or single one via opcode,
- * as request is splitted into sgs.
- * Some sgs may be single one, some sgs may be multi one.
- */
-
- dma_phy = sg_dma_address(sg);
- dma_len = sg_dma_len(sg);
- DBG("dma_len = %d data->blksz = %d sg_len = %d\n", dma_len, data->blksz, sg_len);
- /*SDIO read/write*/
- if (host->cmd->opcode == SD_IO_RW_EXTENDED) {
- /*Single Block read/write*/
- if ((dma_len / (data->blksz)) == 1 && (sg_len == 1)) {
- /* read operation*/
- if (data->flags & MMC_DATA_READ) {
- host->opcode = SD_IO_RW_EXTENDED;
- cmd_type = 2;
- op = 1;
- mask_0 = 0; /*BLOCK_XFER_DONE INT skipped, we use DMA TC INT*/
- mask_1 = (//ATSMB_SDIO_EN
- ATSMB_READ_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = SD_PDMA_CCR_Evt_success;
- DBG("[%s]SR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
- __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
- } else {
- /* write operation*/
- host->opcode = SD_IO_RW_EXTENDED;
- cmd_type = 1;
- op = 2;
- /*====That is what we want===== DMA TC INT skipped*/
- mask_0 = ATSMB_BLOCK_XFER_DONE_EN;
- mask_1 = (//ATSMB_SDIO_EN
- ATSMB_WRITE_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = 0;
- DBG("[%s]SW opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
- __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
- }
- } else {
- /*Multiple Block read/write*/
- /* read operation*/
- if (data->flags & MMC_DATA_READ) {
- host->opcode = SD_IO_RW_EXTENDED;
- cmd_type = 6;
- op = 1;
- mask_0 = 0; /*MULTI_XFER_DONE_EN skipped*/
- mask_1 = (//ATSMB_SDIO_EN /*====That is what we want=====*/
- ATSMB_READ_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = SD_PDMA_CCR_Evt_success;
- DBG("[%s]MR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
- __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
- } else {
- /* write operation*/
- host->opcode = SD_IO_RW_EXTENDED;
- cmd_type = 5;
- op = 2;
- mask_0 = ATSMB_MULTI_XFER_DONE_EN;//ATSMB_BLOCK_XFER_DONE_EN; /*MULTI_XFER_DONE INT skipped*/
- mask_1 = (//ATSMB_SDIO_EN /*====That is what we want=====*/
- ATSMB_WRITE_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = 0;
- DBG("[%s]MR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
- __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
- }
- }
-
- } else {
- if ((dma_len / (data->blksz)) == 1 && (sg_len == 1)) {
- if (data->flags & MMC_DATA_READ) {/* read operation*/
- host->opcode = MMC_READ_SINGLE_BLOCK;
- cmd_type = 2;
- op = 1;
- mask_0 = 0; /*BLOCK_XFER_DONE INT skipped, we use DMA TC INT*/
- mask_1 = (ATSMB_READ_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = SD_PDMA_CCR_Evt_success;
- } else {/*write operation*/
- host->opcode = MMC_WRITE_BLOCK;
- cmd_type = 1;
- op = 2;
- /*====That is what we want===== DMA TC INT skipped*/
- mask_0 = ATSMB_BLOCK_XFER_DONE_EN;
- mask_1 = (ATSMB_WRITE_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = 0;
- }
- } else { /*more than one*/
- if (data->flags&MMC_DATA_READ) {/* read operation*/
- host->opcode = MMC_READ_MULTIPLE_BLOCK;
- cmd_type = 4;
- op = 1;
- mask_0 = 0; /*MULTI_XFER_DONE_EN skipped*/
- mask_1 = (ATSMB_AUTO_STOP_EN /*====That is what we want=====*/
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = 0;
- } else {/*write operation*/
- host->opcode = MMC_WRITE_MULTIPLE_BLOCK;
- cmd_type = 3;
- op = 2;
- mask_0 = 0; /*MULTI_XFER_DONE INT skipped*/
- mask_1 = (ATSMB_AUTO_STOP_EN /*====That is what we want=====*/
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = 0;
- }
- }
- }
- /*To controller every sg done*/
- host->done_data = &complete;
- host->done = &atsmb1_wait_done;
- /*sleep till ISR wakes us*/
- host->soft_timeout = 1; /*If INT comes early than software timer, it would be cleared.*/
-
- total_dma_len = 0;
- DBG("host->DescVirAddr = %x host->DescSize=%x\n", host->DescVirAddr, host->DescSize);
- memset(host->DescVirAddr, 0, host->DescSize);
- for (sg_num = 0 ; sg_num < sg_transfer_len ; sg++, sg_num++) {
-
- /*
- * Now, we can safely issue read/write command.
- * We can not consider this request as multi-block acess or single one via opcode,
- * as request is splitted into sgs.
- * Some sgs may be single one, some sgs may be multi one.
- */
-
- dma_phy = sg_dma_address(sg);
- dma_len = sg_dma_len(sg);
- total_dma_len = total_dma_len + dma_len;
- DBG("sg_num=%d sg_transfer_len=%d sg=%x sg_len=%d total_dma_len=%d dma_len=%d\n",
- sg_num, sg_transfer_len, sg, sg_len, total_dma_len, dma_len);
- /*2009/01/15 janshiue add*/
- if (sg_num < sg_transfer_len - 1) {
- /* means the last descporitor */
- atsmb1_init_short_desc(
- host->DescVirAddr + (sg_num * sizeof(struct SD_PDMA_DESC_S)/4),
- dma_len, (unsigned long *)dma_phy, 0);
- } else {
- atsmb1_init_short_desc(
- host->DescVirAddr + (sg_num * sizeof(struct SD_PDMA_DESC_S)/4),
- dma_len, (unsigned long *)dma_phy, 1);
- }
- /*2009/01/15 janshiue add*/
-
- }
- /*operate our hardware*/
- atsmb1_prep_cmd(host,
- host->opcode,
- /*arg, may be byte addressed, may be block addressed.*/
- card_addr,
- cmd->flags,
- data->blksz - 1, /* in fact, it is useless.*/
- /* for single one, it is useless. but for multi one, */
- /* it would be used to tell auto stop function whether it is done.*/
- total_dma_len/(data->blksz),
- mask_0,
- mask_1,
- cmd_type,
- op);
-
- atsmb1_config_dma((op == 1) ? DMA_CFG_READ : DMA_CFG_WRITE,
- dma_mask,
- host);
-
- atsmb1_issue_cmd();
- wait_for_completion_timeout(&complete,
- ATSMB_TIMEOUT_TIME*sg_transfer_len); /*ISR would completes it.*/
-
- /* When the address of request plus length equal card bound,
- * force this stop command response as pass. Eason 2012/4/20 */
- if (cmd->resp[0] == 0x80000b00) {
- /*This caes used for SD2.0 and after MMC4.1 version*/
- if (card_addr+(total_dma_len/data->blksz) == host->mmc->card->csd.capacity) {
- cmd->resp[0] = 0x00000b00;
- /*printk("card_addr = %08X, card_length = %08X,card capacity = %08X\n",
- card_addr,(total_dma_len/data->blksz),host->mmc->card->csd.capacity);
- printk("card_resp[0]=%08X, addr = %08X\n",cmd->resp[0],cmd->resp);*/
- }
-
- /* This caes used for SD1.0 and before MMC 4.1 */
- if ((card_addr/data->blksz)+(total_dma_len/data->blksz) == host->mmc->card->csd.capacity) {
- cmd->resp[0] = 0x00000b00;
- /*printk("Eason test: cmd->arg = %08X, data->blksz = %08X, length = %08X\n",
- card_addr,data->blksz,(total_dma_len/data->blksz));*/
- }
- }
-
- if (host->soft_timeout == 1) {
- atsmb1_dump_reg(host);
- //*ATSMB1_BUS_MODE |= ATSMB_SFTRST;
- *ATSMB1_PDMA_GCR = SD_PDMA_GCR_SOFTRESET;
- /*disable INT */
- *ATSMB1_INT_MASK_0 &= ~(ATSMB_BLOCK_XFER_DONE_EN | ATSMB_MULTI_XFER_DONE_EN);
- *ATSMB1_INT_MASK_1 &= ~(ATSMB_WRITE_CRC_ERR_EN|ATSMB_READ_CRC_ERR_EN|ATSMB_RSP_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN|ATSMB_AUTO_STOP_EN|ATSMB_RSP_TIMEOUT_EN|ATSMB_RSP_DONE_EN);
-
- cmd->error = -ETIMEDOUT;
- data->error = -ETIMEDOUT;
- }
-
- WARN_ON(host->soft_timeout == 1);
-
- /*check everything goes okay or not*/
- if (cmd->error != MMC_ERR_NONE
- || data->error != MMC_ERR_NONE) {
- DBG("CMD or Data failed error=%X DescVirAddr=%8X dma_phy=%8X dma_mask = %x\n",
- cmd->error, host->DescVirAddr, dma_phy, host->DmaIntMask);
- goto end;
- }
-// card_addr += total_dma_len>>(mmc_card_blockaddr(host->mmc->card_selected) ? 9 : 0);
- card_addr += total_dma_len>>(mmc_card_blockaddr(host->mmc->card) ? 9 : 0); //zhf: modified by James Tian
- data->bytes_xfered += total_dma_len;
-
-
- }
-// dma_unmap_sg(&(host->mmc->class_dev), data->sg, data->sg_len,
-// ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
- WARN_ON(total_blks != (data->bytes_xfered / data->blksz));
- host->opcode = 0;
-end:
- dma_unmap_sg(&(host->mmc->class_dev), data->sg, data->sg_len,
- ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
- spin_lock(&host->lock);
- atsmb1_request_end(host, host->mrq);
- spin_unlock(&host->lock);
- DBG("[%s] e\n",__func__);
-}
-
-
-/**********************************************************************
-Name : atsmb1_cmd_with_data_back
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static void atsmb1_cmd_with_data_back(struct atsmb_host *host)
-{
- DECLARE_COMPLETION(complete);
-
- struct scatterlist *sg = NULL;
- unsigned int sg_len = 0;
- DBG("[%s] s\n",__func__);
- /*for loop*/
- sg = host->data->sg;
- sg_len = host->data->sg_len;
- /*To controller every sg done*/
- host->done_data = &complete;
- host->done = &atsmb1_wait_done;
- dma_map_sg(&(host->mmc->class_dev), sg, sg_len, DMA_FROM_DEVICE);
-
- /*2009/01/15 janshiue add*/
- memset(host->DescVirAddr, 0, host->DescSize);
- atsmb1_init_long_desc(host->DescVirAddr, sg_dma_len(sg), (unsigned long *)sg_dma_address(sg), 0, 1);
- /*2009/01/15 janshiue add*/
- /*prepare for cmd*/
- atsmb1_prep_cmd(host, /*host*/
- host->cmd->opcode, /*opcode*/
- host->cmd->arg, /*arg*/
- host->cmd->flags, /*flags*/
- sg_dma_len(sg)-1, /*block length*/
- 0, /*block size: It looks like useless*/
- 0, /*int_mask_0*/
- (ATSMB_RSP_CRC_ERR_EN|ATSMB_RSP_TIMEOUT_EN
- |ATSMB_READ_CRC_ERR_EN |ATSMB_DATA_TIMEOUT_EN), /*int_mask_1*/
- 2, /*cmd_type*/
- 1); /*op*/
-
- atsmb1_config_dma(DMA_CFG_READ,
- SD_PDMA_CCR_Evt_success,
- host);
- atsmb1_issue_cmd();
- /*ISR would completes it.*/
- wait_for_completion_timeout(&complete, ATSMB_TIMEOUT_TIME);
-
- dma_unmap_sg(&(host->mmc->class_dev), host->data->sg, host->data->sg_len,
- ((host->data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-
- spin_lock(&host->lock);
- atsmb1_request_end(host, host->mrq);
- spin_unlock(&host->lock);
- DBG("[%s] e\n",__func__);
-}
-/**********************************************************************
-Name : atsmb1_start_cmd
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static void atsmb1_start_cmd(struct atsmb_host *host)
-{
- unsigned char int_mask_0,int_mask_1;
- int_mask_0 = 0;
- int_mask_1 = ATSMB_RSP_DONE_EN|ATSMB_RSP_CRC_ERR_EN|ATSMB_RSP_TIMEOUT_EN;
-
- DBG("[%s] s\n",__func__);
-
- atsmb1_prep_cmd(host,
- host->cmd->opcode,
- host->cmd->arg,
- host->cmd->flags,
- 0, /*useless*/
- 0, /*useless*/
- int_mask_0, /*mask_0*/
- int_mask_1, /*mask_1*/
- 0, /*cmd type*/
- 0); /*read or write*/
- atsmb1_issue_cmd();
- DBG("[%s] e\n",__func__);
-}
-/**********************************************************************
-Name : atsmb1_fmt_check_rsp
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static inline void atsmb1_fmt_check_rsp(struct atsmb_host *host)
-{
-
- u8 tmp_resp[4] = {0};
- int i, j, k;
- DBG("[%s] s\n",__func__);
- if (host->cmd->flags != (MMC_RSP_R2 | MMC_CMD_AC)
- && host->cmd->flags != (MMC_RSP_R2 | MMC_CMD_BCR)) {
- for (j = 0, k = 1; j < 4; j++, k++)
- tmp_resp[j] = *(REG8_PTR(_RSP_0 + MMC_ATSMB1_BASE+k));
-
- host->cmd->resp[0] = (tmp_resp[0] << 24) |
- (tmp_resp[1]<<16) | (tmp_resp[2]<<8) | (tmp_resp[3]);
- } else {
- for (i = 0, k = 1; i < 4; i++) { /*R2 has 4 u32 response.*/
- for (j = 0; j < 4; j++) {
- if (k < 16)
- tmp_resp[j] = *(REG8_PTR(_RSP_0 + MMC_ATSMB1_BASE+k));
- else /* k =16*/
- tmp_resp[j] = *(ATSMB1_RSP_0);
- k++;
- }
- host->cmd->resp[i] = (tmp_resp[0]<<24) | (tmp_resp[1]<<16) |
- (tmp_resp[2]<<8) | (tmp_resp[3]);
- }
- }
-
- /*
- * For the situation that we need response,
- * but response registers give us all zeros, we consider this operation timeout.
- */
- if (host->cmd->flags != (MMC_RSP_NONE | MMC_CMD_AC)
- && host->cmd->flags != (MMC_RSP_NONE | MMC_CMD_BC)) {
- if (host->cmd->resp[0] == 0 && host->cmd->resp[1] == 0
- && host->cmd->resp[2] == 0 && host->cmd->resp[3] == 0) {
- host->cmd->error = -ETIMEDOUT; //zhf: modified by James Tian
- }
- }
- DBG("[%s] e\n",__func__);
-}
-/**********************************************************************
-Name : atsmb1_get_slot_status
-Function : Our host only supports one slot.
-Calls :
-Called by :
-Parameter :
-returns : 1: in slot; 0: not in slot.
-Author : Leo Lee
-History :
-***********************************************************************/
-static int atsmb1_get_slot_status(struct mmc_host *mmc)
-{
-// struct atsmb_host *host = mmc_priv(mmc);
- unsigned char status_0 = 0;
-// unsigned long flags;
- unsigned long ret = 0;
- DBG("[%s] s\n",__func__);
-// spin_lock_irqsave(&host->lock, flags); // Vincent Li mark out for CONFIG_PREEMPT_RT
- status_0 = *ATSMB1_SD_STS_0;
-// spin_unlock_irqrestore(&host->lock, flags); // Vincent Li mark out for CONFIG_PREEMPT_RT
- /* after WM3400 A1 ATSMB_CARD_IN_SLOT_GPI = 1 means not in slot*/
- if (MMC1_DRIVER_VERSION >= MMC_DRV_3426_A0) {
- ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 0 : 1);
- DBG("[%s] e1\n",__func__);
- return ret;
- } else {
- ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 1 : 0);
- DBG("[%s] e2\n",__func__);
- return ret;
- }
- DBG("[%s] e3\n",__func__);
- return 0;
-}
-
-/**********************************************************************
-Name : atsmb1_init_short_desc
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Janshiue Wu
-History :
-***********************************************************************/
-int atsmb1_init_short_desc(unsigned long *DescAddr, unsigned int ReqCount, unsigned long *BufferAddr, int End)
-{
- struct SD_PDMA_DESC_S *CurDes_S;
- DBG("[%s] s\n",__func__);
- CurDes_S = (struct SD_PDMA_DESC_S *) DescAddr;
- CurDes_S->ReqCount = ReqCount;
- CurDes_S->i = 0;
- CurDes_S->format = 0;
- CurDes_S->DataBufferAddr = BufferAddr;
- if (End) {
- CurDes_S->end = 1;
- CurDes_S->i = 1;
- }
- DBG("[%s] e\n",__func__);
- return 0;
-}
-
-/**********************************************************************
-Name : atsmb_init_long_desc
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Janshiue Wu
-History :
-***********************************************************************/
-int atsmb1_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount,
- unsigned long *BufferAddr, unsigned long *BranchAddr, int End)
-{
- struct SD_PDMA_DESC_L *CurDes_L;
- DBG("[%s] s\n",__func__);
- CurDes_L = (struct SD_PDMA_DESC_L *) DescAddr;
- CurDes_L->ReqCount = ReqCount;
- CurDes_L->i = 0;
- CurDes_L->format = 1;
- CurDes_L->DataBufferAddr = BufferAddr;
- CurDes_L->BranchAddr = BranchAddr;
- if (End) {
- CurDes_L->end = 1;
- CurDes_L->i = 1;
- }
- DBG("[%s] e\n",__func__);
- return 0;
-}
-
-/**********************************************************************
-Name : atsmb1_dma_isr
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static irqreturn_t atsmb1_dma_isr(int irq, void *dev_id)
-{
-
- struct atsmb_host *host = dev_id;
- u8 status_0, status_1, status_2, status_3;
- u32 pdma_event_code = 0;
- DBG("[%s] s\n",__func__);
-
- disable_irq_nosync(irq);
- spin_lock(&host->lock);
- /*Get INT status*/
- status_0 = *ATSMB1_SD_STS_0;
- status_1 = *ATSMB1_SD_STS_1;
- status_2 = *ATSMB1_SD_STS_2;
- status_3 = *ATSMB1_SD_STS_3;
- /* after WM3426 A0 using PDMA */
- if (MMC1_DRIVER_VERSION >= MMC_DRV_3426_A0) {
-
- pdma_event_code = *ATSMB1_PDMA_CCR & SD_PDMA_CCR_EvtCode;
-
- /* clear INT status to notify HW clear EventCode*/
- *ATSMB1_PDMA_ISR |= SD_PDMA_IER_INT_STS;
-
- /*printk("dma_isr event code = %X\n", *ATSMB1_PDMA_CCR);*/
- /*We expect cmd with data sending back or read single block cmd run here.*/
- if (pdma_event_code == SD_PDMA_CCR_Evt_success) {
- /*means need to update the data->error and cmd->error*/
- if (host->DmaIntMask == SD_PDMA_CCR_Evt_success) {
- if ( host->data != NULL) {
- host->data->error = MMC_ERR_NONE;
- host->cmd->error = MMC_ERR_NONE;
- } else {
- DBG("dma_isr1 host->data is NULL\n");
- /*disable INT*/
- *ATSMB1_PDMA_IER &= ~SD_PDMA_IER_INT_EN;
- goto out;
- }
- }
- /*else do nothing*/
- DBG("dma_isr PDMA OK\n");
- /*atsmb1_dump_reg(host);*/
- }
- /*But unluckily, we should also be prepare for all kinds of error situation.*/
- else {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBGR("** dma_isr PDMA fail** event code = %X\n", *ATSMB1_PDMA_CCR);
- atsmb1_dump_reg(host);
- }
- if (host->DmaIntMask == SD_PDMA_CCR_Evt_success)
- atsmb1_fmt_check_rsp(host);
-
- /*disable INT*/
- *ATSMB1_PDMA_IER &= ~SD_PDMA_IER_INT_EN;
- }
-
- /*wake up some one who is sleeping.*/
- if ((pdma_event_code != SD_PDMA_CCR_Evt_success) || (host->DmaIntMask == SD_PDMA_CCR_Evt_success)) {
- if (host->done_data) {/* We only use done_data when requesting data.*/
- host->soft_timeout = 0;
- host->done(host);
- } else
- atsmb1_request_end(host, host->mrq); /*for cmd with data sending back.*/
- }
-
-out:
- spin_unlock(&host->lock);
- enable_irq(irq);
- DBG("[%s] e\n",__func__);
- return IRQ_HANDLED;
-}
-
-/**********************************************************************
-Name : atsmb1_regular_isr
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-//static irqreturn_t atsmb_regular_isr(int irq, void *dev_id, struct pt_regs *regs)
-irqreturn_t atsmb1_regular_isr(int irq, void *dev_id)
-{
-
- struct atsmb_host *host = dev_id;
- u8 status_0, status_1, status_2, status_3,mask_0,mask_1;
- u32 pdma_sts;
-
- DBG("[%s] s\n",__func__);
- WARN_ON(host == NULL);
-
- disable_irq_nosync(irq);
- spin_lock(&host->lock);
-
- /*Get INT status*/
- status_0 = *ATSMB1_SD_STS_0;
- status_1 = *ATSMB1_SD_STS_1;
- status_2 = *ATSMB1_SD_STS_2;
- status_3 = *ATSMB1_SD_STS_3;
-
- mask_0 = *ATSMB1_INT_MASK_0;
- mask_1 = *ATSMB1_INT_MASK_1;
- /*******************************************************
- card insert interrupt
- ********************************************************/
- if ((status_0 & ATSMB_DEVICE_INSERT) /*Status Set and IRQ enabled*/
- /*To aviod the situation that we intentionally disable IRQ to do rescan.*/
- && (*ATSMB1_INT_MASK_0 & 0x80)) {
-
- if (host->mmc->ops->get_slot_status(host->mmc)) {
- host->mmc->scan_retry = 3;
- host->mmc->card_scan_status = false;
- } else {
- host->mmc->scan_retry = 0;
- host->mmc->card_scan_status = false;
- }
-
- mmc_detect_change(host->mmc, HZ/2);
- /*Taipei Side Request: Disable INSERT IRQ when doing rescan.*/
- //*ATSMB1_INT_MASK_0 &= (~0x80);/* or 40?*/ //zhf: marked by James Tian
- /*Then we clear the INT status*/
- //iowrite32(ATSMB_DEVICE_INSERT, host->base+_SD_STS_0);
- *ATSMB1_SD_STS_0 |= ATSMB_DEVICE_INSERT;
- spin_unlock(&host->lock);
- enable_irq(irq);
- DBG("[%s] e1\n",__func__);
- return IRQ_HANDLED;
- }
-
- if ((status_1 & mask_1)& ATSMB_SDIO_INT) {
- spin_unlock(&host->lock);
- mmc_signal_sdio_irq(host->mmc);
-
- if (((status_1 & mask_1) == ATSMB_SDIO_INT) && ((status_0 & mask_0) == 0)) {
-
- enable_irq(irq);
- DBG("[%s] e2\n",__func__);
-
- return IRQ_HANDLED;
- }
- spin_lock(&host->lock);
- }
- pdma_sts = *ATSMB1_PDMA_CCR;
-
- if (((status_0 & mask_0) | (status_1 & mask_1)) == 0) {
- spin_unlock(&host->lock);
- enable_irq(irq);
- DBG("[%s] e3\n",__func__);
- return IRQ_HANDLED;
- }
- /*******************************************************
- command interrupt.
- *******************************************************/
- /*for write single block*/
- if (host->opcode == MMC_WRITE_BLOCK) {
- if ((status_0 & ATSMB_BLOCK_XFER_DONE)
- && (status_1 & ATSMB_RSP_DONE)) {
- host->data->error = MMC_ERR_NONE;
- host->cmd->error = MMC_ERR_NONE;
- /* okay, what we want.*/
- } else {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err1\n",__func__);
- atsmb1_dump_reg(host);
- }
- } else if (host->opcode == MMC_WRITE_MULTIPLE_BLOCK
- || host->opcode == MMC_READ_MULTIPLE_BLOCK) {
- if ((status_1 & (ATSMB_AUTO_STOP|ATSMB_RSP_DONE))
- && (status_0 & ATSMB_MULTI_XFER_DONE)) {
- /*If CRC error occurs, I think this INT would not occrs.*/
- /*okay, that is what we want.*/
- host->data->error = MMC_ERR_NONE;
- host->cmd->error = MMC_ERR_NONE;
- } else {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err2\n",__func__);
- atsmb1_dump_reg(host);
-
- }
- } else if (host->opcode == MMC_READ_SINGLE_BLOCK) {/* we want DMA TC, run here, must be error.*/
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err3\n",__func__);
- atsmb1_dump_reg(host);
- } else if (host->opcode == SD_IO_RW_EXTENDED){
- /*Write operation*/
- if (*ATSMB1_CTL & BIT2) {
- if ((*ATSMB1_CTL & 0xf0) == 0x10) { /*single block write*/
- if ((status_0 & ATSMB_BLOCK_XFER_DONE)
- && (status_1 & ATSMB_RSP_DONE)) {
- host->data->error = MMC_ERR_NONE;
- host->cmd->error = MMC_ERR_NONE;
- /* okay, what we want.*/
- } else {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err4 status_0 = %x status_1 = %x\n",__func__,status_0,status_1);
- }
-
- } else if ((*ATSMB1_CTL & 0xf0) == 0x50) {
- if ((status_0 & ATSMB_MULTI_XFER_DONE)
- && (status_1 & ATSMB_RSP_DONE)) {
- host->data->error = MMC_ERR_NONE;
- host->cmd->error = MMC_ERR_NONE;
- /* okay, what we want.*/
- } else {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err4-2 status_0 = %x status_1 = %x\n",__func__,status_0,status_1);
- }
- } else {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err4-3 status_0 = %x status_1 = %x\n",__func__,status_0,status_1);
- }
- }
- else {
- /*Read operation*/
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err5\n",__func__);
- }
-
-
- } else {
-/* command, not request data*/
-/* the command which need data sending back,*/
-/* like switch_function, send_ext_csd, send_scr, send_num_wr_blocks.*/
-/* NOTICE: we also send status before reading or writing data, so SEND_STATUS should be excluded.*/
- if (host->data && host->opcode != MMC_SEND_STATUS) {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err6\n",__func__);
- atsmb1_dump_reg(host);
- } else { /* Just command, no need data sending back.*/
- if (status_1 & ATSMB_RSP_DONE) {
- /*Firstly, check data-response is busy or not.*/
- if (host->cmd->flags == (MMC_RSP_R1B | MMC_CMD_AC)) {
- int i = 10000;
-
- while (status_2 & ATSMB_RSP_BUSY) {
- status_2 = *ATSMB1_SD_STS_2;
- if (--i == 0)
- break;
- DBG(" IRQ:Status_2 = %d, busy!\n", status_2);
- }
- if (i == 0)
- printk("[MMC driver] Error :SD data-response always busy!");
- }
-#if 1
-/*for our host, even no card in slot, for SEND_STATUS also returns no error.*/
-/*The protocol layer depends on SEND_STATUS to check whether card is in slot or not.*/
-/*In fact, we can also avoid this situation by checking the response whether they are all zeros.*/
- if (!atsmb1_get_slot_status(host->mmc) && host->opcode == MMC_SEND_STATUS) {
- host->cmd->retries = 0; /* No retry.*/
-// host->cmd->error = MMC_ERR_INVALID;
- host->cmd->error = -EINVAL;
- } else
-#endif
- host->cmd->error = MMC_ERR_NONE;
- } else {
- if (status_1 & ATSMB_RSP_TIMEOUT) {/* RSP_Timeout .*/
-// host->cmd->error = MMC_ERR_TIMEOUT;
- host->cmd->error = -ETIMEDOUT;
- DBG("[%s] err7\n",__func__);
- } else {/*or RSP CRC error*/
-// host->cmd->error = MMC_ERR_BADCRC;
- host->cmd->error = -EILSEQ;
- DBG("[%s] err8\n",__func__);
- }
- atsmb1_dump_reg(host);
- }
- }
- }
- atsmb1_fmt_check_rsp(host);
-
- /*disable INT */
- *ATSMB1_INT_MASK_0 &= ~(ATSMB_BLOCK_XFER_DONE_EN | ATSMB_MULTI_XFER_DONE_EN);
- *ATSMB1_INT_MASK_1 &= ~(ATSMB_WRITE_CRC_ERR_EN|ATSMB_READ_CRC_ERR_EN|ATSMB_RSP_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN|ATSMB_AUTO_STOP_EN|ATSMB_RSP_TIMEOUT_EN|ATSMB_RSP_DONE_EN);
-
-
- /*clear INT status. In fact, we will clear again before issuing new command.*/
- *ATSMB1_SD_STS_0 |= status_0;
- *ATSMB1_SD_STS_1 |= status_1;
-
- /* when read CRC error occur, and the status can't write one to clear.
- * To clear read CRC error status , can do software reset. This is HW bug. 2013/3/21*/
- if ((*ATSMB1_SD_STS_1 & BIT6) == 0x40) {
- DBG("[%s] host1 CMD%d Read CRC error occur\n",__func__,host->cmd->opcode);
- /* Save SD card register */
- atsmb1_copy_reg(0);
- /* Software reset */
- *ATSMB1_BUS_MODE |= BIT7;
- /* restore SD card register */
- atsmb1_copy_reg(1);
- }
-
- if (*ATSMB1_PDMA_ISR & SD_PDMA_IER_INT_STS)
- *ATSMB1_PDMA_ISR |= SD_PDMA_IER_INT_STS;
-
- /*wake up some one who is sleeping.*/
- if (host->done_data) { /* We only use done_data when requesting data.*/
- host->soft_timeout = 0;
- host->done(host);
- } else
- atsmb1_request_end(host, host->mrq); /*for cmd without data.*/
-
- spin_unlock(&host->lock);
- enable_irq(irq);
- DBG("[%s] e4\n",__func__);
- return IRQ_HANDLED;
-}
-EXPORT_SYMBOL(atsmb1_regular_isr);
-
-/**********************************************************************
-Name : atsmb1_get_ro
-Function :.
-Calls :
-Called by :
-Parameter :
-returns : 0 : write protection is disabled. 1: write protection is enabled.
-Author : Leo Lee
-History :
-***********************************************************************/
-int atsmb1_get_ro(struct mmc_host *mmc)
-{
- struct atsmb_host *host = mmc_priv(mmc);
- unsigned char status_0 = 0;
- unsigned long flags;
- unsigned long ret = 0;
- DBG("[%s] s\n",__func__);
- spin_lock_irqsave(&host->lock, flags);
- status_0 = *ATSMB1_SD_STS_0;
- spin_unlock_irqrestore(&host->lock, flags);
- DBG("[%s]\nstatus_0 = 0x%x\n", __func__,status_0);
- ret = ((status_0 & ATSMB_WRITE_PROTECT) ? 0 : 1);
- DBG("[%s] e\n",__func__);
- return ret;
-}
-/**********************************************************************
-Name : atsmb1_dump_host_regs
-Function :
-Calls :
-Called by :
-Parameter :
-returns :
-Author : Leo Lee
-History :
-***********************************************************************/
-void atsmb1_dump_host_regs(struct mmc_host *mmc)
-{
- struct atsmb_host *host = mmc_priv(mmc);
- DBG("[%s] s\n",__func__);
- atsmb1_dump_reg(host);
- DBG("[%s] e\n",__func__);
-}
-EXPORT_SYMBOL(atsmb1_dump_host_regs);
-
-/**********************************************************************
-Name : atsmb_enable_sdio_irq
-Function :
-Calls :
-Called by :
-Parameter :
-returns :
-Author : Tommy Huang
-History :
-***********************************************************************/
-static void atsmb1_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
- struct atsmb_host *host = mmc_priv(mmc);
- unsigned long flags;
-
- DBG("[%s] s enable = %d *ATSMB1_INT_MASK_1 = %x\n",__func__,enable,*ATSMB1_INT_MASK_1);
- spin_lock_irqsave(&host->lock, flags);
-
- if (enable) {
- *ATSMB1_INT_MASK_1 |= ATSMB_SDIO_EN;
- } else {
- *ATSMB1_INT_MASK_1 &= ~ATSMB_SDIO_EN;
- }
-
- spin_unlock_irqrestore(&host->lock, flags);
- DBG("[%s] e\n",__func__);
-
-}
-/**********************************************************************
-Name : atsmb_request
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static void atsmb1_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
-
- struct atsmb_host *host = mmc_priv(mmc);
- DBG("[%s] s\n",__func__);
-
- /* May retry process comes here.*/
- host->mrq = mrq;
- host->data = mrq->data;
- host->cmd = mrq->cmd;
- host->done_data = NULL;
- host->done = NULL;
-
- /*for data request*/
- if (host->data) {
- if (host->cmd->opcode == MMC_WRITE_BLOCK
- || host->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK
- || host->cmd->opcode == MMC_READ_SINGLE_BLOCK
- || host->cmd->opcode == MMC_READ_MULTIPLE_BLOCK
- || host->cmd->opcode == SD_IO_RW_EXTENDED) {
- atsmb1_start_data(host);
- } else {
- atsmb1_cmd_with_data_back(host);
- }
- } else {
- atsmb1_start_cmd(host);
- }
- DBG("[%s] e\n",__func__);
-}
-/**********************************************************************
-Name : atsmb1_set_clock
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Eason Chien
-History :2012/7/19
-***********************************************************************/
-static int atsmb1_set_clock(struct mmc_host *mmc, unsigned int clock)
-{
- int clock_multiplier = 1;
- DBG("clock = %u\n",clock);
-
- if (*ATSMB1_EXT_BUS_MODE & BIT4) /*Enable DDR50*/
- clock_multiplier = 2;
-
- if (clock == mmc->f_min) {
- DBG("[%s]ATSMB1 Host 400KHz\n", __func__);
- return auto_pll_divisor(DEV_SDMMC1, SET_DIV, 1, 390 * clock_multiplier);
- } else if (clock >= 50000000) {
- DBG("[%s]ATSMB1 Host 50MHz\n", __func__);
- return auto_pll_divisor(DEV_SDMMC1, SET_DIV, 2, 45 * clock_multiplier);
- } else if ((clock >= 25000000) && (clock < 50000000)) {
- DBG("[%s]ATSMB1 Host 25MHz\n", __func__);
- return auto_pll_divisor(DEV_SDMMC1, SET_DIV, 2, 24 * clock_multiplier);
- } else if ((clock >= 20000000) && (clock < 25000000)) {
- DBG("[%s]ATSMB1 Host 20MHz\n", __func__);
- return auto_pll_divisor(DEV_SDMMC1, SET_DIV, 2, 20 * clock_multiplier);
- } else {
- DBG("[%s]ATSMB1 Host 390KHz\n", __func__);
- return auto_pll_divisor(DEV_SDMMC1, SET_DIV, 1, 390 * clock_multiplier);
- }
-}
-
-/**********************************************************************
-Name : atsmb1_set_ios
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static void atsmb1_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-
- struct atsmb_host *host = mmc_priv(mmc);
- unsigned long flags;
- unsigned int strapping;
-
- DBG("[%s] s\n",__func__);
- spin_lock_irqsave(&host->lock, flags);
-
- if (ios->power_mode == MMC_POWER_OFF) {
- if (MMC1_DRIVER_VERSION == MMC_DRV_3498) {
- if (atsmb1_first_boot) {
- /*nothing to do for GPIO setting when first boot.*/
- } else {
- /* stop SD output clock */
- *ATSMB1_BUS_MODE &= ~(ATSMB_CST);
-
- /* disable SD1 Card power */
- /*set SD1 power pin as GPO pin*/
- GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL |= GPIO_SD1_POWER;
- GPIO_OC_GP14_NAND_SD1_BYTE_VAL |= GPIO_SD1_POWER;
- /*set internal pull up*/
- PULL_CTRL_GP14_NAND_BYTE_VAL |= GPIO_SD1_POWER;
- /*set internal pull enable*/
- PULL_EN_GP14_NAND_BYTE_VAL |= GPIO_SD1_POWER;
- /*disable SD1 power*/
- GPIO_OD_GP14_NAND_SD1_BYTE_VAL |= GPIO_SD1_POWER;
-
- /* Config SD1 to GPIO */
- GPIO_CTRL_GP16_NAND_SD1_BYTE_VAL |= GPIO_SD1_Data;
- GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL |= SD1_PIN;
-
- /* SD1 all pins output low */
- GPIO_OD_GP16_NAND_SD1_BYTE_VAL &= ~GPIO_SD1_Data;
- GPIO_OD_GP14_NAND_SD1_BYTE_VAL &= ~SD1_PIN;
-
- /* Config SD1 to GPIO */
- GPIO_OC_GP16_NAND_SD1_BYTE_VAL |= GPIO_SD1_Data;
- GPIO_OC_GP14_NAND_SD1_BYTE_VAL |= SD1_PIN;
-
- /*Set SD1 CMD pin pull low because SD1CMD has no gpio pin, check with Jim*/
- /*PULL_CTRL_GP14_NAND_BYTE_VAL &= ~GPIO_SD1_Command;
- PULL_EN_GP14_NAND_BYTE_VAL |= GPIO_SD1_Command;*/
- }
- }
- } else if (ios->power_mode == MMC_POWER_UP) {
- if (MMC1_DRIVER_VERSION == MMC_DRV_3498) {
- if (atsmb1_first_boot) {
- /*nothing to do for GPIO setting when first boot.*/
- } else {
- /* disable SD Card power */
- /*set SD1 power pin as GPO pin*/
- GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL |= GPIO_SD1_POWER;
- GPIO_OC_GP14_NAND_SD1_BYTE_VAL |= GPIO_SD1_POWER;
- /*set internal pull up*/
- PULL_CTRL_GP14_NAND_BYTE_VAL |= GPIO_SD1_POWER;
- /*set internal pull enable*/
- PULL_EN_GP14_NAND_BYTE_VAL |= GPIO_SD1_POWER;
- /*disable SD1 power*/
- GPIO_OD_GP14_NAND_SD1_BYTE_VAL |= GPIO_SD1_POWER;
-
- /* enable SD1 PIN share */
- PIN_SHARING_SEL_4BYTE_VAL |= GPIO_SD1_PinShare;
-
- /* do not config GPIO_SD1_CD because ISR has already run,
- * config card detect will issue ISR storm.
- */
- /* Config SD to GPIO */
- GPIO_CTRL_GP16_NAND_SD1_BYTE_VAL |= GPIO_SD1_Data;
- GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL |= SD1_PIN;
-
- /* SD all pins output low */
- GPIO_OD_GP16_NAND_SD1_BYTE_VAL &= ~GPIO_SD1_Data;
- GPIO_OD_GP14_NAND_SD1_BYTE_VAL &= ~SD1_PIN;
-
- /* Config SD to GPO */
- GPIO_OC_GP16_NAND_SD1_BYTE_VAL |= GPIO_SD1_Data;
- GPIO_OC_GP14_NAND_SD1_BYTE_VAL |= SD1_PIN;
-
- /* stop SD output clock */
- *ATSMB1_BUS_MODE &= ~ATSMB_CST;
-
- /* Pull up/down resister of SD Bus */
- /*Disable Clock & CMD Pull enable*/
- PULL_EN_GP14_NAND_BYTE_VAL &= ~(GPIO_SD1_Clock | GPIO_SD1_Command);
-
- /*Set CD ,WP ,DATA pin pull up*/
- PULL_CTRL_GP16_NANDIO_BYTE_VAL |= GPIO_SD1_Data;
- PULL_CTRL_GP14_NAND_BYTE_VAL |= (GPIO_SD1_WriteProtect | GPIO_SD1_CD);
-
- /*Enable CD ,WP ,DATA internal pull*/
- PULL_EN_GP16_NANDIO_BYTE_VAL |= GPIO_SD1_Data;
- PULL_EN_GP14_NAND_BYTE_VAL |= (GPIO_SD1_WriteProtect | GPIO_SD1_CD);
-
- spin_unlock_irqrestore(&host->lock, flags);
- msleep(1);
- spin_lock_irqsave(&host->lock, flags);
-
- /* enable SD1 power */
- GPIO_OD_GP14_NAND_SD1_BYTE_VAL &= ~GPIO_SD1_POWER;
-
- /* enable SD output clock */
- *ATSMB1_BUS_MODE |= ATSMB_CST;
-
- spin_unlock_irqrestore(&host->lock, flags);
- msleep(1);
- spin_lock_irqsave(&host->lock, flags);
-
- /* Config SD1 back to function */
- GPIO_CTRL_GP16_NAND_SD1_BYTE_VAL &= ~GPIO_SD1_Data;
- GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL &= ~SD1_PIN;
- GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL &= ~GPIO_SD1_CD;
-
- /* terminate emmc boot mode */
- DBG("[%s] STRAP_STATUS_VAL = 0x%x\n", __func__, STRAP_STATUS_VAL);
- strapping = STRAP_STATUS_VAL & 0xE;
- if (strapping == 0x2) {
- printk("[%s] strapping = 0x%x, terminate boot mode\n", __func__, strapping);
- *ATSMB1_EXT_BUS_MODE &= ~BIT0;
- *ATSMB1_BUS_MODE &= ~BIT4;
- *ATSMB1_BUS_MODE |= BIT4;
- }
- }
- }
- } else {
- /*nothing to do when powering on.*/
- }
-
- host->current_clock = atsmb1_set_clock(mmc,ios->clock);
-
- if (ios->bus_width == MMC_BUS_WIDTH_8) {
- *ATSMB1_EXT_CTL |= (0x04);
- } else if (ios->bus_width == MMC_BUS_WIDTH_4) {
- *ATSMB1_BUS_MODE |= ATSMB_BUS_WIDTH_4;
- *ATSMB1_EXT_CTL &= ~(0x04);
- } else {
- *ATSMB1_BUS_MODE &= ~(ATSMB_BUS_WIDTH_4);
- *ATSMB1_EXT_CTL &= ~(0x04);
- }
-
-#if 1
- if (ios->timing == MMC_TIMING_SD_HS)
- *ATSMB1_EXT_CTL &= ~0x80; /*HIGH SPEED MODE hsot1 H_S must be off for wm3498*/
- else if (ios->timing == MMC_TIMING_MMC_HS)
- *ATSMB1_EXT_CTL &= ~0x80;
- else if (ios->timing == MMC_TIMING_UHS_DDR50) {
- /* enable emmc DDR mode */
- *ATSMB1_EXT_BUS_MODE |= BIT4; /*Enable DDR50*/
- /* enable SD output clock */
- *ATSMB1_BUS_MODE &= ~ATSMB_CST;
- spin_unlock_irqrestore(&host->lock, flags);
- msleep(1);
- spin_lock_irqsave(&host->lock, flags);
-
- *ATSMB1_EXT_BUS_MODE |= BIT4; /*Enable DDR50*/
- /* enable SD output clock */
- *ATSMB0_BUS_MODE |= ATSMB_CST;
- /*BIT4~7: PMOS driver strength, BIT8~11: NMOS driver strength */
- DRV_SPI_NAND_4BYTE_VAL |= (BIT4 |BIT5 | BIT6 | BIT7 | BIT8 | BIT9 | BIT10 | BIT11);
- }
-#endif
-#if 0 //zhf: marked by James Tian
- if (ios->ins_en == MMC_INSERT_IRQ_EN)
- *ATSMB1_INT_MASK_0 |= (0x80);/* or 40?*/
- else
- *ATSMB1_INT_MASK_0 &= (~0x80);/* or 40?*/
-#endif
-
- spin_unlock_irqrestore(&host->lock, flags);
- DBG("[%s] e\n",__func__);
-}
-
-
-static const struct mmc_host_ops atsmb1_ops = {
- .request = atsmb1_request,
- .set_ios = atsmb1_set_ios,
- .get_ro = atsmb1_get_ro,
- .get_slot_status = atsmb1_get_slot_status,
- .dump_host_regs = atsmb1_dump_host_regs,
- .enable_sdio_irq = atsmb1_enable_sdio_irq,
-};
-
-extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
-
-/**********************************************************************
-Name :atsmb1_probe
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static int __init atsmb1_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct mmc_host *mmc_host = NULL;
- struct atsmb_host *atsmb_host = NULL;
- struct resource *resource = NULL;
- int irq[2] = {0};
- int ret = 0;
- DBG("[%s] s\n",__func__);
- if (!pdev) {
- ret = -EINVAL; /* Invalid argument */
- goto the_end;
- }
-
-
- /*Enable SD host clock*/
- auto_pll_divisor(DEV_SDMMC1, CLK_ENABLE, 0, 0);
-
- if (MMC1_DRIVER_VERSION == MMC_DRV_3498) {
- /* enable SD1 PIN share */
- PIN_SHARING_SEL_4BYTE_VAL |= GPIO_SD1_PinShare;
-
- /* Pull up/down resister of SD CD */
- PULL_CTRL_GP14_NAND_BYTE_VAL |= GPIO_SD1_CD;
- PULL_EN_GP14_NAND_BYTE_VAL |= GPIO_SD1_CD;
-
- /* config CardDetect pin to SD function */
- GPIO_CTRL_GP14_NAND_SD1_BYTE_VAL &= ~GPIO_SD1_CD;
- }
-
- /* support emmc fisrt boot don't setting GPIO*/
- atsmb1_first_boot = 1; //1:first boot, 0: suspend/resume
-
- resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!resource) {
- ret = -ENXIO; /* No such device or address */
- printk(KERN_ALERT "[MMC/SD driver] Getting platform resources failed!\n");
- goto the_end;
- }
-#if 0
- if (!request_mem_region(resource->start, SZ_1K, MMC1_DRIVER_NAME)) {
- ret = -EBUSY;
- printk(KERN_ALERT "[MMC/SD driver] Request memory region failed!\n");
- goto the_end ;
- }
-#endif
- irq[0] = platform_get_irq(pdev, 0); /*get IRQ for device*/;
- irq[1] = platform_get_irq(pdev, 1); /*get IRQ for dma*/;
-
- if (irq[0] == NO_IRQ || irq[1] == NO_IRQ) {
- ret = -ENXIO;/* No such device or address */
- printk(KERN_ALERT "[MMC/SD driver] Get platform IRQ failed!\n");
- goto rls_region;
- }
-
- /*allocate a standard msp_host structure attached with a atsmb structure*/
- mmc_host = mmc_alloc_host(sizeof(struct atsmb_host), dev);
- if (!mmc_host) {
- ret = -ENOMEM;
- printk(KERN_ALERT "[MMC/SD driver] Allocating driver's data failed!\n");
- goto rls_region;
- }
- mmc_host->wmt_host_index = 1; /*to identify host number*/
-
- dev_set_drvdata(dev, (void *)mmc_host); /* mmc_host is driver data for the atsmb dev.*/
- atsmb_host = mmc_priv(mmc_host);
-
- mmc_host->ops = &atsmb1_ops;
-
- mmc_host->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
-
- mmc_host->f_min = 390425; /*390.425Hz = 400MHz/64/16*/
- mmc_host->f_max = 50000000; /* in fact, the max frequency is 400MHz( = 400MHz/1/1)*/
-
- if (SDXC1_function == 1) {
- mmc_host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ
- | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_8_BIT_DATA | MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50;
- } else if (SDXC1_function == 0) {
- mmc_host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ
- | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_8_BIT_DATA; /* */ //zhf: marked by James Tian
- }
-
- mmc_host->max_segs = 128; /*we use software sg. so we could manage even larger number.*/
-
- /*1MB per each request */
- /*we have a 16 bit block number register, and block length is 512 bytes.*/
- mmc_host->max_req_size = 16*512*(mmc_host->max_segs);
- mmc_host->max_seg_size = 65024; /* 0x7F*512 PDMA one descriptor can transfer 64K-1 byte*/
- mmc_host->max_blk_size = 2048; /* our block length register is 11 bits.*/
- mmc_host->max_blk_count = (mmc_host->max_req_size)/512;
-
- /*set the specified host -- ATSMB*/
-#ifdef CONFIG_MMC_UNSAFE_RESUME
- mmc_host->card_attath_status = card_attach_status_unchange;
-#endif
- sema_init(&mmc_host->req_sema,1); /*initial request semaphore*/
-#if 0
- atsmb_host->base = ioremap(resource->start, SZ_1K);
- if (!atsmb_host->base) {
- printk(KERN_ALERT "[MMC/SD driver] IO remap failed!\n");
- ret = -ENOMEM;
- goto fr_host;
- }
-#endif
- atsmb_host->base = (void *)resource->start;
- atsmb_host->mmc = mmc_host;
- spin_lock_init(&atsmb_host->lock);
- atsmb_host->res = resource;/* for atsmb_remove*/
-
- /*disable all interrupt and clear status by resetting controller.*/
- //*ATSMB1_BUS_MODE |= ATSMB_SFTRST; //emmc card don't execute SW reset. because uboot is done.
- *ATSMB1_BLK_LEN &= ~(0xa000);
- *ATSMB1_SD_STS_0 |= 0xff;
- *ATSMB1_SD_STS_1 |= 0xff;
-
- /* WM3437 A0 default not output clock, after SFTRST need to enable SD clock */
- //if (MMC1_DRIVER_VERSION >= MMC_DRV_3437_A0) /* including 3429 */
- *ATSMB1_BUS_MODE |= ATSMB_CST;
-
- atsmb_host->regular_irq = irq[0];
- atsmb_host->dma_irq = irq[1];
-
- ret = request_irq(atsmb_host->regular_irq,
- atsmb1_regular_isr,
- IRQF_SHARED, //SA_SHIRQ, /*SA_INTERRUPT, * that is okay?*/ //zhf: modified by James Tian, should be IRQF_SHARED?
- MMC1_DRIVER_NAME,
- (void *)atsmb_host);
- if (ret) {
- printk(KERN_ALERT "[MMC/SD driver] Failed to register regular ISR!\n");
- goto unmap;
- }
-
- ret = request_irq(atsmb_host->dma_irq,
- atsmb1_dma_isr,
- IRQF_DISABLED, // SA_INTERRUPT, //zhf: modified by James Tian
- MMC1_DRIVER_NAME,
- (void *)atsmb_host);
- if (ret) {
- printk(KERN_ALERT "[MMC/SD driver] Failed to register DMA ISR!\n");
- goto fr_regular_isr;
- }
-
-
-
- /*wait card detect status change*/
- //msleep(10);
- /*enable card insertion interrupt and enable DMA and its Global INT*/
- *ATSMB1_BLK_LEN |= (0xa000); /* also, we enable GPIO to detect card.*/
- *ATSMB1_SD_STS_0 |= 0xff;
- *ATSMB1_INT_MASK_0 |= 0x80; /*or 0x40?*/
-
- /*allocation dma descriptor*/
- ret = atsmb1_alloc_desc(atsmb_host, sizeof(struct SD_PDMA_DESC_S) * MAX_DESC_NUM);
- if (ret == -1) {
- printk(KERN_ALERT "[MMC/SD driver] Failed to allocate DMA descriptor!\n");
- goto fr_dma_isr;
- }
- printk(KERN_INFO "WMT ATSMB1 (AHB To SD/MMC1 Bus) controller registered!\n");
- mmc_add_host(mmc_host,true);
-
- DBG("[%s] e1\n",__func__);
- return 0;
-
-fr_dma_isr:
- free_irq(atsmb_host->dma_irq, atsmb_host);
-fr_regular_isr:
- free_irq(atsmb_host->regular_irq, atsmb_host);
-unmap:
- //iounmap(atsmb_host->base);
-//fr_host:
- dev_set_drvdata(dev, NULL);
- mmc_free_host(mmc_host);
-rls_region:
- //release_mem_region(resource->start, SZ_1K);
-the_end:
- printk(KERN_ALERT "[MMC/SD driver] ATSMB1 probe Failed!\n") ;
- DBG("[%s] e2\n",__func__);
- return ret;
-}
-/**********************************************************************
-Name : atsmb1_remove
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static int atsmb1_remove(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct mmc_host *mmc_host = (struct mmc_host *)dev_get_drvdata(dev);
- struct atsmb_host *atsmb_host;
-
- DBG("[%s] s\n",__func__);
- atsmb_host = mmc_priv(mmc_host);
- if (!mmc_host || !atsmb_host) {
- printk(KERN_ALERT "[MMC/SD driver] ATSMB1 remove method failed!\n");
- DBG("[%s] e1\n",__func__);
- return -ENXIO;
- }
- mmc_remove_host(mmc_host);
-
- /*disable interrupt by resetting controller -- for safey*/
- *ATSMB1_BUS_MODE |= ATSMB_SFTRST;
- *ATSMB1_BLK_LEN &= ~(0xa000);
- *ATSMB1_SD_STS_0 |= 0xff;
- *ATSMB1_SD_STS_1 |= 0xff;
-
- (void)free_irq(atsmb_host->regular_irq, atsmb_host);
- (void)free_irq(atsmb_host->dma_irq, atsmb_host);
- (void)iounmap(atsmb_host->base);
- (void)release_mem_region(atsmb_host->res->start, SZ_1K);
- dev_set_drvdata(dev, NULL);
- /*free dma descriptor*/
- dma_free_coherent(atsmb_host->mmc->parent, atsmb_host->DescSize,
- atsmb_host->DescVirAddr, atsmb_host->DescPhyAddr);
- (void)mmc_free_host(mmc_host);/* also free atsmb_host.*/
- DBG("[%s] e2\n",__func__);
- return 0;
-}
-
-/**********************************************************************
-Name : atsmb_shutdown
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Tommy Huang
-History :
-***********************************************************************/
-static void atsmb1_shutdown(struct platform_device *pdev)
-{
- /*atsmb1_shutdown don't be used now.*/
- /*struct device *dev = &pdev->dev;
- struct mmc_host *mmc_host = (struct mmc_host *)dev_get_drvdata(dev);*/
-
- DBG("[%s] s\n",__func__);
-
- /* turn off clock before emmc card shutdown. */
- *ATSMB1_BUS_MODE &= ~(ATSMB_CST);
-
- /*Disable card detect interrupt*/
- *ATSMB1_INT_MASK_0 &= ~0x80;
- DBG("[%s] e\n",__func__);
-
-}
-
-/**********************************************************************
-Name : atsmb_suspend
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-#ifdef CONFIG_PM
-static int atsmb1_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct device *dev = &pdev->dev;
- struct mmc_host *mmc = (struct mmc_host *)dev_get_drvdata(dev);
- int ret = 0;
- DBG("[%s] s\n",__func__);
-
- /* after suspend/resume, it isn't first boot*/
- atsmb1_first_boot = 0;
-
- if (mmc) {
- /*struct atsmb_host *host = mmc_priv(mmc);*/
- ret = mmc_suspend_host(mmc);
- if (ret == 0) {
- /*disable all interrupt and clear status by resetting controller. */
- *ATSMB1_BUS_MODE |= ATSMB_SFTRST;
- *ATSMB1_BLK_LEN &= ~(0xa000);
- *ATSMB1_SD_STS_0 |= 0xff;
- *ATSMB1_SD_STS_1 |= 0xff;
-
- }
- /*disable source clock*/
- //TODO: SD1 clock en or dis
- auto_pll_divisor(DEV_SDMMC1, CLK_DISABLE, 0, 0);
-#ifdef CONFIG_MMC_UNSAFE_RESUME
- /*clean SD card attatch status change*/
- PMCWS_VAL |= BIT20;
- mmc->card_attath_status = card_attach_status_unchange;
-#endif
- }
-
- DBG("[%s] e\n",__func__);
- return ret;
-}
-/**********************************************************************
-Name : atsmb_resume
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static int atsmb1_resume(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct mmc_host *mmc = (struct mmc_host *)dev_get_drvdata(dev);
- int ret = 0;
- DBG("[%s] s\n",__func__);
-
- /*
- * enable interrupt, DMA, etc.
- * Supply power to slot.
- */
- if (mmc) {
- /*enable source clock*/
- auto_pll_divisor(DEV_SDMMC1, CLK_ENABLE, 0, 0);
-
- udelay(1);
- /*enable card insertion interrupt and enable DMA and its Global INT*/
- *ATSMB1_BUS_MODE |= ATSMB_SFTRST;
- *ATSMB1_BLK_LEN |= (0xa000);
- *ATSMB1_INT_MASK_0 |= 0x80; /* or 40?*/
-#ifdef CONFIG_MMC_UNSAFE_RESUME
- /*modify SD card attatch status change*/
- if ((PMCWS_VAL & BIT20) && !mmc->bus_dead) {
- /*card change when suspend mode*/
- mmc->card_attath_status = card_attach_status_change;
- /*clean SD card attatch status change*/
- PMCWS_VAL |= BIT20;
- }
-#endif
- ret = mmc_resume_host(mmc);
- }
-
- DBG("[%s] e\n",__func__);
- return ret;
-}
-#else
-#define atsmb1_suspend NULL
-#define atsmb1_resume NULL
-#endif
-
-static struct platform_driver atsmb1_driver = {
- .driver.name = "sdmmc1",
- //.probe = atsmb1_probe,
- .remove = atsmb1_remove,
- .shutdown = atsmb1_shutdown,
- .suspend = atsmb1_suspend,
- .resume = atsmb1_resume,
-};
-
-static struct platform_device wmt_sdmmc1_device = {
- .name = "sdmmc1",
- .id = 0,
- .dev = {
- .dma_mask = &wmt_sdmmc1_dma_mask,
- .coherent_dma_mask = ~0,
- .release = atsmb1_release,
- },
- .num_resources = ARRAY_SIZE(wmt_sdmmc1_resources),
- .resource = wmt_sdmmc1_resources,
-};
-
-
-static int __init atsmb1_init(void)
-{
- int ret;
- int retval;
- unsigned char buf[80];
- int varlen = 80;
- char *varname = "wmt.sd1.param";
- int temp = 0, sd_enable = 0; /*0 :disable 1:enable*/
-
- DBG("[%s] s\n",__func__);
-
-#ifdef CONFIG_MTD_WMT_SF
- /*Read system param to identify host function 0: SD/MMC 1:SDIO wifi*/
- retval = wmt_getsyspara(varname, buf, &varlen);
- if (retval == 0) {
- sscanf(buf,"%x:%d", &temp, &SD1_function);
- printk(KERN_ALERT "wmt.sd1.param = %x:%d\n", temp, SD1_function);
- sd_enable = temp & 0xf;
- SDXC1_function = (temp >> 4) & 0xf;
- printk(KERN_ALERT "SD1 ebable = %x, SDXC = %x, function = %x\n",
- sd_enable, SDXC1_function, SD1_function);
-
- if (SD1_function < 0 || SD1_function >= SD_MAX_FUN)
- return -ENODEV;
- } else {
- printk(KERN_ALERT "Default wmt.sd1.param = %x:%d\n", temp, SD1_function);
- }
-#endif
- /*SD function disable*/
- if (sd_enable != 1)
- return -ENODEV;
-
- get_driver_version1();
-
- if (platform_device_register(&wmt_sdmmc1_device))//add by jay,for modules support
- return -1;
- //ret = platform_driver_register(&atsmb1_driver);
- ret = platform_driver_probe(&atsmb1_driver, atsmb1_probe);
-
- DBG("[%s] e\n",__func__);
- return ret;
-}
-
-static void __exit atsmb1_exit(void)
-{
- DBG("[%s] s\n",__func__);
- (void)platform_driver_unregister(&atsmb1_driver);
- (void)platform_device_unregister(&wmt_sdmmc1_device);//add by jay,for modules support
- DBG("[%s] e\n",__func__);
-}
-
-module_init(atsmb1_init);
-module_exit(atsmb1_exit);
-module_param(fmax1, uint, 0444);
-
-MODULE_AUTHOR("WonderMedia Technologies, Inc.");
-MODULE_DESCRIPTION("WMT [AHB to SD/MMC1 Bridge] driver");
-MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb2.c b/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb2.c
deleted file mode 100755
index 944e3cc4..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/mmc_atsmb2.c
+++ /dev/null
@@ -1,2855 +0,0 @@
-/*++
-linux/drivers/mmc/host/mmc_atsmb.c
-
-Copyright (c) 2008 WonderMedia Technologies, Inc.
-
-This program is free software: you can redistribute it and/or modify it under the
-terms of the GNU General Public License as published by the Free Software Foundation,
-either version 2 of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
-PARTICULAR PURPOSE. See the GNU General Public License for more details.
-You should have received a copy of the GNU General Public License along with
-this program. If not, see <http://www.gnu.org/licenses/>.
-
-WonderMedia Technologies, Inc.
-10F, 529, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C.
---*/
-
-//#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/blkdev.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sd.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/sdio.h>
-#include <linux/completion.h>
-#include <linux/pagemap.h>
-#include <linux/dma-mapping.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/memory.h>
-#include <mach/hardware.h>
-#include <asm/scatterlist.h>
-#include <asm/sizes.h>
-#include "mmc_atsmb.h"
-//#include <mach/multicard.h>
-#include <mach/irqs.h>
-#include <linux/mmc/sdio.h>
-#include <linux/gpio.h>
-#include <mach/wmt_iomux.h>
-
-int enable_wifi_irq = 1;
-
-#define MMC2_SDIO_EXT_IRQ (1) /* use sdio ext irq or not */
-
-#if MMC2_SDIO_EXT_IRQ
-static int is_mtk6620 = 0;
-static unsigned int mmc2_sdio_ext_irq = 0;
-static unsigned long mmc2_sdio_ext_irq_flags = 0;
-enum ext_irq_flag {
- IN_SUSPEND = 0,
- IRQ_IN_SUSPEND = 1,
-};
-int wmt_mtk6620_intr=0xf; //gpio 15
-#endif
-
-
-static int is_nmc1000 = 0x0;
-static int is_ap6330 = 0;
-int set_bus_dead = 1;
-#define mprintk
-
-#if 0
-#define DBG(host, fmt, args...) \
- pr_debug("%s: %s: " fmt, mmc_hostname(host->mmc), __func__ , args)
-#endif
-#define ATSMB_TIMEOUT_TIME (HZ*2)
-
-//add by jay,for modules support
-static u64 wmt_sdmmc2_dma_mask = 0xffffffffUL;
-static struct resource wmt_sdmmc2_resources[] = {
- [0] = {
- .start = SD2_SDIO_MMC_BASE_ADDR,
- .end = (SD2_SDIO_MMC_BASE_ADDR + 0x3FF),
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_SDC2,
- .end = IRQ_SDC2,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
- .start = IRQ_SDC2_DMA,
- .end = IRQ_SDC2_DMA,
- .flags = IORESOURCE_IRQ,
- },
- /*2008/10/6 RichardHsu-s*/
- [3] = {
- .start = IRQ_PMC_WAKEUP,
- .end = IRQ_PMC_WAKEUP,
- .flags = IORESOURCE_IRQ,
- },
- /*2008/10/6 RichardHsu-e*/
-};
-
-struct kobject *atsmb2_kobj;
-struct mmc_host *mmc2_host_attr = NULL;
-//
-static void atsmb2_release(struct device * dev) {}
-
-/*#ifdef CONFIG_MMC_DEBUG*/
-#define MORE_INFO
-#if 0
-#define DBG(x...) printk(KERN_ALERT x)
-#define DBGR(x...) printk(KERN_ALERT x)
-#else
-#define DBG(x...) do { } while (0)
-#define DBGR(x...) do { } while (0)
-#endif
-
-/* when Read CRC error occur, and clear read CRC error by software reset.*/
-void atsmb2_copy_reg(int direct)
-{
- static u8 CTL, CMD_IDX, RSP_TYPE, BUS_MODE, INT_MASK_0, INT_MASK_1, SD_STS_0, SD_STS_1, SD_STS_2, SD_STS_3;
- static u8 EXT_BUS_MODE, EXT_CTL_1, EXT_CTL_2, MAN_TUNE_VAL, SD_WRI_TUNE;
- static u8 RSP_0, RSP_1, RSP_2, RSP_3, RSP_4, RSP_5, RSP_6, RSP_7;
- static u8 RSP_8, RSP_9, RSP_10, RSP_11, RSP_12, RSP_13, RSP_14, RSP_15;
- static u8 RSP_TOUT, CLK_SEL, EXT_CTL;
- static u16 BLK_LEN, BLK_CNT, SHDW_BLKLEN, TIMER_VAL, CTL2;
- static u32 CMD_ARG, CURBLK_CNT;
-
- /*direct 0: copy register to memory; 1: copy memory to register.*/
- if (direct == 0) {
- CTL = *ATSMB2_CTL;
- CMD_IDX = *ATSMB2_CMD_IDX;
- RSP_TYPE = *ATSMB2_RSP_TYPE;
- CMD_ARG = *ATSMB2_CMD_ARG;
- BUS_MODE = *ATSMB2_BUS_MODE;
- EXT_BUS_MODE = *ATSMB2_EXT_BUS_MODE;
- CTL2 = *ATSMB2_CTL2;
- BLK_LEN = *ATSMB2_BLK_LEN;
- BLK_CNT = *ATSMB2_BLK_CNT;
- RSP_0 = *ATSMB2_RSP_0;
- RSP_1 = *ATSMB2_RSP_1;
- RSP_2 = *ATSMB2_RSP_2;
- RSP_3 = *ATSMB2_RSP_3;
- RSP_4 = *ATSMB2_RSP_4;
- RSP_5 = *ATSMB2_RSP_5;
- RSP_6 = *ATSMB2_RSP_6;
- RSP_7 = *ATSMB2_RSP_7;
- RSP_8 = *ATSMB2_RSP_8;
- RSP_9 = *ATSMB2_RSP_9;
- RSP_10 = *ATSMB2_RSP_10;
- RSP_11 = *ATSMB2_RSP_11;
- RSP_12 = *ATSMB2_RSP_12;
- RSP_13 = *ATSMB2_RSP_13;
- RSP_14 = *ATSMB2_RSP_14;
- RSP_15 = *ATSMB2_RSP_15;
- CURBLK_CNT = *ATSMB2_CURBLK_CNT;
- INT_MASK_0 = *ATSMB2_INT_MASK_0;
- INT_MASK_1 = *ATSMB2_INT_MASK_1;
- SD_STS_0 = *ATSMB2_SD_STS_0;
- SD_STS_1 = *ATSMB2_SD_STS_1;
- SD_STS_2 = *ATSMB2_SD_STS_2;
- SD_STS_3 = *ATSMB2_SD_STS_3;
- RSP_TOUT = *ATSMB2_RSP_TOUT;
- CLK_SEL = *ATSMB2_CLK_SEL;
- EXT_CTL = *ATSMB2_EXT_CTL;
- EXT_CTL_1 = *ATSMB2_EXT_CTL_1;
- EXT_CTL_2 = *ATSMB2_EXT_CTL_2;
- SHDW_BLKLEN = *ATSMB2_SHDW_BLKLEN;
- MAN_TUNE_VAL = *ATSMB2_MAN_TUNE_VAL;
- SD_WRI_TUNE = *ATSMB2_SD_WRI_TUNE;
- TIMER_VAL = *ATSMB2_TIMER_VAL;
- } else {
- *ATSMB2_CTL = CTL;
- *ATSMB2_CMD_IDX = CMD_IDX;
- *ATSMB2_RSP_TYPE = RSP_TYPE;
- *ATSMB2_CMD_ARG = CMD_ARG;
- *ATSMB2_BUS_MODE = BUS_MODE;
- *ATSMB2_EXT_BUS_MODE = EXT_BUS_MODE;
- *ATSMB2_CTL2 = CTL2;
- *ATSMB2_BLK_LEN = BLK_LEN;
- *ATSMB2_BLK_CNT = BLK_CNT;
- *ATSMB2_RSP_0 = RSP_0;
- *ATSMB2_RSP_1 = RSP_1;
- *ATSMB2_RSP_2 = RSP_2;
- *ATSMB2_RSP_3 = RSP_3;
- *ATSMB2_RSP_4 = RSP_4;
- *ATSMB2_RSP_5 = RSP_5;
- *ATSMB2_RSP_6 = RSP_6;
- *ATSMB2_RSP_7 = RSP_7;
- *ATSMB2_RSP_8 = RSP_8;
- *ATSMB2_RSP_9 = RSP_9;
- *ATSMB2_RSP_10 = RSP_10;
- *ATSMB2_RSP_11 = RSP_11;
- *ATSMB2_RSP_12 = RSP_12;
- *ATSMB2_RSP_13 = RSP_13;
- *ATSMB2_RSP_14 = RSP_14;
- *ATSMB2_RSP_15 = RSP_15;
- *ATSMB2_CURBLK_CNT = CURBLK_CNT;
- *ATSMB2_INT_MASK_0 = INT_MASK_0;
- *ATSMB2_INT_MASK_1 = INT_MASK_1;
- *ATSMB2_SD_STS_0 = SD_STS_0;
- *ATSMB2_SD_STS_1 = SD_STS_1;
- *ATSMB2_SD_STS_2 = SD_STS_2;
- *ATSMB2_SD_STS_3 = SD_STS_3;
- *ATSMB2_RSP_TOUT = RSP_TOUT;
- *ATSMB2_CLK_SEL = CLK_SEL;
- *ATSMB2_EXT_CTL = EXT_CTL;
- *ATSMB2_EXT_CTL_1 = EXT_CTL_1;
- *ATSMB2_EXT_CTL_2 = EXT_CTL_2;
- *ATSMB2_SHDW_BLKLEN = SHDW_BLKLEN;
- *ATSMB2_MAN_TUNE_VAL = MAN_TUNE_VAL;
- *ATSMB2_SD_WRI_TUNE = SD_WRI_TUNE;
- *ATSMB2_TIMER_VAL = TIMER_VAL;
- }
-}
-
-#if 0
-void atsmb2_dump_reg(struct atsmb_host *host)
-{
- u8 CTL, CMD_IDX, RSP_TYPE, BUS_MODE, INT_MASK_0, INT_MASK_1, SD_STS_0, SD_STS_1, SD_STS_2, SD_STS_3;
- u8 EXT_BUS_MODE, EXT_CTL_1, EXT_CTL_2, MAN_TUNE_VAL, SD_WRI_TUNE;
- u8 RSP_0, RSP_1, RSP_2, RSP_3, RSP_4, RSP_5, RSP_6, RSP_7;
- u8 RSP_8, RSP_9, RSP_10, RSP_11, RSP_12, RSP_13, RSP_14, RSP_15;
- u8 RSP_TOUT, CLK_SEL, EXT_CTL;
- u16 BLK_LEN, BLK_CNT, SHDW_BLKLEN, TIMER_VAL, CTL2;
- u32 CMD_ARG, PDMA_GCR, PDMA_IER, PDMA_ISR, PDMA_DESPR, PDMA_RBR, PDMA_DAR, PDMA_BAR, PDMA_CPR, PDMA_CCR;
- u32 CURBLK_CNT;
-
- CTL = *ATSMB2_CTL;
- CMD_IDX = *ATSMB2_CMD_IDX;
- RSP_TYPE = *ATSMB2_RSP_TYPE;
- CMD_ARG = *ATSMB2_CMD_ARG;
- BUS_MODE = *ATSMB2_BUS_MODE;
- EXT_BUS_MODE = *ATSMB2_EXT_BUS_MODE;
- CTL2 = *ATSMB2_CTL2;
- BLK_LEN = *ATSMB2_BLK_LEN;
- BLK_CNT = *ATSMB2_BLK_CNT;
- RSP_0 = *ATSMB2_RSP_0;
- RSP_1 = *ATSMB2_RSP_1;
- RSP_2 = *ATSMB2_RSP_2;
- RSP_3 = *ATSMB2_RSP_3;
- RSP_4 = *ATSMB2_RSP_4;
- RSP_5 = *ATSMB2_RSP_5;
- RSP_6 = *ATSMB2_RSP_6;
- RSP_7 = *ATSMB2_RSP_7;
- RSP_8 = *ATSMB2_RSP_8;
- RSP_9 = *ATSMB2_RSP_9;
- RSP_10 = *ATSMB2_RSP_10;
- RSP_11 = *ATSMB2_RSP_11;
- RSP_12 = *ATSMB2_RSP_12;
- RSP_13 = *ATSMB2_RSP_13;
- RSP_14 = *ATSMB2_RSP_14;
- RSP_15 = *ATSMB2_RSP_15;
- CURBLK_CNT = *ATSMB2_CURBLK_CNT;
- INT_MASK_0 = *ATSMB2_INT_MASK_0;
- INT_MASK_1 = *ATSMB2_INT_MASK_1;
- SD_STS_0 = *ATSMB2_SD_STS_0;
- SD_STS_1 = *ATSMB2_SD_STS_1;
- SD_STS_2 = *ATSMB2_SD_STS_2;
- SD_STS_3 = *ATSMB2_SD_STS_3;
- RSP_TOUT = *ATSMB2_RSP_TOUT;
- CLK_SEL = *ATSMB2_CLK_SEL;
- EXT_CTL = *ATSMB2_EXT_CTL;
- EXT_CTL_1 = *ATSMB2_EXT_CTL_1;
- EXT_CTL_2 = *ATSMB2_EXT_CTL_2;
- SHDW_BLKLEN = *ATSMB2_SHDW_BLKLEN;
- MAN_TUNE_VAL = *ATSMB2_MAN_TUNE_VAL;
- SD_WRI_TUNE = *ATSMB2_SD_WRI_TUNE;
- TIMER_VAL = *ATSMB2_TIMER_VAL;
-
- PDMA_GCR = *ATSMB2_PDMA_GCR;
- PDMA_IER = *ATSMB2_PDMA_IER;
- PDMA_ISR = *ATSMB2_PDMA_ISR;
- PDMA_DESPR = *ATSMB2_PDMA_DESPR;
- PDMA_RBR = *ATSMB2_PDMA_RBR;
- PDMA_DAR = *ATSMB2_PDMA_DAR;
- PDMA_BAR = *ATSMB2_PDMA_BAR;
- PDMA_CPR = *ATSMB2_PDMA_CPR;
- PDMA_CCR = *ATSMB2_PDMA_CCR;
-
- DBGR("\n+---------------------------Registers----------------------------+\n");
-
- DBGR("%16s = 0x%8x |", "CTL", CTL);
- DBGR("%16s = 0x%8x\n", "CMD_IDX", CMD_IDX);
-
- DBGR("%16s = 0x%8x |", "RSP_TYPE", RSP_TYPE);
- DBGR("%16s = 0x%8x\n", "CMD_ARG", CMD_ARG);
-
- DBGR("%16s = 0x%8x |", "BUS_MODE", BUS_MODE);
- DBGR("%16s = 0x%8x\n", "EXT_BUS_MODE", EXT_BUS_MODE);
-
- DBGR("%16s = 0x%8x |", "CTL2", CTL2);
- DBGR("%16s = 0x%8x\n", "BLK_LEN", BLK_LEN);
-
- DBGR("%16s = 0x%8x |", "BLK_CNT", BLK_CNT);
- DBGR("%16s = 0x%8x\n", "RSP_0", RSP_0);
-
- DBGR("%16s = 0x%8x |", "RSP_1", RSP_1);
- DBGR("%16s = 0x%8x\n", "RSP_2", RSP_2);
-
- DBGR("%16s = 0x%8x |", "RSP_3", RSP_3);
- DBGR("%16s = 0x%8x\n", "RSP_4", RSP_4);
-
- DBGR("%16s = 0x%8x |", "RSP_5", RSP_5);
- DBGR("%16s = 0x%8x\n", "RSP_6", RSP_6);
-
- DBGR("%16s = 0x%8x |", "RSP_7", RSP_7);
- DBGR("%16s = 0x%8x\n", "RSP_8", RSP_8);
-
- DBGR("%16s = 0x%8x |", "RSP_9", RSP_9);
- DBGR("%16s = 0x%8x\n", "RSP_10", RSP_10);
-
- DBGR("%16s = 0x%8x |", "RSP_11", RSP_11);
- DBGR("%16s = 0x%8x\n", "RSP_12", RSP_12);
-
- DBGR("%16s = 0x%8x |", "RSP_13", RSP_13);
- DBGR("%16s = 0x%8x\n", "RSP_14", RSP_14);
-
- DBGR("%16s = 0x%8x\n", "RSP_15", RSP_15);
-
- DBGR("%16s = 0x%8x |", "CURBLK_CNT", CURBLK_CNT);
- DBGR("%16s = 0x%8x\n", "INT_MASK_0", INT_MASK_0);
-
- DBGR("%16s = 0x%8x |", "INT_MASK_1", INT_MASK_1);
- DBGR("%16s = 0x%8x\n", "SD_STS_0", SD_STS_0);
-
- DBGR("%16s = 0x%8x |", "SD_STS_1", SD_STS_1);
- DBGR("%16s = 0x%8x\n", "SD_STS_2", SD_STS_2);
-
- DBGR("%16s = 0x%8x |", "SD_STS_3", SD_STS_3);
- DBGR("%16s = 0x%8x\n", "RSP_TOUT", RSP_TOUT);
-
- DBGR("%16s = 0x%8x |", "CLK_SEL", CLK_SEL);
- DBGR("%16s = 0x%8x\n", "EXT_CTL", EXT_CTL);
-
- DBGR("%16s = 0x%8x |", "EXT_CTL_1", EXT_CTL_1);
- DBGR("%16s = 0x%8x\n", "EXT_CTL_2", EXT_CTL_2);
-
- DBGR("%16s = 0x%8x |", "SHDW_BLKLEN", SHDW_BLKLEN);
- DBGR("%16s = 0x%8x\n", "MAN_TUNE_VAL", MAN_TUNE_VAL);
-
- DBGR("%16s = 0x%8x |", "SD_WRI_TUNE", SD_WRI_TUNE);
- DBGR("%16s = 0x%8x\n", "TIMER_VAL", TIMER_VAL);
-
- DBGR("%16s = 0x%8x |", "PDMA_GCR", PDMA_GCR);
- DBGR("%16s = 0x%8x\n", "PDMA_IER", PDMA_IER);
-
- DBGR("%16s = 0x%8x |", "PDMA_ISR", PDMA_ISR);
- DBGR("%16s = 0x%8x\n", "PDMA_DESPR", PDMA_DESPR);
-
- DBGR("%16s = 0x%8x |", "PDMA_RBR", PDMA_RBR);
- DBGR("%16s = 0x%8x\n", "PDMA_DAR", PDMA_DAR);
-
- DBGR("%16s = 0x%8x |", "PDMA_BAR", PDMA_BAR);
- DBGR("%16s = 0x%8x\n", "PDMA_CPR", PDMA_CPR);
-
- DBGR("%16s = 0x%8x |", "PDMA_CCR", PDMA_CCR);
- DBGR("\n+----------------------------------------------------------------+\n");
-}
-#else
-void atsmb2_dump_reg(struct atsmb_host *host) {}
-#endif
-
-unsigned int fmax2 = 515633;
-unsigned int MMC2_DRIVER_VERSION;
-int SD2_function = 0; /*0: normal SD/MMC card reader , 1: internal SDIO wifi*/
-int SDXC2_function;
-
-int SCC2_ID(void){
- unsigned short val;
-
- val = REG16_VAL(SYSTEM_CFG_CTRL_BASE_ADDR + 0x2);
- return val;
-}
-
-int get_chip_version2(void) /*2008/05/01 janshiue modify for A1 chip*/
-{
- u32 tmp;
-
- tmp = REG32_VAL(SYSTEM_CFG_CTRL_BASE_ADDR);
- tmp = ((tmp & 0xF00) >> 4) + 0x90 + ((tmp & 0xFF) - 1);
- return tmp;
-}
-
-void get_driver_version2(void)
-{
- if (SCC2_ID() == 0x3426) {
- if (get_chip_version2() < 0xA1)
- MMC2_DRIVER_VERSION = MMC_DRV_3426_A0;
- else if (get_chip_version2() == 0xA1)
- MMC2_DRIVER_VERSION = MMC_DRV_3426_A1;
- else
- MMC2_DRIVER_VERSION = MMC_DRV_3426_A2;
- } else if (SCC2_ID() == 0x3437) {
- if (get_chip_version2() < 0xA1)
- MMC2_DRIVER_VERSION = MMC_DRV_3437_A0;
- else
- MMC2_DRIVER_VERSION = MMC_DRV_3437_A1;
- } else if (SCC2_ID() == 0x3429) {
- MMC2_DRIVER_VERSION = MMC_DRV_3429;
- } else if (SCC2_ID() == 0x3451) {
- if (get_chip_version2() < 0xA1)
- MMC2_DRIVER_VERSION = MMC_DRV_3451_A0;
- } else if (SCC2_ID() == 0x3465) {
- MMC2_DRIVER_VERSION = MMC_DRV_3465;
- } else if (SCC2_ID() == 0x3445) {
- MMC2_DRIVER_VERSION = MMC_DRV_3445;
- } else if (SCC2_ID() == 0x3481) {
- MMC2_DRIVER_VERSION = MMC_DRV_3481;
- } else if (SCC2_ID() == 0x3498) {
- MMC2_DRIVER_VERSION = MMC_DRV_3498;
- }
-}
-/*2008/10/6 RichardHsu-e*/
-
-/**********************************************************************
-Name : atsmb2_alloc_desc
-Function : To config PDMA descriptor setting.
-Calls :
-Called by :
-Parameter :
-Author : Janshiue Wu
-History :
-***********************************************************************/
-static inline int atsmb2_alloc_desc(struct atsmb_host *host,
- unsigned int bytes)
-{
- void *DescPool = NULL;
- DBG("[%s] s\n",__func__);
-
- DescPool = dma_alloc_coherent(host->mmc->parent, bytes, &(host->DescPhyAddr), GFP_KERNEL);
- if (!DescPool) {
- DBG("can't allocal desc pool=%8X %8X\n", DescPool, host->DescPhyAddr);
- DBG("[%s] e1\n",__func__);
- return -1;
- }
- DBG("allocal desc pool=%8X %8X\n", DescPool, host->DescPhyAddr);
- host->DescVirAddr = (unsigned long *)DescPool;
- host->DescSize = bytes;
- DBG("[%s] e2\n",__func__);
- return 0;
-}
-
-/**********************************************************************
-Name : atsmb2_config_desc
-Function : To config PDMA descriptor setting.
-Calls :
-Called by :
-Parameter :
-Author : Janshiue Wu
-History :
-***********************************************************************/
-static inline void atsmb2_config_desc(unsigned long *DescAddr,
- unsigned long *BufferAddr,
- unsigned long Blk_Cnt)
-{
-
- int i = 0 ;
- unsigned long *CurDes = DescAddr;
- DBG("[%s] s\n",__func__);
-
- /* the first Descriptor store for 1 Block data
- * (512 bytes)
- */
- for (i = 0 ; i < 3 ; i++) {
- atsmb2_init_short_desc(CurDes, 0x80, BufferAddr, 0);
- BufferAddr += 0x20;
- CurDes += sizeof(struct SD_PDMA_DESC_S)/4;
- }
- if (Blk_Cnt > 1) {
- atsmb2_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 0);
- BufferAddr += 0x20;
- CurDes += sizeof(struct SD_PDMA_DESC_L)/4;
- /* the following Descriptor store the rest Blocks data
- * (Blk_Cnt - 1) * 512 bytes
- */
- atsmb2_init_long_desc(CurDes, (Blk_Cnt - 1) * 512,
- BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 1);
- } else {
- atsmb2_init_long_desc(CurDes, 0x80, BufferAddr, CurDes + (sizeof(struct SD_PDMA_DESC_L)/4), 1);
- }
- DBG("[%s] e\n",__func__);
-}
-/**********************************************************************
-Name : atsmb2_config_dma
-Function : To set des/src address, byte count to transfer, and DMA channel settings,
- and DMA ctrl. register.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static inline void atsmb2_config_dma(unsigned long config_dir,
- unsigned long dma_mask,
- struct atsmb_host *host)
-{
-
- DBG("[%s] s\n",__func__);
- /* Enable DMA */
- *ATSMB2_PDMA_GCR = SD_PDMA_GCR_DMA_EN;
- *ATSMB2_PDMA_GCR = SD_PDMA_GCR_SOFTRESET;
- *ATSMB2_PDMA_GCR = SD_PDMA_GCR_DMA_EN;
- /*open interrupt*/
- *ATSMB2_PDMA_IER = SD_PDMA_IER_INT_EN;
- /*Make sure host could co-work with DMA*/
- *ATSMB2_SD_STS_2 |= ATSMB_CLK_FREEZ_EN;
-
- /*Set timer timeout value*/
- /*If clock is 390KHz*/
- if (host->current_clock < 400000)
- *ATSMB2_TIMER_VAL = 0x200; /*1024*512*(1/390K) second*/
- else
- *ATSMB2_TIMER_VAL = 0x1fff; /*why not to be 0xffff?*/
-
- /*clear all DMA INT status for safety*/
- *ATSMB2_PDMA_ISR |= SD_PDMA_IER_INT_STS;
-
- /* hook desc */
- *ATSMB2_PDMA_DESPR = host->DescPhyAddr;
- if (config_dir == DMA_CFG_WRITE)
- *ATSMB2_PDMA_CCR &= SD_PDMA_CCR_IF_to_peripheral;
- else
- *ATSMB2_PDMA_CCR |= SD_PDMA_CCR_peripheral_to_IF;
-
- host->DmaIntMask = dma_mask; /*save success event*/
-
- *ATSMB2_PDMA_CCR |= SD_PDMA_CCR_RUN;
- DBG("[%s] e\n",__func__);
-}
-
-/**********************************************************************
-Name : atsmb2_prep_cmd
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static inline void atsmb2_prep_cmd(struct atsmb_host *host,
- u32 opcode,
- u32 arg,
- unsigned int flags,
- u16 blk_len,
- u16 blk_cnt,
- unsigned char int_maks_0,
- unsigned char int_mask_1,
- unsigned char cmd_type,
- unsigned char op)
-{
- unsigned long spl_flags; /* add by th */
- DBG("[%s] s\n",__func__);
-
- /*set cmd operation code and arguments.*/
- host->opcode = opcode;
- *ATSMB2_CMD_IDX = opcode; /* host->opcode is set for further use in ISR.*/
- *ATSMB2_CMD_ARG = arg;
-
-#if 0 /* Fixme to support SPI mode, James Tian*/
- if ((flags && MMC_RSP_NONE) == MMC_RSP_NONE)
- *ATSMB2_RSP_TYPE = ATMSB_TYPE_R0;
- else if ((flags && MMC_RSP_R1) == MMC_RSP_R1)
- *ATSMB2_RSP_TYPE = ATMSB_TYPE_R1;
- else if ((flags && MMC_RSP_R1B) == MMC_RSP_R1B)
- *ATSMB2_RSP_TYPE = ATMSB_TYPE_R1b;
- else if ((flags && MMC_RSP_R2) == MMC_RSP_R2)
- *ATSMB2_RSP_TYPE = ATMSB_TYPE_R2;
- else if ((flags && MMC_RSP_R3) == MMC_RSP_R3)
- *ATSMB2_RSP_TYPE = ATMSB_TYPE_R3;
- else if ((flags && MMC_RSP_R6) == MMC_RSP_R6)
- *ATSMB2_RSP_TYPE = ((opcode != SD_SEND_IF_COND) ? ATMSB_TYPE_R6 : ATMSB_TYPE_R7);
- else
- *ATSMB2_RSP_TYPE = ATMSB_TYPE_R0;
-#endif
-
-#if 1
- /*set cmd response type*/
- switch (flags) {
- case MMC_RSP_NONE | MMC_CMD_AC:
- case MMC_RSP_NONE | MMC_CMD_BC:
- *ATSMB2_RSP_TYPE = ATMSB_TYPE_R0;
- break;
- case MMC_RSP_R1 | MMC_CMD_ADTC:
- case MMC_RSP_R1 | MMC_CMD_AC:
- *ATSMB2_RSP_TYPE = ATMSB_TYPE_R1;
- break;
- case MMC_RSP_R1B | MMC_CMD_AC:
- *ATSMB2_RSP_TYPE = ATMSB_TYPE_R1b;
- break;
- case MMC_RSP_R2 | MMC_CMD_BCR:
- case MMC_RSP_R2 | MMC_CMD_AC:
- *ATSMB2_RSP_TYPE = ATMSB_TYPE_R2;
- break;
- case MMC_RSP_R3 | MMC_CMD_BCR:
- *ATSMB2_RSP_TYPE = ATMSB_TYPE_R3;
- break;
- case MMC_RSP_R6 | MMC_CMD_BCR: /*MMC_RSP_R6 = MMC_RSP_R7.*/
- *ATSMB2_RSP_TYPE = ((opcode != SD_SEND_IF_COND) ?
- ATMSB_TYPE_R6 : ATMSB_TYPE_R7);
- break;
- case MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC:
- case MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC:
- *ATSMB2_RSP_TYPE = ATMSB_TYPE_R5;
- break;
- case MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR:
- *ATSMB2_RSP_TYPE = ATMSB_TYPE_R4;
- break;
- default:
- *ATSMB2_RSP_TYPE = ATMSB_TYPE_R0;
- break;
- }
-#endif
- /*SDIO cmd 52 , 53*/
- if ((opcode == SD_IO_RW_DIRECT) ||
- (opcode == SD_IO_RW_EXTENDED)) {
- *ATSMB2_RSP_TYPE = ATMSB_TYPE_R5;
- *ATSMB2_RSP_TYPE |= BIT6;
- }
- /*SDIO cmd 5*/
- if ((opcode == SD_IO_SEND_OP_COND) &&
- ((flags & (MMC_RSP_PRESENT|
- MMC_RSP_136|
- MMC_RSP_CRC|
- MMC_RSP_BUSY|
- MMC_RSP_OPCODE)) == MMC_RSP_R4)) {
- *ATSMB2_RSP_TYPE = ATMSB_TYPE_R4;
- *ATSMB2_RSP_TYPE |= BIT6;
- }
-
- /*reset Response FIFO*/
- *ATSMB2_CTL |= 0x08;
-
- /* SD Host enable Clock */
- *ATSMB2_BUS_MODE |= ATSMB_CST;
-
- /*Set Cmd-Rsp Timeout to be maximum value.*/
- *ATSMB2_RSP_TOUT = 0xFE;
-
- /*clear all status registers for safety*/
- *ATSMB2_SD_STS_0 |= 0xff;
- *ATSMB2_SD_STS_1 |= 0xff;
- *ATSMB2_SD_STS_2 |= 0xff;
- //*ATSMB2_SD_STS_2 |= 0x7f;
- *ATSMB2_SD_STS_3 |= 0xff;
-
- //set block length and block count for cmd requesting data
- *ATSMB2_BLK_LEN &=~(0x07ff);
- *ATSMB2_BLK_LEN |= blk_len;
- //*ATSMB2_SHDW_BLKLEN = blk_len;
- *ATSMB2_BLK_CNT = blk_cnt;
-
-
- *ATSMB2_INT_MASK_0 |= int_maks_0;
-
- /* spin_lock add by th for fix sdio irq*/
- spin_lock_irqsave(&host->lock, spl_flags);
- *ATSMB2_INT_MASK_1 |= int_mask_1;
- spin_unlock_irqrestore(&host->lock, spl_flags);
-
- //Set Auto stop for Multi-block access
- if(cmd_type == 3 || cmd_type == 4)
- {
- //auto stop command set.
- *ATSMB2_EXT_CTL |= 0x01;
-
-/*
- * Enable transaction abort.
- * When CRC error occurs, CMD 12 would be automatically issued.
- * That is why we cannot enable R/W CRC error INTs.
- * If we enable CRC error INT, we would handle this INT in ISR and then issue CMD 12 via software.
- */
- *ATSMB2_BLK_LEN |= 0x0800;
- }
-
- /*Set read or write*/
- if (op == 1)
- *ATSMB2_CTL &= ~(0x04);
- else if (op == 2)
- *ATSMB2_CTL |= 0x04;
-
- /*for Non data access command, command type is 0.*/
- *ATSMB2_CTL &= 0x0F;
- *ATSMB2_CTL |= (cmd_type<<4);
- DBG("[%s] e\n",__func__);
-}
-
-static inline void atsmb2_issue_cmd(void)
-{
- *ATSMB2_CTL |= ATSMB_START;
- wmb();
-}
-/**********************************************************************
-Name : atsmb2_request_end
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static void
-atsmb2_request_end(struct atsmb_host *host, struct mmc_request *mrq)
-{
- DBG("[%s] s\n",__func__);
- /*
- * Need to drop the host lock here; mmc_request_done may call
- * back into the driver...
- */
- //kevin delete spin lock
- //spin_unlock(&host->lock);
- /*DBG("100");*/
- mmc_request_done(host->mmc, mrq);
- /*DBG("101\n");*/
- //spin_lock(&host->lock);
- DBG("[%s] e\n",__func__);
-}
-
-/**********************************************************************
-Name : atsmb2_data_done
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-void atsmb2_wait_done(void *data)
-{
- struct atsmb_host *host = (struct atsmb_host *) data;
- DBG("[%s] s\n",__func__);
-
- WARN_ON(host->done_data == NULL);
- complete(host->done_data);
- host->done_data = NULL;
- host->done = NULL;
- DBG("[%s] e\n",__func__);
-}
-
-/**********************************************************************
-wait_data_busy
-waiting for previous data transfer done
-**********************************************************************/
-void wait_data_busy(struct mmc_command *cmd)
-{
- int wait_count = 500000;
-
- switch(cmd->opcode) {
- case MMC_GO_IDLE_STATE:
- case MMC_STOP_TRANSMISSION:
- case MMC_SEND_STATUS:
- case MMC_GO_INACTIVE_STATE:
- break;
- default:
- do {
- if (*ATSMB2_CURBLK_CNT & (0x01<<24))
- break;
-
- udelay(1);
-
- } while (--wait_count);
- }
-
-}
-/**********************************************************************
-Name : atsmb2_start_data
-Function : If we start data, there must be only four cases.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static void atsmb2_start_data(struct atsmb_host *host)
-{
- DECLARE_COMPLETION(complete);
- unsigned char cmd_type = 0;
- unsigned char op = 0; /*0: non-operation; 1:read; 2: write*/
- unsigned char mask_0 = 0;
- unsigned char mask_1 = 0;
- unsigned long dma_mask = 0;
-
- struct mmc_data *data = host->data;
- struct mmc_command *cmd = host->cmd;
-
- struct scatterlist *sg = NULL;
- unsigned int sg_len = 0;
-
- unsigned int total_blks = 0; /*total block number to transfer*/
- u32 card_addr = 0;
- unsigned long dma_len = 0;
- unsigned long total_dma_len = 0;
- dma_addr_t dma_phy = 0; /* physical address used for DMA*/
- unsigned int dma_times = 0; /*times dma need to transfer*/
- unsigned int dma_loop = 0;
- unsigned int sg_num = 0;
- int loop_cnt = 10000;
- unsigned int sg_transfer_len = 0; /*record each time dma transfer sg length */
-
- DBG("[%s] s\n",__func__);
- data->bytes_xfered = 0;
- cmd->error = 0;
- data->error = 0;
-
- /*for loop*/
- sg = data->sg;
- sg_len = data->sg_len;
-
- dma_times = (sg_len / MAX_DESC_NUM);
- if (sg_len % MAX_DESC_NUM)
- dma_times++;
- DBG("dma_times = %d sg_len = %d sg = %x\n", dma_times, sg_len, sg);
- card_addr = cmd->arg; /*may be it is block-addressed, or byte-addressed.*/
- total_blks = data->blocks;
- dma_map_sg(&(host->mmc->class_dev), sg, sg_len,
- ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-
-
- for (dma_loop = 1 ; dma_loop <= dma_times; dma_loop++, sg_len -= sg_transfer_len) {
- DBG("dma_loop = %d sg_len = %d sg_transfer_len = %d\n", dma_loop, sg_len, sg_transfer_len);
- if (dma_loop < dma_times)
- sg_transfer_len = MAX_DESC_NUM;
- else
- sg_transfer_len = sg_len;
- DBG("sg_transfer_len = %d\n", sg_transfer_len);
- /*
- *Firstly, check and wait till card is in the transfer state.
- *For our hardware, we can not consider
- *the card has successfully tranfered its state from data/rcv to trans,
- *when auto stop INT occurs.
- */
- loop_cnt = 10000;
- do {
- if (host->cmd->opcode == SD_IO_RW_EXTENDED)
- break;
- loop_cnt--;
- WARN_ON(loop_cnt == 0);
- host->done_data = &complete;
- host->done = &atsmb2_wait_done;
- host->soft_timeout = 1;
- atsmb2_prep_cmd(host,
- MMC_SEND_STATUS,
- (host->mmc->card->rca)<<16,
- MMC_RSP_R1 | MMC_CMD_AC,
- 0,
- 0,
- 0, /*mask_0*/
- ATSMB_RSP_DONE_EN
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN,
- 0, /*cmd type*/
- 0); /*read or write*/
- atsmb2_issue_cmd();
- DBG("%16s = 0x%8x |", "INT_MASK_1", *ATSMB2_INT_MASK_1);
- DBG("%16s = 0x%8x \n", "SD_STS_1", *ATSMB2_SD_STS_1);
- /*ISR would completes it.*/
- wait_for_completion_timeout(&complete, ATSMB_TIMEOUT_TIME);
-
- WARN_ON(host->soft_timeout == 1);
- if (host->soft_timeout == 1) {
- DBG("%s soft_timeout.\n", __func__);
- atsmb2_dump_reg(host);
- }
- if (cmd->error != MMC_ERR_NONE) {
- cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("Getting Status failed.\n");
- goto end;
- }
- } while ((cmd->resp[0] & 0x1f00) != 0x900 && loop_cnt > 0); /*wait for trans state.*/
-
- /*
- * Now, we can safely issue read/write command.
- * We can not consider this request as multi-block acess or single one via opcode,
- * as request is splitted into sgs.
- * Some sgs may be single one, some sgs may be multi one.
- */
-
- dma_phy = sg_dma_address(sg);
- dma_len = sg_dma_len(sg);
- DBG("dma_len = %d data->blksz = %d sg_len = %d\n", dma_len, data->blksz, sg_len);
- /*SDIO read/write*/
- if (host->cmd->opcode == SD_IO_RW_EXTENDED) {
- /*Single Block read/write*/
- if ((dma_len / (data->blksz)) == 1 && (sg_len == 1)) {
- /* read operation*/
- if (data->flags & MMC_DATA_READ) {
- host->opcode = SD_IO_RW_EXTENDED;
- cmd_type = 2;
- op = 1;
- mask_0 = 0; /*BLOCK_XFER_DONE INT skipped, we use DMA TC INT*/
- mask_1 = (//ATSMB_SDIO_EN
- ATSMB_READ_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = SD_PDMA_CCR_Evt_success;
- DBG("[%s]SR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
- __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
- } else {
- /* write operation*/
- host->opcode = SD_IO_RW_EXTENDED;
- cmd_type = 1;
- op = 2;
- /*====That is what we want===== DMA TC INT skipped*/
- mask_0 = ATSMB_BLOCK_XFER_DONE_EN;
- mask_1 = (//ATSMB_SDIO_EN
- ATSMB_WRITE_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = 0;
- DBG("[%s]SW opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
- __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
- }
- } else {
- /*Multiple Block read/write*/
- /* read operation*/
- if (data->flags & MMC_DATA_READ) {
- host->opcode = SD_IO_RW_EXTENDED;
- cmd_type = 6;
- op = 1;
- mask_0 = 0; /*MULTI_XFER_DONE_EN skipped*/
- mask_1 = (//ATSMB_SDIO_EN /*====That is what we want=====*/
- ATSMB_READ_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = SD_PDMA_CCR_Evt_success;
- DBG("[%s]MR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
- __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
- } else {
- /* write operation*/
- host->opcode = SD_IO_RW_EXTENDED;
- cmd_type = 5;
- op = 2;
- mask_0 = ATSMB_MULTI_XFER_DONE_EN;//ATSMB_BLOCK_XFER_DONE_EN; /*MULTI_XFER_DONE INT skipped*/
- mask_1 = (//ATSMB_SDIO_EN /*====That is what we want=====*/
- ATSMB_WRITE_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = 0;
- DBG("[%s]MR opcode = %d type = 0x%x op = 0x%x m_0 = 0x%x m_1 = 0x%x d_m = 0x%x\n",
- __func__,host->opcode,cmd_type,op,mask_0,mask_1,dma_mask);
- }
- }
-
- } else {
- if ((dma_len / (data->blksz)) == 1 && (sg_len == 1)) {
- if (data->flags & MMC_DATA_READ) {/* read operation*/
- host->opcode = MMC_READ_SINGLE_BLOCK;
- cmd_type = 2;
- op = 1;
- mask_0 = 0; /*BLOCK_XFER_DONE INT skipped, we use DMA TC INT*/
- mask_1 = (ATSMB_READ_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = SD_PDMA_CCR_Evt_success;
- } else {/*write operation*/
- host->opcode = MMC_WRITE_BLOCK;
- cmd_type = 1;
- op = 2;
- /*====That is what we want===== DMA TC INT skipped*/
- mask_0 = ATSMB_BLOCK_XFER_DONE_EN;
- mask_1 = (ATSMB_WRITE_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = 0;
- }
- } else { /*more than one*/
- if (data->flags&MMC_DATA_READ) {/* read operation*/
- host->opcode = MMC_READ_MULTIPLE_BLOCK;
- cmd_type = 4;
- op = 1;
- mask_0 = 0; /*MULTI_XFER_DONE_EN skipped*/
- mask_1 = (ATSMB_AUTO_STOP_EN /*====That is what we want=====*/
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = 0;
- } else {/*write operation*/
- host->opcode = MMC_WRITE_MULTIPLE_BLOCK;
- cmd_type = 3;
- op = 2;
- mask_0 = 0; /*MULTI_XFER_DONE INT skipped*/
- mask_1 = (ATSMB_AUTO_STOP_EN /*====That is what we want=====*/
- |ATSMB_DATA_TIMEOUT_EN
- /*Data Timeout and CRC error */
- |ATSMB_RSP_CRC_ERR_EN
- |ATSMB_RSP_TIMEOUT_EN);
- /*Resp Timeout and CRC error */
- dma_mask = 0;
- }
- }
- }
- /*To controller every sg done*/
- host->done_data = &complete;
- host->done = &atsmb2_wait_done;
- /*sleep till ISR wakes us*/
- host->soft_timeout = 1; /*If INT comes early than software timer, it would be cleared.*/
-
- total_dma_len = 0;
- DBG("host->DescVirAddr = %x host->DescSize=%x\n", host->DescVirAddr, host->DescSize);
- memset(host->DescVirAddr, 0, host->DescSize);
- for (sg_num = 0 ; sg_num < sg_transfer_len ; sg++, sg_num++) {
-
- /*
- * Now, we can safely issue read/write command.
- * We can not consider this request as multi-block acess or single one via opcode,
- * as request is splitted into sgs.
- * Some sgs may be single one, some sgs may be multi one.
- */
-
- dma_phy = sg_dma_address(sg);
- dma_len = sg_dma_len(sg);
- total_dma_len = total_dma_len + dma_len;
- DBG("sg_num=%d sg_transfer_len=%d sg=%x sg_len=%d total_dma_len=%d dma_len=%d\n",
- sg_num, sg_transfer_len, sg, sg_len, total_dma_len, dma_len);
- /*2009/01/15 janshiue add*/
- if (sg_num < sg_transfer_len - 1) {
- /* means the last descporitor */
- atsmb2_init_short_desc(
- host->DescVirAddr + (sg_num * sizeof(struct SD_PDMA_DESC_S)/4),
- dma_len, (unsigned long *)dma_phy, 0);
- } else {
- atsmb2_init_short_desc(
- host->DescVirAddr + (sg_num * sizeof(struct SD_PDMA_DESC_S)/4),
- dma_len, (unsigned long *)dma_phy, 1);
- }
- /*2009/01/15 janshiue add*/
-
- }
- /*operate our hardware*/
- atsmb2_prep_cmd(host,
- host->opcode,
- /*arg, may be byte addressed, may be block addressed.*/
- card_addr,
- cmd->flags,
- data->blksz - 1, /* in fact, it is useless.*/
- /* for single one, it is useless. but for multi one, */
- /* it would be used to tell auto stop function whether it is done.*/
- total_dma_len/(data->blksz),
- mask_0,
- mask_1,
- cmd_type,
- op);
-
- atsmb2_config_dma((op == 1) ? DMA_CFG_READ : DMA_CFG_WRITE,
- dma_mask,
- host);
-
- wait_data_busy(cmd);
- //sync from tp,fix broadcom 6181 wifi dongle crash.
- //udelay(10);
- atsmb2_issue_cmd();
- wait_for_completion_timeout(&complete,
- ATSMB_TIMEOUT_TIME*sg_transfer_len); /*ISR would completes it.*/
-
- /* When the address of request plus length equal card bound,
- * force this stop command response as pass. Eason 2012/4/20 */
- if (cmd->resp[0] == 0x80000b00) {
- /*This caes used for SD2.0 and after MMC4.1 version*/
- if (card_addr+(total_dma_len/data->blksz) == host->mmc->card->csd.capacity) {
- cmd->resp[0] = 0x00000b00;
- /*printk("card_addr = %08X, card_length = %08X,card capacity = %08X\n",
- card_addr,(total_dma_len/data->blksz),host->mmc->card->csd.capacity);
- printk("card_resp[0]=%08X, addr = %08X\n",cmd->resp[0],cmd->resp);*/
- }
-
- /* This caes used for SD1.0 and before MMC 4.1 */
- if ((card_addr/data->blksz)+(total_dma_len/data->blksz) == host->mmc->card->csd.capacity) {
- cmd->resp[0] = 0x00000b00;
- /*printk("Eason test: cmd->arg = %08X, data->blksz = %08X, length = %08X\n",
- card_addr,data->blksz,(total_dma_len/data->blksz));*/
- }
- }
-
- if (host->soft_timeout == 1) {
- atsmb2_dump_reg(host);
- //*ATSMB2_BUS_MODE |= ATSMB_SFTRST;
- *ATSMB2_PDMA_GCR = SD_PDMA_GCR_SOFTRESET;
- /*disable INT */
- *ATSMB2_INT_MASK_0 &= ~(ATSMB_BLOCK_XFER_DONE_EN | ATSMB_MULTI_XFER_DONE_EN);
- *ATSMB2_INT_MASK_1 &= ~(ATSMB_WRITE_CRC_ERR_EN|ATSMB_READ_CRC_ERR_EN|ATSMB_RSP_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN|ATSMB_AUTO_STOP_EN|ATSMB_RSP_TIMEOUT_EN|ATSMB_RSP_DONE_EN);
-
- cmd->error = -ETIMEDOUT;
- data->error = -ETIMEDOUT;
- }
-
- WARN_ON(host->soft_timeout == 1);
-
- /*check everything goes okay or not*/
- if (cmd->error != MMC_ERR_NONE
- || data->error != MMC_ERR_NONE) {
- DBG("CMD or Data failed error=%X DescVirAddr=%8X dma_phy=%8X dma_mask = %x\n",
- cmd->error, host->DescVirAddr, dma_phy, host->DmaIntMask);
- goto end;
- }
-// card_addr += total_dma_len>>(mmc_card_blockaddr(host->mmc->card_selected) ? 9 : 0);
- card_addr += total_dma_len>>(mmc_card_blockaddr(host->mmc->card) ? 9 : 0); //zhf: modified by James Tian
- data->bytes_xfered += total_dma_len;
-
-
- }
-// dma_unmap_sg(&(host->mmc->class_dev), data->sg, data->sg_len,
-// ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
- WARN_ON(total_blks != (data->bytes_xfered / data->blksz));
- host->opcode = 0;
-end:
- dma_unmap_sg(&(host->mmc->class_dev), data->sg, data->sg_len,
- ((data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
- //kevin delete spin lock
- //spin_lock(&host->lock);
- atsmb2_request_end(host, host->mrq);
- //spin_unlock(&host->lock);
- DBG("[%s] e\n",__func__);
-}
-
-
-/**********************************************************************
-Name : atsmb2_cmd_with_data_back
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static void atsmb2_cmd_with_data_back(struct atsmb_host *host)
-{
- DECLARE_COMPLETION(complete);
-
- struct scatterlist *sg = NULL;
- unsigned int sg_len = 0;
- DBG("[%s] s\n",__func__);
- /*for loop*/
- sg = host->data->sg;
- sg_len = host->data->sg_len;
- /*To controller every sg done*/
- host->done_data = &complete;
- host->done = &atsmb2_wait_done;
- dma_map_sg(&(host->mmc->class_dev), sg, sg_len, DMA_FROM_DEVICE);
-
- /*2009/01/15 janshiue add*/
- memset(host->DescVirAddr, 0, host->DescSize);
- atsmb2_init_long_desc(host->DescVirAddr, sg_dma_len(sg), (unsigned long *)sg_dma_address(sg), 0, 1);
- /*2009/01/15 janshiue add*/
- /*prepare for cmd*/
- atsmb2_prep_cmd(host, /*host*/
- host->cmd->opcode, /*opcode*/
- host->cmd->arg, /*arg*/
- host->cmd->flags, /*flags*/
- sg_dma_len(sg)-1, /*block length*/
- 0, /*block size: It looks like useless*/
- 0, /*int_mask_0*/
- (ATSMB_RSP_CRC_ERR_EN|ATSMB_RSP_TIMEOUT_EN
- |ATSMB_READ_CRC_ERR_EN |ATSMB_DATA_TIMEOUT_EN), /*int_mask_1*/
- 2, /*cmd_type*/
- 1); /*op*/
-
- atsmb2_config_dma(DMA_CFG_READ,
- SD_PDMA_CCR_Evt_success,
- host);
- atsmb2_issue_cmd();
- /*ISR would completes it.*/
- wait_for_completion_timeout(&complete, ATSMB_TIMEOUT_TIME);
-
- dma_unmap_sg(&(host->mmc->class_dev), host->data->sg, host->data->sg_len,
- ((host->data->flags)&MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
- spin_lock(&host->lock);
- atsmb2_request_end(host, host->mrq);
- spin_unlock(&host->lock);
- DBG("[%s] e\n",__func__);
-}
-/**********************************************************************
-Name : atsmb2_start_cmd
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static void atsmb2_start_cmd(struct atsmb_host *host)
-{
- unsigned char int_mask_0,int_mask_1;
- int_mask_0 = 0;
- int_mask_1 = ATSMB_RSP_DONE_EN|ATSMB_RSP_CRC_ERR_EN|ATSMB_RSP_TIMEOUT_EN;
-
- DBG("[%s] s\n",__func__);
-
- atsmb2_prep_cmd(host,
- host->cmd->opcode,
- host->cmd->arg,
- host->cmd->flags,
- 0, /*useless*/
- 0, /*useless*/
- int_mask_0, /*mask_0*/
- int_mask_1, /*mask_1*/
- 0, /*cmd type*/
- 0); /*read or write*/
- atsmb2_issue_cmd();
- DBG("[%s] e\n",__func__);
-}
-/**********************************************************************
-Name : atsmb2_fmt_check_rsp
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static inline void atsmb2_fmt_check_rsp(struct atsmb_host *host)
-{
-
- u8 tmp_resp[4] = {0};
- int i, j, k;
- DBG("[%s] s\n",__func__);
- if (host->cmd->flags != (MMC_RSP_R2 | MMC_CMD_AC)
- && host->cmd->flags != (MMC_RSP_R2 | MMC_CMD_BCR)) {
- for (j = 0, k = 1; j < 4; j++, k++)
- tmp_resp[j] = *(REG8_PTR(_RSP_0 + MMC_ATSMB2_BASE+k));
-
- host->cmd->resp[0] = (tmp_resp[0] << 24) |
- (tmp_resp[1]<<16) | (tmp_resp[2]<<8) | (tmp_resp[3]);
- } else {
- for (i = 0, k = 1; i < 4; i++) { /*R2 has 4 u32 response.*/
- for (j = 0; j < 4; j++) {
- if (k < 16)
- tmp_resp[j] = *(REG8_PTR(_RSP_0 + MMC_ATSMB2_BASE+k));
- else /* k =16*/
- tmp_resp[j] = *(ATSMB2_RSP_0);
- k++;
- }
- host->cmd->resp[i] = (tmp_resp[0]<<24) | (tmp_resp[1]<<16) |
- (tmp_resp[2]<<8) | (tmp_resp[3]);
- }
- }
-
- /*
- * For the situation that we need response,
- * but response registers give us all zeros, we consider this operation timeout.
- */
- if (host->cmd->flags != (MMC_RSP_NONE | MMC_CMD_AC)
- && host->cmd->flags != (MMC_RSP_NONE | MMC_CMD_BC)) {
- if (host->cmd->resp[0] == 0 && host->cmd->resp[1] == 0
- && host->cmd->resp[2] == 0 && host->cmd->resp[3] == 0) {
- host->cmd->error = -ETIMEDOUT; //zhf: modified by James Tian
- }
- }
- DBG("[%s] e\n",__func__);
-}
-/**********************************************************************
-Name : atsmb2_get_slot_status
-Function : Our host only supports one slot.
-Calls :
-Called by :
-Parameter :
-returns : 1: in slot; 0: not in slot.
-Author : Leo Lee
-History :
-***********************************************************************/
-static int atsmb2_get_slot_status(struct mmc_host *mmc)
-{
-// struct atsmb_host *host = mmc_priv(mmc);
- unsigned char status_0 = 0;
-// unsigned long flags;
- unsigned long ret = 0;
- DBG("[%s] s\n",__func__);
-// spin_lock_irqsave(&host->lock, flags); // Vincent Li mark out for CONFIG_PREEMPT_RT
- status_0 = *ATSMB2_SD_STS_0;
-// spin_unlock_irqrestore(&host->lock, flags); // Vincent Li mark out for CONFIG_PREEMPT_RT
- /* after WM3400 A1 ATSMB_CARD_IN_SLOT_GPI = 1 means not in slot*/
- if (MMC2_DRIVER_VERSION >= MMC_DRV_3426_A0) {
- ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 0 : 1);
- DBG("[%s] e1\n",__func__);
- return ret;
- } else {
- ret = ((status_0 & ATSMB_CARD_NOT_IN_SLOT_GPI) ? 1 : 0);
- DBG("[%s] e2\n",__func__);
- return ret;
- }
- DBG("[%s] e3\n",__func__);
- return 0;
-}
-
-/**********************************************************************
-Name : atsmb2_init_short_desc
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Janshiue Wu
-History :
-***********************************************************************/
-int atsmb2_init_short_desc(unsigned long *DescAddr, unsigned int ReqCount, unsigned long *BufferAddr, int End)
-{
- struct SD_PDMA_DESC_S *CurDes_S;
- DBG("[%s] s\n",__func__);
- CurDes_S = (struct SD_PDMA_DESC_S *) DescAddr;
- CurDes_S->ReqCount = ReqCount;
- CurDes_S->i = 0;
- CurDes_S->format = 0;
- CurDes_S->DataBufferAddr = BufferAddr;
- if (End) {
- CurDes_S->end = 1;
- CurDes_S->i = 1;
- }
- DBG("[%s] e\n",__func__);
- return 0;
-}
-
-/**********************************************************************
-Name : atsmb2_init_long_desc
-Function :
-Calls :
-Called by :
-Parameter :
-Author : Janshiue Wu
-History :
-***********************************************************************/
-int atsmb2_init_long_desc(unsigned long *DescAddr, unsigned int ReqCount,
- unsigned long *BufferAddr, unsigned long *BranchAddr, int End)
-{
- struct SD_PDMA_DESC_L *CurDes_L;
- DBG("[%s] s\n",__func__);
- CurDes_L = (struct SD_PDMA_DESC_L *) DescAddr;
- CurDes_L->ReqCount = ReqCount;
- CurDes_L->i = 0;
- CurDes_L->format = 1;
- CurDes_L->DataBufferAddr = BufferAddr;
- CurDes_L->BranchAddr = BranchAddr;
- if (End) {
- CurDes_L->end = 1;
- CurDes_L->i = 1;
- }
- DBG("[%s] e\n",__func__);
- return 0;
-}
-
-/**********************************************************************
-Name : atsmb2_dma_isr
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static irqreturn_t atsmb2_dma_isr(int irq, void *dev_id)
-{
-
- struct atsmb_host *host = dev_id;
- u8 status_0, status_1, status_2, status_3;
- u32 pdma_event_code = 0;
- DBG("[%s] s\n",__func__);
-
- disable_irq_nosync(irq);
- spin_lock(&host->lock);
- /*Get INT status*/
- status_0 = *ATSMB2_SD_STS_0;
- status_1 = *ATSMB2_SD_STS_1;
- status_2 = *ATSMB2_SD_STS_2;
- status_3 = *ATSMB2_SD_STS_3;
- /* after WM3426 A0 using PDMA */
- if (MMC2_DRIVER_VERSION >= MMC_DRV_3426_A0) {
-
- pdma_event_code = *ATSMB2_PDMA_CCR & SD_PDMA_CCR_EvtCode;
-
- /* clear INT status to notify HW clear EventCode*/
- *ATSMB2_PDMA_ISR |= SD_PDMA_IER_INT_STS;
-
- /*printk("dma_isr event code = %X\n", *ATSMB2_PDMA_CCR);*/
- /*We expect cmd with data sending back or read single block cmd run here.*/
- if (pdma_event_code == SD_PDMA_CCR_Evt_success) {
- /*means need to update the data->error and cmd->error*/
- if (host->DmaIntMask == SD_PDMA_CCR_Evt_success) {
- if (host->data != NULL) {
- host->data->error = MMC_ERR_NONE;
- host->cmd->error = MMC_ERR_NONE;
- } else {
- DBG("dma_isr2 hodt->data is NULL\n");
- /*disable INT*/
- *ATSMB2_PDMA_IER &= ~SD_PDMA_IER_INT_EN;
- goto out;
- }
- }
- /*else do nothing*/
- DBG("dma_isr PDMA OK\n");
- /*atsmb2_dump_reg(host);*/
- }
- /*But unluckily, we should also be prepare for all kinds of error situation.*/
- else {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBGR("** dma_isr PDMA fail** event code = %X\n", *ATSMB2_PDMA_CCR);
- atsmb2_dump_reg(host);
- }
-
- if (host->DmaIntMask == SD_PDMA_CCR_Evt_success)
- atsmb2_fmt_check_rsp(host);
-
- /*disable INT*/
- *ATSMB2_PDMA_IER &= ~SD_PDMA_IER_INT_EN;
- }
-
- /*wake up some one who is sleeping.*/
- if ((pdma_event_code != SD_PDMA_CCR_Evt_success) || (host->DmaIntMask == SD_PDMA_CCR_Evt_success)) {
- if (host->done_data) {/* We only use done_data when requesting data.*/
- host->soft_timeout = 0;
- host->done(host);
- } else
- atsmb2_request_end(host, host->mrq); /*for cmd with data sending back.*/
- }
-
-out:
- spin_unlock(&host->lock);
- enable_irq(irq);
- DBG("[%s] e\n",__func__);
- return IRQ_HANDLED;
-}
-
-/* add by th for ack interrupt */
-void eagle_ack_interrupt(void)
-{
- *ATSMB2_SD_STS_1 |= ATSMB_SDIO_INT;
-}
-EXPORT_SYMBOL(eagle_ack_interrupt);
-
-/**********************************************************************
-Name : atsmb2_regular_isr
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-//static irqreturn_t atsmb2_regular_isr(int irq, void *dev_id, struct pt_regs *regs)
-irqreturn_t atsmb2_regular_isr(int irq, void *dev_id)
-{
-
- struct atsmb_host *host = dev_id;
- u8 status_0, status_1, status_2, status_3,mask_0,mask_1;
- u32 pdma_sts;
-
- DBG("[%s] s\n",__func__);
- WARN_ON(host == NULL);
-
- disable_irq_nosync(irq);
- spin_lock(&host->lock);
-
- /*Get INT status*/
- status_0 = *ATSMB2_SD_STS_0;
- status_1 = *ATSMB2_SD_STS_1;
- status_2 = *ATSMB2_SD_STS_2;
- status_3 = *ATSMB2_SD_STS_3;
-
- mask_0 = *ATSMB2_INT_MASK_0;
- mask_1 = *ATSMB2_INT_MASK_1;
- /*******************************************************
- card insert interrupt
- ********************************************************/
- if ((status_0 & ATSMB_DEVICE_INSERT) /*Status Set and IRQ enabled*/
- /*To aviod the situation that we intentionally disable IRQ to do rescan.*/
- && (*ATSMB2_INT_MASK_0 & 0x80)) {
-
- if (host->mmc->ops->get_slot_status(host->mmc)) {
- host->mmc->scan_retry = 3;
- host->mmc->card_scan_status = false;
- } else {
- host->mmc->scan_retry = 0;
- host->mmc->card_scan_status = false;
- }
-
- mmc_detect_change(host->mmc, HZ/2);
- /*Taipei Side Request: Disable INSERT IRQ when doing rescan.*/
- //*ATSMB2_INT_MASK_0 &= (~0x80);/* or 40?*/ //zhf: marked by James Tian
- /*Then we clear the INT status*/
- //iowrite32(ATSMB_DEVICE_INSERT, host->base+_SD_STS_0);
- *ATSMB2_SD_STS_0 |= ATSMB_DEVICE_INSERT;
- spin_unlock(&host->lock);
- enable_irq(irq);
- DBG("[%s] e1\n",__func__);
- return IRQ_HANDLED;
- }
-
- if ((status_1 & mask_1)& ATSMB_SDIO_INT) {
- spin_unlock(&host->lock);
- mmc_signal_sdio_irq(host->mmc);
-
- if (((status_1 & mask_1) == ATSMB_SDIO_INT) && ((status_0 & mask_0) == 0)) {
-
- enable_irq(irq);
- DBG("[%s] e2\n",__func__);
-
- return IRQ_HANDLED;
- }
- spin_lock(&host->lock);
- }
- pdma_sts = *ATSMB2_PDMA_CCR;
-
- if (((status_0 & mask_0) | (status_1 & mask_1)) == 0) {
- spin_unlock(&host->lock);
- enable_irq(irq);
- DBG("[%s] e3\n",__func__);
- return IRQ_HANDLED;
- }
- /*******************************************************
- command interrupt.
- *******************************************************/
- /*for write single block*/
- if (host->opcode == MMC_WRITE_BLOCK) {
- if ((status_0 & ATSMB_BLOCK_XFER_DONE)
- && (status_1 & ATSMB_RSP_DONE)) {
- host->data->error = MMC_ERR_NONE;
- host->cmd->error = MMC_ERR_NONE;
- /* okay, what we want.*/
- } else {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err1\n",__func__);
- atsmb2_dump_reg(host);
- }
- } else if (host->opcode == MMC_WRITE_MULTIPLE_BLOCK
- || host->opcode == MMC_READ_MULTIPLE_BLOCK) {
- if ((status_1 & (ATSMB_AUTO_STOP|ATSMB_RSP_DONE))
- && (status_0 & ATSMB_MULTI_XFER_DONE)) {
- /*If CRC error occurs, I think this INT would not occrs.*/
- /*okay, that is what we want.*/
- host->data->error = MMC_ERR_NONE;
- host->cmd->error = MMC_ERR_NONE;
- } else {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err2\n",__func__);
- atsmb2_dump_reg(host);
-
- }
- } else if (host->opcode == MMC_READ_SINGLE_BLOCK) {/* we want DMA TC, run here, must be error.*/
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err3\n",__func__);
- atsmb2_dump_reg(host);
- } else if (host->opcode == SD_IO_RW_EXTENDED){
- /*Write operation*/
- if (*ATSMB2_CTL & BIT2) {
- if ((*ATSMB2_CTL & 0xf0) == 0x10) { /*single block write*/
- if ((status_0 & ATSMB_BLOCK_XFER_DONE)
- && (status_1 & ATSMB_RSP_DONE)) {
- host->data->error = MMC_ERR_NONE;
- host->cmd->error = MMC_ERR_NONE;
- /* okay, what we want.*/
- } else {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err4 status_0 = %x status_1 = %x\n",__func__,status_0,status_1);
- }
-
- } else if ((*ATSMB2_CTL & 0xf0) == 0x50) {
- if ((status_0 & ATSMB_MULTI_XFER_DONE)
- && (status_1 & ATSMB_RSP_DONE)) {
- host->data->error = MMC_ERR_NONE;
- host->cmd->error = MMC_ERR_NONE;
- /* okay, what we want.*/
- } else {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err4-2 status_0 = %x status_1 = %x\n",__func__,status_0,status_1);
- }
- } else {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err4-3 status_0 = %x status_1 = %x\n",__func__,status_0,status_1);
- }
- }
- else {
- /*Read operation*/
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err5\n",__func__);
- }
-
-
- } else {
-/* command, not request data*/
-/* the command which need data sending back,*/
-/* like switch_function, send_ext_csd, send_scr, send_num_wr_blocks.*/
-/* NOTICE: we also send status before reading or writing data, so SEND_STATUS should be excluded.*/
- if (host->data && host->opcode != MMC_SEND_STATUS) {
- host->data->error = -EIO; //MMC_ERR_FAILED;
- host->cmd->error = -EIO; //MMC_ERR_FAILED;
- DBG("[%s] err6\n",__func__);
- atsmb2_dump_reg(host);
- } else { /* Just command, no need data sending back.*/
- if (status_1 & ATSMB_RSP_DONE) {
- /*Firstly, check data-response is busy or not.*/
- if (host->cmd->flags == (MMC_RSP_R1B | MMC_CMD_AC)) {
- int i = 10000;
-
- while (status_2 & ATSMB_RSP_BUSY) {
- status_2 = *ATSMB2_SD_STS_2;
- if (--i == 0)
- break;
- DBG(" IRQ:Status_2 = %d, busy!\n", status_2);
- }
- if (i == 0)
- printk("[MMC driver] Error :SD data-response always busy!");
- }
-#if 1
-/*for our host, even no card in slot, for SEND_STATUS also returns no error.*/
-/*The protocol layer depends on SEND_STATUS to check whether card is in slot or not.*/
-/*In fact, we can also avoid this situation by checking the response whether they are all zeros.*/
- if (!atsmb2_get_slot_status(host->mmc) && host->opcode == MMC_SEND_STATUS) {
- host->cmd->retries = 0; /* No retry.*/
-// host->cmd->error = MMC_ERR_INVALID;
- host->cmd->error = -EINVAL;
- } else
-#endif
- host->cmd->error = MMC_ERR_NONE;
- } else {
- if (status_1 & ATSMB_RSP_TIMEOUT) {/* RSP_Timeout .*/
-// host->cmd->error = MMC_ERR_TIMEOUT;
- host->cmd->error = -ETIMEDOUT;
- DBG("[%s] err7\n",__func__);
- } else {/*or RSP CRC error*/
-// host->cmd->error = MMC_ERR_BADCRC;
- host->cmd->error = -EILSEQ;
- DBG("[%s] err8\n",__func__);
- }
- atsmb2_dump_reg(host);
- }
- }
- }
- atsmb2_fmt_check_rsp(host);
-
- /*disable INT */
- *ATSMB2_INT_MASK_0 &= ~(ATSMB_BLOCK_XFER_DONE_EN | ATSMB_MULTI_XFER_DONE_EN);
- *ATSMB2_INT_MASK_1 &= ~(ATSMB_WRITE_CRC_ERR_EN|ATSMB_READ_CRC_ERR_EN|ATSMB_RSP_CRC_ERR_EN
- |ATSMB_DATA_TIMEOUT_EN|ATSMB_AUTO_STOP_EN|ATSMB_RSP_TIMEOUT_EN|ATSMB_RSP_DONE_EN);
-
-
- /*clear INT status. In fact, we will clear again before issuing new command.*/
- *ATSMB2_SD_STS_0 |= status_0;
- *ATSMB2_SD_STS_1 |= status_1;
- //*ATSMB2_SD_STS_1 |= ((status_1 & mask_1) | (status_1 & (~ATSMB_SDIO_INT)));
-
- /* when read CRC error occur, and the status can't write one to clear.
- * To clear read CRC error status , can do software reset. This is HW bug. 2013/3/21*/
- if ((*ATSMB2_SD_STS_1 & BIT6) == 0x40) {
- DBG("[%s] host2 CMD%d Read CRC error occur\n",__func__,host->cmd->opcode);
- /* Save SD card register */
- atsmb2_copy_reg(0);
- /* Software reset */
- *ATSMB2_BUS_MODE |= BIT7;
- /* restore SD card register */
- atsmb2_copy_reg(1);
- }
-
- if (*ATSMB2_PDMA_ISR & SD_PDMA_IER_INT_STS)
- *ATSMB2_PDMA_ISR |= SD_PDMA_IER_INT_STS;
-
- /*wake up some one who is sleeping.*/
- if (host->done_data) { /* We only use done_data when requesting data.*/
- host->soft_timeout = 0;
- host->done(host);
- } else
- atsmb2_request_end(host, host->mrq); /*for cmd without data.*/
-
- spin_unlock(&host->lock);
- enable_irq(irq);
- DBG("[%s] e4\n",__func__);
- return IRQ_HANDLED;
-}
-EXPORT_SYMBOL(atsmb2_regular_isr);
-
-/**********************************************************************
-Name : atsmb2_get_ro
-Function :.
-Calls :
-Called by :
-Parameter :
-returns : 0 : write protection is disabled. 1: write protection is enabled.
-Author : Leo Lee
-History :
-***********************************************************************/
-int atsmb2_get_ro(struct mmc_host *mmc)
-{
- struct atsmb_host *host = mmc_priv(mmc);
- unsigned char status_0 = 0;
- unsigned long flags;
- unsigned long ret = 0;
- DBG("[%s] s\n",__func__);
- spin_lock_irqsave(&host->lock, flags);
- status_0 = *ATSMB2_SD_STS_0;
- spin_unlock_irqrestore(&host->lock, flags);
- DBG("[%s]\nstatus_0 = 0x%x\n", __func__,status_0);
- ret = ((status_0 & ATSMB_WRITE_PROTECT) ? 0 : 1);
- DBG("[%s] e\n",__func__);
- return ret;
-}
-/**********************************************************************
-Name : atsmb2_dump_host_regs
-Function :
-Calls :
-Called by :
-Parameter :
-returns :
-Author : Leo Lee
-History :
-***********************************************************************/
-void atsmb2_dump_host_regs(struct mmc_host *mmc)
-{
- struct atsmb_host *host = mmc_priv(mmc);
- DBG("[%s] s\n",__func__);
- atsmb2_dump_reg(host);
- DBG("[%s] e\n",__func__);
-}
-EXPORT_SYMBOL(atsmb2_dump_host_regs);
-
-
-
-
-#if MMC2_SDIO_EXT_IRQ
-static irqreturn_t mtk6620_sdio_ext_irq (int irq, void *dev_id)
-{
- struct mmc_host *mmc = dev_id;
-
- if(!is_gpio_irqenable(wmt_mtk6620_intr) || !gpio_irqstatus(wmt_mtk6620_intr))
- return IRQ_NONE;
-
- smp_rmb();
- if (unlikely(test_bit(IN_SUSPEND, &mmc2_sdio_ext_irq_flags))) {
- //disable_irq_nosync(mmc2_sdio_ext_irq);
- wmt_gpio_mask_irq(wmt_mtk6620_intr);
-
- set_bit(IRQ_IN_SUSPEND, &mmc2_sdio_ext_irq_flags);
- smp_wmb();
-
- printk( "%s: irq in suspend, defer & disable_irq(%d)\n",
- mmc_hostname(mmc), mmc2_sdio_ext_irq);
- wmt_gpio_ack_irq(wmt_mtk6620_intr);
- return IRQ_HANDLED;
- }
- //printk( "%s: irq happen, call mmc_signal_sdio_irq\n", mmc_hostname(mmc));
- mmc_signal_sdio_irq(mmc);
- wmt_gpio_ack_irq(wmt_mtk6620_intr);
- return IRQ_HANDLED;
-}
-
-static void mtk6620_setup_sdio_ext_irq (struct mmc_host *mmc)
-{
- int ret;
- printk(KERN_WARNING "setup sdio ext irq but mmc2_sdio_ext_irq(%d) != 0!\n", mmc2_sdio_ext_irq);
-
- if (0 != mmc2_sdio_ext_irq) {
- return;
- }
-
- wmt_gpio_setpull(wmt_mtk6620_intr,WMT_GPIO_PULL_UP);
-
-// s3c_gpio_setpull(MMC2_SDIO_EINT_PIN, S3C_GPIO_PULL_NONE);
-// s3c_gpio_cfgpin(MMC2_SDIO_EINT_PIN, S3C_GPIO_SFN(0xF));
-
- mmc2_sdio_ext_irq = 1;//gpio_to_irq(MMC2_SDIO_EINT_PIN);
-
- wmt_gpio_mask_irq(wmt_mtk6620_intr);
- //clear_gpio26_irq_state();
- wmt_gpio_ack_irq(wmt_mtk6620_intr);
-
-
- ret = request_irq(IRQ_GPIO, mtk6620_sdio_ext_irq, IRQF_SHARED,"mmc2_sdio_ext_irq", mmc);
- if (ret) {
- printk( "request_irq(%d, 0x%p, IRQF_TRIGGER_LOW) fail(%d)!!\n",
- mmc2_sdio_ext_irq, mtk6620_sdio_ext_irq, ret);
- mmc2_sdio_ext_irq = 0;
- return;
- }
-
- /*clear int status register before enable this int pin*/
- wmt_gpio_ack_irq(wmt_mtk6620_intr);
- /*enable this int pin*/
- wmt_gpio_unmask_irq(wmt_mtk6620_intr);
-
-// enable_irq_wake(mmc2_sdio_ext_irq);
- printk("%s: using sdio_ext_irq and enable_irq_wake(%d) gpio(%d) IRQ_EINT(%d)\n",
- mmc_hostname(mmc), mmc2_sdio_ext_irq, wmt_mtk6620_intr,
- (IRQ_GPIO));
- return;
-}
-#endif /* MMC2_SDIO_EXT_IRQ */
-
-
-
-
-/**********************************************************************
-Name : atsmb2_enable_sdio_irq
-Function :
-Calls :
-Called by :
-Parameter :
-returns :
-Author : Tommy Huang
-History :
-***********************************************************************/
-static void atsmb2_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
- struct atsmb_host *host = mmc_priv(mmc);
- unsigned long flags;
-
- DBG("[%s] s enable = %d *ATSMB2_INT_MASK_1 = %x\n",__func__,enable,*ATSMB2_INT_MASK_1);
- spin_lock_irqsave(&host->lock, flags);
-
-
-#if MMC2_SDIO_EXT_IRQ
- if (is_mtk6620) {
- if (enable&&enable_wifi_irq) {
- if (likely(0 != mmc2_sdio_ext_irq)) {
- //enable_irq(mmc2_sdio_ext_irq);
- wmt_gpio_unmask_irq(wmt_mtk6620_intr);
- }
- else {
- mtk6620_setup_sdio_ext_irq(mmc);
- }
- }
- else {
- smp_rmb();
- if (unlikely(test_and_clear_bit(IRQ_IN_SUSPEND, &mmc2_sdio_ext_irq_flags))) {
- smp_wmb();
- printk("%s: irq already disabled when being deferred(%d)\n",
- mmc_hostname(host->mmc), mmc2_sdio_ext_irq);
- /* do nothing */
- }
- else {
- //disable_irq_nosync(mmc2_sdio_ext_irq);
- wmt_gpio_mask_irq(wmt_mtk6620_intr);
- }
- }
- goto out;
- }
-#endif /* MMC2_SDIO_EXT_IRQ */
-
-
-
- if (enable) {
- *ATSMB2_INT_MASK_1 |= ATSMB_SDIO_EN;
- } else {
- *ATSMB2_INT_MASK_1 &= ~ATSMB_SDIO_EN;
- }
-out:
- spin_unlock_irqrestore(&host->lock, flags);
- DBG("[%s] e\n",__func__);
-
-}
-void wmt_detect_sdio2(void){
-
- if(mmc2_host_attr!=NULL){
-
- struct atsmb_host *host = mmc_priv(mmc2_host_attr);
-
- mmc_detect_change(host->mmc, HZ/2);
- }
-}
-
-
-void force_remove_sdio2(void)
-{
- if(mmc2_host_attr!=NULL)
- mmc_force_remove_card(mmc2_host_attr);
-}
-
-void rda_mci_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
- enable_wifi_irq = (unsigned int )enable;
- atsmb2_enable_sdio_irq(mmc, enable);
-}
-
-EXPORT_SYMBOL(rda_mci_enable_sdio_irq);
-
-EXPORT_SYMBOL(wmt_detect_sdio2);
-EXPORT_SYMBOL(force_remove_sdio2);
-/**********************************************************************
-Name : atsmb2_request
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static void atsmb2_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
-
- struct atsmb_host *host = mmc_priv(mmc);
- DBG("[%s] s\n",__func__);
-
- /* May retry process comes here.*/
- host->mrq = mrq;
- host->data = mrq->data;
- host->cmd = mrq->cmd;
- host->done_data = NULL;
- host->done = NULL;
-
- /*for data request*/
- if (host->data) {
- if (host->cmd->opcode == MMC_WRITE_BLOCK
- || host->cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK
- || host->cmd->opcode == MMC_READ_SINGLE_BLOCK
- || host->cmd->opcode == MMC_READ_MULTIPLE_BLOCK
- || host->cmd->opcode == SD_IO_RW_EXTENDED) {
- atsmb2_start_data(host);
- } else {
- atsmb2_cmd_with_data_back(host);
- }
- } else {
- atsmb2_start_cmd(host);
- }
- DBG("[%s] e\n",__func__);
-}
-/**********************************************************************
-Name : atsmb2_set_clock
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Eason Chien
-History :2012/7/19
-***********************************************************************/
-static int atsmb2_set_clock(struct mmc_host *mmc, unsigned int clock)
-{
- if (clock == mmc->f_min) {
- DBG("[%s]ATSMB2 Host 400KHz\n", __func__);
- return auto_pll_divisor(DEV_SDMMC2, SET_DIV, 1, 390);
- } else if (clock >= 50000000) {
- DBG("[%s]ATSMB2 Host 50MHz\n", __func__);
- return auto_pll_divisor(DEV_SDMMC2, SET_DIV, 2, 45);
- } else if ((clock >= 25000000) && (clock < 50000000)) {
- DBG("[%s]ATSMB2 Host 25MHz\n", __func__);
- return auto_pll_divisor(DEV_SDMMC2, SET_DIV, 2, 24);
- } else if ((clock >= 20000000) && (clock < 25000000)) {
- DBG("[%s]ATSMB2 Host 20MHz\n", __func__);
- return auto_pll_divisor(DEV_SDMMC2, SET_DIV, 2, 20);
- } else {
- DBG("[%s]ATSMB2 Host 390KHz\n", __func__);
- return auto_pll_divisor(DEV_SDMMC2, SET_DIV, 1, 390);
- }
-}
-
-/**********************************************************************
-Name : atsmb2_set_ios
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static void atsmb2_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-
- struct atsmb_host *host = mmc_priv(mmc);
- unsigned long flags;
- DBG("[%s] s\n",__func__);
- spin_lock_irqsave(&host->lock, flags);
-#if MMC2_SDIO_EXT_IRQ
- if(is_mtk6620){
- if ((ios->power_mode == MMC_POWER_OFF)) {
- if (0 != mmc2_sdio_ext_irq) {
- printk("%s: set mmc2 MMC_POWER_OFF disable_irq_wake & free_irq(%d)!\n", __func__, mmc2_sdio_ext_irq);
- //disable_irq_wake(mmc2_sdio_ext_irq);
- wmt_gpio_mask_irq(wmt_mtk6620_intr);
- free_irq(IRQ_GPIO, host->mmc);
- mmc2_sdio_ext_irq = 0;
- }
- }
- }
-#endif /* MMC2_SDIO_EXT_IRQ */
-
-
- if (ios->power_mode == MMC_POWER_OFF) {
- if (MMC2_DRIVER_VERSION == MMC_DRV_3498) {
- /* stop SD output clock */
- *ATSMB2_BUS_MODE &= ~(ATSMB_CST);
-
- /* disable SD Card power */
- /*set SD2 power pin as GPO pin*/
- if (SD2_function == SDIO_WIFI)
- ;//GPIO_OC_GP0_BYTE_VAL |= BIT6;
- else {
- GPIO_CTRL_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER;
- GPIO_OC_GP19_SD2_BYTE_VAL|= GPIO_SD2_POWER;
- }
-
- /*set internal pull up*/
- PULL_CTRL_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER;
- /*set internal pull enable*/
- PULL_EN_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER;
- /*disable SD2 power*/
- if (SD2_function == SDIO_WIFI)
- GPIO_OD_GP0_BYTE_VAL &= ~BIT6;
- else
- GPIO_OD_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER;
-
- /* Disable Pull up/down resister of SD Bus */
- PULL_CTRL_GP19_SD2_BYTE_VAL &= ~SD2_PIN;
-
- /* Config SD2 to GPIO */
- GPIO_CTRL_GP19_SD2_BYTE_VAL |= SD2_PIN;
-
- /* SD2 all pins output low */
- GPIO_OD_GP19_SD2_BYTE_VAL &= ~SD2_PIN;
-
- /* Config SD2 to GPIO */
- GPIO_OC_GP19_SD2_BYTE_VAL |= SD2_PIN;
- }
- } else if (ios->power_mode == MMC_POWER_UP) {
- if (MMC2_DRIVER_VERSION == MMC_DRV_3498) {
- /* disable SD Card power */
- /*set SD2 power pin as GPO pin*/
- if (SD2_function == SDIO_WIFI)
- ;//GPIO_OC_GP0_BYTE_VAL |= BIT6;
- else {
- GPIO_CTRL_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER;
- GPIO_OC_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER;
- }
-
- /*set internal pull up*/
- PULL_CTRL_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER;
- /*set internal pull enable*/
- PULL_EN_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER;
- /*disable SD2 power*/
- if (SD2_function == SDIO_WIFI)
- GPIO_OD_GP0_BYTE_VAL &= ~BIT6;
- else
- GPIO_OD_GP19_SD2_BYTE_VAL |= GPIO_SD2_POWER;
-
- /* Config SD PIN share */
- //kevin delete for dvfs
- //PIN_SHARING_SEL_4BYTE_VAL |= GPIO_SD2_PinShare;
-
- /* do not config GPIO_SD2_CD because ISR has already run,
- * config card detect will issue ISR storm.
- */
- /* Config SD to GPIO */
- GPIO_CTRL_GP19_SD2_BYTE_VAL |= SD2_PIN;
-
- /* SD all pins output low */
- GPIO_OD_GP19_SD2_BYTE_VAL &= ~SD2_PIN;
-
- /* Config SD to GPO */
- GPIO_OC_GP19_SD2_BYTE_VAL |= SD2_PIN;
-
- /* Pull up/down resister of SD Bus */
- /*Disable Clock & CMD Pull enable*/
- PULL_EN_GP19_SD2_BYTE_VAL &= ~(GPIO_SD2_Clock );
-
- /*Set CD ,WP ,DATA pin pull up*/
- if (SD2_function == SDIO_WIFI) {
- PULL_CTRL_GP23_I2C3_BYTE_VAL &= ~GPIO_SD2_CD; /*pull down card always in slot*/
- PULL_CTRL_GP19_SD2_BYTE_VAL |= (GPIO_SD2_Data | GPIO_SD2_WriteProtect|GPIO_SD2_Command);
- } else {
- PULL_CTRL_GP23_I2C3_BYTE_VAL |= GPIO_SD2_CD;
- PULL_CTRL_GP19_SD2_BYTE_VAL |= (GPIO_SD2_Data | GPIO_SD2_WriteProtect|GPIO_SD2_Command);
- }
-
- /*Enable CD ,WP ,DATA internal pull*/
- PULL_EN_GP23_I2C3_BYTE_VAL |= GPIO_SD2_CD;
- PULL_EN_GP19_SD2_BYTE_VAL |= (GPIO_SD2_Data | GPIO_SD2_WriteProtect|GPIO_SD2_Command);
-
- spin_unlock_irqrestore(&host->lock, flags);
- msleep(100);
- spin_lock_irqsave(&host->lock, flags);
-
- /* enable SD Card Power */
- if (SD2_function == SDIO_WIFI)
- GPIO_OD_GP0_BYTE_VAL |= BIT6;
- else
- GPIO_OD_GP19_SD2_BYTE_VAL &= ~GPIO_SD2_POWER;
-
- /* enable SD output clock */
- *ATSMB2_BUS_MODE |= ATSMB_CST;
-
- spin_unlock_irqrestore(&host->lock, flags);
- msleep(10);
- spin_lock_irqsave(&host->lock, flags);
-
- /* Config SD0 back to function */
- GPIO_CTRL_GP23_I2C3_BYTE_VAL &= ~GPIO_SD2_CD;
- GPIO_CTRL_GP19_SD2_BYTE_VAL &= ~SD2_PIN;
- }
- } else {
- /*nothing to do when powering on.*/
- }
-
- host->current_clock = atsmb2_set_clock(mmc,ios->clock);
-
- if (ios->bus_width == MMC_BUS_WIDTH_8) {
- *ATSMB2_EXT_CTL |= (0x04);
- } else if (ios->bus_width == MMC_BUS_WIDTH_4) {
- *ATSMB2_BUS_MODE |= ATSMB_BUS_WIDTH_4;
- *ATSMB2_EXT_CTL &= ~(0x04);
- } else {
- *ATSMB2_BUS_MODE &= ~(ATSMB_BUS_WIDTH_4);
- *ATSMB2_EXT_CTL &= ~(0x04);
- }
-#if 1
- if (ios->timing == MMC_TIMING_SD_HS)
- *ATSMB2_EXT_CTL |= 0x80; /*HIGH SPEED MODE*/
- else
- *ATSMB2_EXT_CTL &= ~(0x80);
-#endif
-#if 0 //zhf: marked by James Tian
- if (ios->ins_en == MMC_INSERT_IRQ_EN)
- *ATSMB2_INT_MASK_0 |= (0x80);/* or 40?*/
- else
- *ATSMB2_INT_MASK_0 &= (~0x80);/* or 40?*/
-#endif
-
- spin_unlock_irqrestore(&host->lock, flags);
- DBG("[%s] e\n",__func__);
-}
-
-
-static const struct mmc_host_ops atsmb2_ops = {
- .request = atsmb2_request,
- .set_ios = atsmb2_set_ios,
- .get_ro = atsmb2_get_ro,
- .get_slot_status = atsmb2_get_slot_status,
- .dump_host_regs = atsmb2_dump_host_regs,
- .enable_sdio_irq = atsmb2_enable_sdio_irq,
-};
-
-extern int wmt_getsyspara(char *varname, unsigned char *varval, int *varlen);
-
-/**********************************************************************
-Name :atsmb2_probe
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static int __init atsmb2_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct mmc_host *mmc_host = NULL;
- struct atsmb_host *atsmb_host = NULL;
- struct resource *resource = NULL;
- int irq[2] = {0};
- int ret = 0;
-
- DBG("[%s] s\n",__func__);
- if (!pdev) {
- ret = -EINVAL; /* Invalid argument */
- goto the_end;
- }
-
- /*Enable SD host clock*/
- auto_pll_divisor(DEV_SDMMC2, CLK_ENABLE, 0, 0);
-
- if (MMC2_DRIVER_VERSION == MMC_DRV_3498) {
- /* enable SD1 PIN share */
- //kevin delete for dvfs
- //PIN_SHARING_SEL_4BYTE_VAL |= GPIO_SD2_PinShare;
-
- /* Pull up/down resister of SD CD */
- if (SD2_function == SDIO_WIFI) {
- PULL_CTRL_GP23_I2C3_BYTE_VAL &= ~GPIO_SD2_CD; /*pull down CD*/
- } else {
- PULL_CTRL_GP23_I2C3_BYTE_VAL |= GPIO_SD2_CD; /*pull up CD*/
- }
- PULL_EN_GP23_I2C3_BYTE_VAL |= GPIO_SD2_CD;
-
- /* config CardDetect pin to SD function */
- GPIO_CTRL_GP23_I2C3_BYTE_VAL &= ~GPIO_SD2_CD;
- }
-
-
- resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!resource) {
- ret = -ENXIO; /* No such device or address */
- printk(KERN_ALERT "[MMC/SD driver] Getting platform resources failed!\n");
- goto the_end;
- }
-#if 0
- if (!request_mem_region(resource->start, SZ_1K, MMC2_DRIVER_NAME)) {
- ret = -EBUSY;
- printk(KERN_ALERT "[MMC/SD driver] Request memory region failed!\n");
- goto the_end ;
- }
-#endif
- irq[0] = platform_get_irq(pdev, 0); /*get IRQ for device*/;
- irq[1] = platform_get_irq(pdev, 1); /*get IRQ for dma*/;
-
- if (irq[0] == NO_IRQ || irq[1] == NO_IRQ) {
- ret = -ENXIO;/* No such device or address */
- printk(KERN_ALERT "[MMC/SD driver] Get platform IRQ failed!\n");
- goto rls_region;
- }
-
- /*allocate a standard msp_host structure attached with a atsmb structure*/
- mmc_host = mmc_alloc_host(sizeof(struct atsmb_host), dev);
- if (!mmc_host) {
- ret = -ENOMEM;
- printk(KERN_ALERT "[MMC/SD driver] Allocating driver's data failed!\n");
- goto rls_region;
- }
- mmc_host->wmt_host_index = 2; /*to identify host number*/
-
- dev_set_drvdata(dev, (void *)mmc_host); /* mmc_host is driver data for the atsmb dev.*/
- atsmb_host = mmc_priv(mmc_host);
-
- mmc_host->ops = &atsmb2_ops;
-
- mmc_host->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
-
- mmc_host->f_min = 390425; /*390.425Hz = 400MHz/64/16*/
- mmc_host->f_max = 50000000; /* in fact, the max frequency is 400MHz( = 400MHz/1/1)*/
-
- if(!is_nmc1000){
- mmc_host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SDIO_IRQ| MMC_CAP_NONREMOVABLE;
- }else{
- mmc_host->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SDIO_IRQ| MMC_CAP_NONREMOVABLE;
- }
- /* |MMC_CAP_8_BIT_DATA;*/ //zhf: marked by James Tian
- mmc_host->pm_caps |= MMC_PM_KEEP_POWER;
- mmc_host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;//add by kevinguan for mtk6620
-
- mmc_host->max_segs = 128; /*we use software sg. so we could manage even larger number.*/
-
- /*1MB per each request */
- /*we have a 16 bit block number register, and block length is 512 bytes.*/
- mmc_host->max_req_size = 16*512*(mmc_host->max_segs);
- mmc_host->max_seg_size = 65024; /* 0x7F*512 PDMA one descriptor can transfer 64K-1 byte*/
- mmc_host->max_blk_size = 2048; /* our block length register is 11 bits.*/
- mmc_host->max_blk_count = (mmc_host->max_req_size)/512;
-
- /*set the specified host -- ATSMB*/
-#ifdef CONFIG_MMC_UNSAFE_RESUME
- mmc_host->card_attath_status = card_attach_status_unchange;
-#endif
- sema_init(&mmc_host->req_sema,1); /*initial request semaphore*/
-#if 0
- atsmb_host->base = ioremap(resource->start, SZ_1K);
- if (!atsmb_host->base) {
- printk(KERN_ALERT "[MMC/SD driver] IO remap failed!\n");
- ret = -ENOMEM;
- goto fr_host;
- }
-#endif
- atsmb_host->base = (void *)resource->start;
- atsmb_host->mmc = mmc_host;
- spin_lock_init(&atsmb_host->lock);
- atsmb_host->res = resource;/* for atsmb2_remove*/
-
- /*disable all interrupt and clear status by resetting controller.*/
- *ATSMB2_BUS_MODE |= ATSMB_SFTRST;
- *ATSMB2_BLK_LEN &= ~(0xa000);
- *ATSMB2_SD_STS_0 |= 0xff;
- *ATSMB2_SD_STS_1 |= 0xff;
-
- /* WM3437 A0 default not output clock, after SFTRST need to enable SD clock */
- //if (MMC2_DRIVER_VERSION >= MMC_DRV_3437_A0) /* including 3429 */
- *ATSMB2_BUS_MODE |= ATSMB_CST;
-
- atsmb_host->regular_irq = irq[0];
- atsmb_host->dma_irq = irq[1];
-
- ret = request_irq(atsmb_host->regular_irq,
- atsmb2_regular_isr,
- IRQF_SHARED, //SA_SHIRQ, /*SA_INTERRUPT, * that is okay?*/ //zhf: modified by James Tian, should be IRQF_SHARED?
- MMC2_DRIVER_NAME,
- (void *)atsmb_host);
- if (ret) {
- printk(KERN_ALERT "[MMC/SD driver] Failed to register regular ISR!\n");
- goto unmap;
- }
-
- ret = request_irq(atsmb_host->dma_irq,
- atsmb2_dma_isr,
- IRQF_DISABLED, // SA_INTERRUPT, //zhf: modified by James Tian
- MMC2_DRIVER_NAME,
- (void *)atsmb_host);
- if (ret) {
- printk(KERN_ALERT "[MMC/SD driver] Failed to register DMA ISR!\n");
- goto fr_regular_isr;
- }
-
-
- /*wait card detect status change*/
- //msleep(10);
-
- /*enable card insertion interrupt and enable DMA and its Global INT*/
- *ATSMB2_BLK_LEN |= (0xa000); /* also, we enable GPIO to detect card.*/
- *ATSMB2_SD_STS_0 |= 0xff;
- *ATSMB2_INT_MASK_0 |= 0x80; /*or 0x40?*/
-
- /*allocation dma descriptor*/
- ret = atsmb2_alloc_desc(atsmb_host, sizeof(struct SD_PDMA_DESC_S) * MAX_DESC_NUM);
- if (ret == -1) {
- printk(KERN_ALERT "[MMC/SD driver] Failed to allocate DMA descriptor!\n");
- goto fr_dma_isr;
- }
- printk(KERN_INFO "WMT ATSMB2 (AHB To SD/MMC2 Bus) controller registered!\n");
-
- if (SD2_function == SDIO_WIFI){
- if(set_bus_dead){
- mmc_host->bus_dead = 1; //fix this problem: mmc1: error -110 during resume (card was removed?)
- }else
- printk("dont set bus dead in probe function\n");
- mmc_add_host(mmc_host,false);
- }else
- mmc_add_host(mmc_host,true);
-
- mmc2_host_attr = mmc_host;
- DBG("[%s] e1\n",__func__);
- return 0;
-
-fr_dma_isr:
- free_irq(atsmb_host->dma_irq, atsmb_host);
-fr_regular_isr:
- free_irq(atsmb_host->regular_irq, atsmb_host);
-unmap:
- //iounmap(atsmb_host->base);
-//fr_host:
- dev_set_drvdata(dev, NULL);
- mmc_free_host(mmc_host);
-rls_region:
- //release_mem_region(resource->start, SZ_1K);
-the_end:
- printk(KERN_ALERT "[MMC/SD driver] ATSMB2 probe Failed!\n") ;
- DBG("[%s] e2\n",__func__);
- return ret;
-}
-/**********************************************************************
-Name : atsmb2_remove
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static int atsmb2_remove(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct mmc_host *mmc_host = (struct mmc_host *)dev_get_drvdata(dev);
- struct atsmb_host *atsmb_host;
-
- DBG("[%s] s\n",__func__);
- atsmb_host = mmc_priv(mmc_host);
- if (!mmc_host || !atsmb_host) {
- printk(KERN_ALERT "[MMC/SD driver] ATSMB2 remove method failed!\n");
- DBG("[%s] e1\n",__func__);
- return -ENXIO;
- }
- mmc_remove_host(mmc_host);
-
- /*disable interrupt by resetting controller -- for safey*/
- *ATSMB2_BUS_MODE |= ATSMB_SFTRST;
- *ATSMB2_BLK_LEN &= ~(0xa000);
- *ATSMB2_SD_STS_0 |= 0xff;
- *ATSMB2_SD_STS_1 |= 0xff;
-
- (void)free_irq(atsmb_host->regular_irq, atsmb_host);
- (void)free_irq(atsmb_host->dma_irq, atsmb_host);
- (void)iounmap(atsmb_host->base);
- (void)release_mem_region(atsmb_host->res->start, SZ_1K);
- dev_set_drvdata(dev, NULL);
- /*free dma descriptor*/
- dma_free_coherent(atsmb_host->mmc->parent, atsmb_host->DescSize,
- atsmb_host->DescVirAddr, atsmb_host->DescPhyAddr);
- (void)mmc_free_host(mmc_host);/* also free atsmb_host.*/
- DBG("[%s] e2\n",__func__);
- return 0;
-}
-
-/**********************************************************************
-Name : atsmb2_shutdown
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Tommy Huang
-History :
-***********************************************************************/
-static void atsmb2_shutdown(struct platform_device *pdev)
-{
- /*atsmb2_shutdown don't be used now.*/
- /*struct device *dev = &pdev->dev;
- struct mmc_host *mmc_host = (struct mmc_host *)dev_get_drvdata(dev);*/
-
- DBG("[%s] s\n",__func__);
- if (SD2_function != SDIO_WIFI) {
- /*Disable card detect interrupt*/
- *ATSMB2_INT_MASK_0 &= ~0x80;
- }
- DBG("[%s] e\n",__func__);
-
-}
-
-/**********************************************************************
-Name : atsmb2_suspend
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-int SD2_card_state = 0; /*0: card remove >=1: card enable*/
-
-#ifdef CONFIG_PM
-static int atsmb2_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct device *dev = &pdev->dev;
- struct mmc_host *mmc = (struct mmc_host *)dev_get_drvdata(dev);
- int ret = 0;
- DBG("[%s] s\n",__func__);
-
- if (mmc) {
-
- if (SD2_function == SDIO_WIFI) {
- if (SD2_card_state > 0)
- mmc_force_remove_card(mmc2_host_attr);
- }
-#if MMC2_SDIO_EXT_IRQ
- if (is_mtk6620) {
- if (0 != mmc2_sdio_ext_irq) {
- //if (mmc_try_claim_host(host->mmc)) {
- if(true){
- set_bit(IN_SUSPEND, &mmc2_sdio_ext_irq_flags);
- printk(KERN_INFO "%s:in_suspend++\n", mmc_hostname(mmc));
- }
- else {
- printk(KERN_INFO "%s:claim host fail in suspend, return -EBUSY\n", mmc_hostname(mmc));
- return -EBUSY;
- }
- }
- }
-#endif /* MMC2_SDIO_EXT_IRQ */
-
- /*struct atsmb_host *host = mmc_priv(mmc);*/
- ret = mmc_suspend_host(mmc);
-
-#if MMC2_SDIO_EXT_IRQ
- if (is_mtk6620) {
- if (ret) {
- printk("\n\n\n\n\n\n%s:mmc_suspend_host fail(%d)\n\n\n\n\n\n",
- mmc_hostname(mmc), ret);
- if (0 != mmc2_sdio_ext_irq) {
- clear_bit(IN_SUSPEND, &mmc2_sdio_ext_irq_flags);
- //mmc_release_host(host->mmc);
-
- }
- return ret;
- }
-
- }
-#endif
-
-
- if (ret == 0) {
- /*disable all interrupt and clear status by resetting controller. */
- *ATSMB2_BUS_MODE |= ATSMB_SFTRST;
- *ATSMB2_BLK_LEN &= ~(0xa000);
- *ATSMB2_SD_STS_0 |= 0xff;
- *ATSMB2_SD_STS_1 |= 0xff;
-
- }
- /*disable source clock*/
- auto_pll_divisor(DEV_SDMMC2, CLK_DISABLE, 0, 0);
-#ifdef CONFIG_MMC_UNSAFE_RESUME
- /*clean SD card attatch status change*/
- //PMCWS_VAL |= BIT19;
- mmc->card_attath_status = card_attach_status_unchange;
-#endif
- }
-
- DBG("[%s] e\n",__func__);
- return ret;
-}
-/**********************************************************************
-Name : atsmb2_resume
-Function :.
-Calls :
-Called by :
-Parameter :
-Author : Leo Lee
-History :
-***********************************************************************/
-static int atsmb2_resume(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct mmc_host *mmc = (struct mmc_host *)dev_get_drvdata(dev);
- int ret = 0;
- DBG("[%s] s\n",__func__);
-
- /*
- * enable interrupt, DMA, etc.
- * Supply power to slot.
- */
- if (mmc) {
- /*enable source clock*/
- auto_pll_divisor(DEV_SDMMC2, CLK_ENABLE, 0, 0);
-
- udelay(1);
- /*enable card insertion interrupt and enable DMA and its Global INT*/
- *ATSMB2_BUS_MODE |= ATSMB_SFTRST;
- *ATSMB2_BLK_LEN |= (0xa000);
- *ATSMB2_INT_MASK_0 |= 0x80; /* or 40?*/
-#ifdef CONFIG_MMC_UNSAFE_RESUME
- /*modify SD card attatch status change*/
- //if ((PMCWS_VAL & BIT19) && !mmc->bus_dead) {
- /*card change when suspend mode*/
- mmc->card_attath_status = card_attach_status_change;
- /*clean SD card attatch status change*/
- // PMCWS_VAL |= BIT19;
- //}
-#endif
- if (SD2_function == SDIO_WIFI) {
- PULL_CTRL_GP23_I2C3_BYTE_VAL &= ~GPIO_SD2_CD; /*pull down CD*/
- PULL_EN_GP23_I2C3_BYTE_VAL |= GPIO_SD2_CD;
-
- //kevin add for suspend&resume
- PULL_CTRL_GP19_SD2_BYTE_VAL |= GPIO_SD2_Data | GPIO_SD2_Command;
- PULL_CTRL_GP19_SD2_BYTE_VAL &= ~GPIO_SD2_WriteProtect;
- PULL_EN_GP19_SD2_BYTE_VAL |= (GPIO_SD2_Data | GPIO_SD2_WriteProtect|GPIO_SD2_Command);
- PULL_EN_GP19_SD2_BYTE_VAL &= ~GPIO_SD2_Clock;
- GPIO_CTRL_GP19_SD2_BYTE_VAL &= ~(GPIO_SD2_Data | GPIO_SD2_WriteProtect | GPIO_SD2_Command | GPIO_SD2_Clock);
- *ATSMB2_BUS_MODE |= ATSMB_CST;
- msleep(20);
-
-
- if (SD2_card_state > 0) {
- printk("[%s] mmc_resume_host s\n",__func__);
- mmc_detect_change(mmc2_host_attr, 1*HZ/2);
- printk("[%s] mmc_resume_host e\n",__func__);
- }
-
-
-#if MMC2_SDIO_EXT_IRQ
- if (is_mtk6620) {
- if (0 != mmc2_sdio_ext_irq) {
- /* sdhc goes back to normal working mode, after mtk6620_init() */
- clear_bit(IN_SUSPEND, &mmc2_sdio_ext_irq_flags);
- //mmc_release_host(host->mmc);
- printk(KERN_INFO "%s:in_suspend--\n", mmc_hostname(mmc));
- }
- }
-#endif /* MMC2_SDIO_EXT_IRQ */
-
-
-
- //kevin add for suspend&resume
- ret = mmc_resume_host(mmc);
-
-
-#if MMC2_SDIO_EXT_IRQ
- /* after mmc_resume_host(), sdio_func is also resumed */
- if (is_mtk6620) {
- if (0 != mmc2_sdio_ext_irq) {
- /* signal deferred irq if any */
- smp_rmb();
- if (unlikely(test_bit(IRQ_IN_SUSPEND, &mmc2_sdio_ext_irq_flags))) {
- printk(KERN_INFO "%s: signal deferred irq(%d)\n",
- mmc_hostname(mmc), mmc2_sdio_ext_irq);
- /* signal the deferred irq */
- mmc_signal_sdio_irq(mmc);
- }
- }
- }
-#endif
-
- } else {
- ret = mmc_resume_host(mmc);
- }
- }
-
- DBG("[%s] e\n",__func__);
- return ret;
-}
-#else
-#define atsmb2_suspend NULL
-#define atsmb2_resume NULL
-#endif
-
-static struct platform_driver atsmb2_driver = {
- .driver.name = "sdmmc2",
- //.probe = atsmb2_probe,
- .remove = atsmb2_remove,
- .shutdown = atsmb2_shutdown,
- .suspend = atsmb2_suspend,
- .resume = atsmb2_resume,
-};
-
-static struct platform_device wmt_sdmmc2_device = {
- .name = "sdmmc2",
- .id = 0,
- .dev = {
- .dma_mask = &wmt_sdmmc2_dma_mask,
- .coherent_dma_mask = ~0,
- .release = atsmb2_release,
- },
- .num_resources = ARRAY_SIZE(wmt_sdmmc2_resources),
- .resource = wmt_sdmmc2_resources,
-};
-
-static DEFINE_MUTEX(SD2_state_lock);
-
-static ssize_t atsmb2_state_show(struct kobject *kobj, struct kobj_attribute *attr,
- char *buf)
-{
- int ret = 0;
-
- DBG("[%s] s\n",__func__);
-
- ret = sprintf(buf, "%d\n", SD2_card_state);
- DBG("[%s]SD2_card_state = %d\n",__func__,SD2_card_state);
- DBG("[%s] e\n",__func__);
- return ret;
-}
-
-static ssize_t atsmb2_state_store(struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n)
-{
- int val;
- DBG("[%s] s\n",__func__);
-
- mutex_lock(&SD2_state_lock);
- if (sscanf(buf, "%d", &val) == 1) {
- DBG("[%s] val = %d\n",__func__,val);
- if (val == 1) {
- SD2_card_state++;
- DBG("[%s] add state SD2_card_state = %d\n",__func__,SD2_card_state);
- if ((SD2_card_state == 1) && (mmc2_host_attr->card == NULL)) {
- DBG("[%s]add card\n",__func__);
- mmc_detect_change(mmc2_host_attr, 0);
- msleep(1000);
- } else {
- msleep(1000); /*to prevent the card not init ready*/
- }
- } else if (val == 0) {
- SD2_card_state--;
- printk("[%s] sub state SD2_card_state = %d\n",__func__,SD2_card_state);
- if (SD2_card_state < 0) {
- SD2_card_state = 0;
- printk("[%s] set 0 SD2_card_state = %d\n",__func__,SD2_card_state);
- }
-
- if ((SD2_card_state == 0) && (mmc2_host_attr->card != NULL)) {
- DBG("[%s]remove card\n",__func__);
- mmc_force_remove_card(mmc2_host_attr);
- }
- }
-
- DBG("[%s] e1\n",__func__);
- mutex_unlock(&SD2_state_lock);
- return n;
- }
-
- mutex_unlock(&SD2_state_lock);
- DBG("[%s] e2\n",__func__);
- return -EINVAL;
-}
-
-static struct kobj_attribute atsmb2_state_attr = { \
- .attr = { \
- .name = __stringify(state), \
- .mode = 0755, \
- }, \
- .show = atsmb2_state_show, \
- .store = atsmb2_state_store, \
-};
-
-#if MMC2_SDIO_EXT_IRQ
-
-static ssize_t atsmb2_intr_show(struct kobject *kobj, struct kobj_attribute *attr,
- char *buf)
-{
- int ret = 0;
-
-
- ret = sprintf(buf, "%d\n", is_mtk6620);
- printk("[%s]is_mtk6620 = %d\n",__func__,is_mtk6620);
- return ret;
-}
-
-static ssize_t atsmb2_intr_store(struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n)
-{
- int val;
- if (sscanf(buf, "%d", &val) == 1) {
- printk("[%s] val = %d\n",__func__,val);
- if (val == 1) {
- if (gpio_request(wmt_mtk6620_intr, "mtk6620_wifi_intr") < 0) {
- printk("gpio(%d) mtk6620_wifi_intr gpio request fail\n", wmt_mtk6620_intr);
- is_mtk6620 = 0;
- return -1;
- }
- } else if (val == 0) {
-
- gpio_free(wmt_mtk6620_intr);
-
- }
- is_mtk6620 = val;
-
- return n;
- }
- return -EINVAL;
-}
-
-static struct kobj_attribute atsmb2_intr_attr = { \
- .attr = { \
- .name = __stringify(intr), \
- .mode = 0755, \
- }, \
- .show = atsmb2_intr_show, \
- .store = atsmb2_intr_store, \
-};
-#endif
-
-
-static struct attribute * g2[] = {
- &atsmb2_state_attr.attr,
-#if MMC2_SDIO_EXT_IRQ
- &atsmb2_intr_attr.attr,
-#endif
- NULL,
-};
-
-static struct attribute_group attr2_group = {
- .attrs = g2,
-};
-
-static int __init atsmb2_init(void)
-{
- int ret;
-
- int retval;
- unsigned char buf[80];
- unsigned char buf1[80];
- int varlen = 80;
- char *varname = "wmt.sd2.param";
- int temp = 0, sd_enable = 0; /*0 :disable 1:enable*/
-
- DBG("[%s] s\n",__func__);
-
-#ifdef CONFIG_MTD_WMT_SF
- /*Read system param to identify host function 0: SD/MMC 1:SDIO wifi*/
- retval = wmt_getsyspara(varname, buf, &varlen);
- if (retval == 0) {
- sscanf(buf,"%x:%d", &temp, &SD2_function);
- printk(KERN_ALERT "wmt.sd2.param = %x:%d\n", temp, SD2_function);
- sd_enable = temp & 0xf;
- SDXC2_function = (temp >> 4) & 0xf;
- printk(KERN_ALERT "SD2 ebable = %x, SDXC = %x, function = %x\n",
- sd_enable, SDXC2_function, SD2_function);
-
- if (SD2_function < 0 || SD2_function >= SD_MAX_FUN)
- return -ENODEV;
- } else {
- //default is enable sdio wifi
- temp = sd_enable = 1;
- SD2_function = 1;
- printk(KERN_ALERT "Default wmt.sd2.param = %x:%d\n", temp, SD2_function);
-
- }
- memset(buf,0,sizeof(buf));
- varlen = 80;
- retval = wmt_getsyspara("wmt.init.rc", buf, &varlen);
- if (retval == 0) {
- printk(KERN_ALERT"wmt.init.rc:%s\n",buf);
- if(!strcmp(buf,"init_nmc1000.rc")){
- is_nmc1000 = 0x01;
- printk("is_nmc1000:%d",is_nmc1000);
- }
- if (!strcmp(buf, "init.bcm6330.rc"))
- {
- is_ap6330 = 1;
- printk("is_ap6330:%d\n", is_ap6330);
- }
- if (!strcmp(buf, "init.rda5991.rc"))
- {
- printk("is rda5991\n");
- set_bus_dead = 0;
- }
- if (!strcmp(buf, "init.mtk6620.rc"))
- {
- printk("is mtk6620\n");
- set_bus_dead = 0;
- }
- } else {
- printk(KERN_ALERT "wmt.init.rc do not exit\n");
- }
-#endif
- /*SD function disable*/
- if (sd_enable != 1)
- return -ENODEV;
-
- get_driver_version2();
-
- if (platform_device_register(&wmt_sdmmc2_device))//add by jay,for modules support
- return -1;
- //ret = platform_driver_register(&atsmb2_driver);
- ret = platform_driver_probe(&atsmb2_driver, atsmb2_probe);
-
- atsmb2_kobj = kobject_create_and_add("mmc2", NULL);
- if (!atsmb2_kobj)
- return -ENOMEM;
- return sysfs_create_group(atsmb2_kobj, &attr2_group);
-
- DBG("[%s] e\n",__func__);
- return ret;
-}
-
-static void __exit atsmb2_exit(void)
-{
- DBG("[%s] s\n",__func__);
- (void)platform_driver_unregister(&atsmb2_driver);
- (void)platform_device_unregister(&wmt_sdmmc2_device);//add by jay,for modules support
- DBG("[%s] e\n",__func__);
-}
-
-module_init(atsmb2_init);
-module_exit(atsmb2_exit);
-module_param(fmax2, uint, 0444);
-
-MODULE_AUTHOR("WonderMedia Technologies, Inc.");
-MODULE_DESCRIPTION("WMT [AHB to SD/MMC2 Bridge] driver");
-MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/mmc_spi.c b/ANDROID_3.4.5/drivers/mmc/host/mmc_spi.c
deleted file mode 100644
index 273306c6..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/mmc_spi.c
+++ /dev/null
@@ -1,1554 +0,0 @@
-/*
- * mmc_spi.c - Access SD/MMC cards through SPI master controllers
- *
- * (C) Copyright 2005, Intec Automation,
- * Mike Lavender (mike@steroidmicros)
- * (C) Copyright 2006-2007, David Brownell
- * (C) Copyright 2007, Axis Communications,
- * Hans-Peter Nilsson (hp@axis.com)
- * (C) Copyright 2007, ATRON electronic GmbH,
- * Jan Nikitenko <jan.nikitenko@gmail.com>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/bio.h>
-#include <linux/dma-mapping.h>
-#include <linux/crc7.h>
-#include <linux/crc-itu-t.h>
-#include <linux/scatterlist.h>
-
-#include <linux/mmc/host.h>
-#include <linux/mmc/mmc.h> /* for R1_SPI_* bit values */
-
-#include <linux/spi/spi.h>
-#include <linux/spi/mmc_spi.h>
-
-#include <asm/unaligned.h>
-
-
-/* NOTES:
- *
- * - For now, we won't try to interoperate with a real mmc/sd/sdio
- * controller, although some of them do have hardware support for
- * SPI protocol. The main reason for such configs would be mmc-ish
- * cards like DataFlash, which don't support that "native" protocol.
- *
- * We don't have a "DataFlash/MMC/SD/SDIO card slot" abstraction to
- * switch between driver stacks, and in any case if "native" mode
- * is available, it will be faster and hence preferable.
- *
- * - MMC depends on a different chipselect management policy than the
- * SPI interface currently supports for shared bus segments: it needs
- * to issue multiple spi_message requests with the chipselect active,
- * using the results of one message to decide the next one to issue.
- *
- * Pending updates to the programming interface, this driver expects
- * that it not share the bus with other drivers (precluding conflicts).
- *
- * - We tell the controller to keep the chipselect active from the
- * beginning of an mmc_host_ops.request until the end. So beware
- * of SPI controller drivers that mis-handle the cs_change flag!
- *
- * However, many cards seem OK with chipselect flapping up/down
- * during that time ... at least on unshared bus segments.
- */
-
-
-/*
- * Local protocol constants, internal to data block protocols.
- */
-
-/* Response tokens used to ack each block written: */
-#define SPI_MMC_RESPONSE_CODE(x) ((x) & 0x1f)
-#define SPI_RESPONSE_ACCEPTED ((2 << 1)|1)
-#define SPI_RESPONSE_CRC_ERR ((5 << 1)|1)
-#define SPI_RESPONSE_WRITE_ERR ((6 << 1)|1)
-
-/* Read and write blocks start with these tokens and end with crc;
- * on error, read tokens act like a subset of R2_SPI_* values.
- */
-#define SPI_TOKEN_SINGLE 0xfe /* single block r/w, multiblock read */
-#define SPI_TOKEN_MULTI_WRITE 0xfc /* multiblock write */
-#define SPI_TOKEN_STOP_TRAN 0xfd /* terminate multiblock write */
-
-#define MMC_SPI_BLOCKSIZE 512
-
-
-/* These fixed timeouts come from the latest SD specs, which say to ignore
- * the CSD values. The R1B value is for card erase (e.g. the "I forgot the
- * card's password" scenario); it's mostly applied to STOP_TRANSMISSION after
- * reads which takes nowhere near that long. Older cards may be able to use
- * shorter timeouts ... but why bother?
- */
-#define r1b_timeout (HZ * 3)
-
-/* One of the critical speed parameters is the amount of data which may
- * be transferred in one command. If this value is too low, the SD card
- * controller has to do multiple partial block writes (argggh!). With
- * today (2008) SD cards there is little speed gain if we transfer more
- * than 64 KBytes at a time. So use this value until there is any indication
- * that we should do more here.
- */
-#define MMC_SPI_BLOCKSATONCE 128
-
-/****************************************************************************/
-
-/*
- * Local Data Structures
- */
-
-/* "scratch" is per-{command,block} data exchanged with the card */
-struct scratch {
- u8 status[29];
- u8 data_token;
- __be16 crc_val;
-};
-
-struct mmc_spi_host {
- struct mmc_host *mmc;
- struct spi_device *spi;
-
- unsigned char power_mode;
- u16 powerup_msecs;
-
- struct mmc_spi_platform_data *pdata;
-
- /* for bulk data transfers */
- struct spi_transfer token, t, crc, early_status;
- struct spi_message m;
-
- /* for status readback */
- struct spi_transfer status;
- struct spi_message readback;
-
- /* underlying DMA-aware controller, or null */
- struct device *dma_dev;
-
- /* buffer used for commands and for message "overhead" */
- struct scratch *data;
- dma_addr_t data_dma;
-
- /* Specs say to write ones most of the time, even when the card
- * has no need to read its input data; and many cards won't care.
- * This is our source of those ones.
- */
- void *ones;
- dma_addr_t ones_dma;
-};
-
-
-/****************************************************************************/
-
-/*
- * MMC-over-SPI protocol glue, used by the MMC stack interface
- */
-
-static inline int mmc_cs_off(struct mmc_spi_host *host)
-{
- /* chipselect will always be inactive after setup() */
- return spi_setup(host->spi);
-}
-
-static int
-mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len)
-{
- int status;
-
- if (len > sizeof(*host->data)) {
- WARN_ON(1);
- return -EIO;
- }
-
- host->status.len = len;
-
- if (host->dma_dev)
- dma_sync_single_for_device(host->dma_dev,
- host->data_dma, sizeof(*host->data),
- DMA_FROM_DEVICE);
-
- status = spi_sync_locked(host->spi, &host->readback);
-
- if (host->dma_dev)
- dma_sync_single_for_cpu(host->dma_dev,
- host->data_dma, sizeof(*host->data),
- DMA_FROM_DEVICE);
-
- return status;
-}
-
-static int mmc_spi_skip(struct mmc_spi_host *host, unsigned long timeout,
- unsigned n, u8 byte)
-{
- u8 *cp = host->data->status;
- unsigned long start = jiffies;
-
- while (1) {
- int status;
- unsigned i;
-
- status = mmc_spi_readbytes(host, n);
- if (status < 0)
- return status;
-
- for (i = 0; i < n; i++) {
- if (cp[i] != byte)
- return cp[i];
- }
-
- if (time_is_before_jiffies(start + timeout))
- break;
-
- /* If we need long timeouts, we may release the CPU.
- * We use jiffies here because we want to have a relation
- * between elapsed time and the blocking of the scheduler.
- */
- if (time_is_before_jiffies(start+1))
- schedule();
- }
- return -ETIMEDOUT;
-}
-
-static inline int
-mmc_spi_wait_unbusy(struct mmc_spi_host *host, unsigned long timeout)
-{
- return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0);
-}
-
-static int mmc_spi_readtoken(struct mmc_spi_host *host, unsigned long timeout)
-{
- return mmc_spi_skip(host, timeout, 1, 0xff);
-}
-
-
-/*
- * Note that for SPI, cmd->resp[0] is not the same data as "native" protocol
- * hosts return! The low byte holds R1_SPI bits. The next byte may hold
- * R2_SPI bits ... for SEND_STATUS, or after data read errors.
- *
- * cmd->resp[1] holds any four-byte response, for R3 (READ_OCR) and on
- * newer cards R7 (IF_COND).
- */
-
-static char *maptype(struct mmc_command *cmd)
-{
- switch (mmc_spi_resp_type(cmd)) {
- case MMC_RSP_SPI_R1: return "R1";
- case MMC_RSP_SPI_R1B: return "R1B";
- case MMC_RSP_SPI_R2: return "R2/R5";
- case MMC_RSP_SPI_R3: return "R3/R4/R7";
- default: return "?";
- }
-}
-
-/* return zero, else negative errno after setting cmd->error */
-static int mmc_spi_response_get(struct mmc_spi_host *host,
- struct mmc_command *cmd, int cs_on)
-{
- u8 *cp = host->data->status;
- u8 *end = cp + host->t.len;
- int value = 0;
- int bitshift;
- u8 leftover = 0;
- unsigned short rotator;
- int i;
- char tag[32];
-
- snprintf(tag, sizeof(tag), " ... CMD%d response SPI_%s",
- cmd->opcode, maptype(cmd));
-
- /* Except for data block reads, the whole response will already
- * be stored in the scratch buffer. It's somewhere after the
- * command and the first byte we read after it. We ignore that
- * first byte. After STOP_TRANSMISSION command it may include
- * two data bits, but otherwise it's all ones.
- */
- cp += 8;
- while (cp < end && *cp == 0xff)
- cp++;
-
- /* Data block reads (R1 response types) may need more data... */
- if (cp == end) {
- cp = host->data->status;
- end = cp+1;
-
- /* Card sends N(CR) (== 1..8) bytes of all-ones then one
- * status byte ... and we already scanned 2 bytes.
- *
- * REVISIT block read paths use nasty byte-at-a-time I/O
- * so it can always DMA directly into the target buffer.
- * It'd probably be better to memcpy() the first chunk and
- * avoid extra i/o calls...
- *
- * Note we check for more than 8 bytes, because in practice,
- * some SD cards are slow...
- */
- for (i = 2; i < 16; i++) {
- value = mmc_spi_readbytes(host, 1);
- if (value < 0)
- goto done;
- if (*cp != 0xff)
- goto checkstatus;
- }
- value = -ETIMEDOUT;
- goto done;
- }
-
-checkstatus:
- bitshift = 0;
- if (*cp & 0x80) {
- /* Houston, we have an ugly card with a bit-shifted response */
- rotator = *cp++ << 8;
- /* read the next byte */
- if (cp == end) {
- value = mmc_spi_readbytes(host, 1);
- if (value < 0)
- goto done;
- cp = host->data->status;
- end = cp+1;
- }
- rotator |= *cp++;
- while (rotator & 0x8000) {
- bitshift++;
- rotator <<= 1;
- }
- cmd->resp[0] = rotator >> 8;
- leftover = rotator;
- } else {
- cmd->resp[0] = *cp++;
- }
- cmd->error = 0;
-
- /* Status byte: the entire seven-bit R1 response. */
- if (cmd->resp[0] != 0) {
- if ((R1_SPI_PARAMETER | R1_SPI_ADDRESS)
- & cmd->resp[0])
- value = -EFAULT; /* Bad address */
- else if (R1_SPI_ILLEGAL_COMMAND & cmd->resp[0])
- value = -ENOSYS; /* Function not implemented */
- else if (R1_SPI_COM_CRC & cmd->resp[0])
- value = -EILSEQ; /* Illegal byte sequence */
- else if ((R1_SPI_ERASE_SEQ | R1_SPI_ERASE_RESET)
- & cmd->resp[0])
- value = -EIO; /* I/O error */
- /* else R1_SPI_IDLE, "it's resetting" */
- }
-
- switch (mmc_spi_resp_type(cmd)) {
-
- /* SPI R1B == R1 + busy; STOP_TRANSMISSION (for multiblock reads)
- * and less-common stuff like various erase operations.
- */
- case MMC_RSP_SPI_R1B:
- /* maybe we read all the busy tokens already */
- while (cp < end && *cp == 0)
- cp++;
- if (cp == end)
- mmc_spi_wait_unbusy(host, r1b_timeout);
- break;
-
- /* SPI R2 == R1 + second status byte; SEND_STATUS
- * SPI R5 == R1 + data byte; IO_RW_DIRECT
- */
- case MMC_RSP_SPI_R2:
- /* read the next byte */
- if (cp == end) {
- value = mmc_spi_readbytes(host, 1);
- if (value < 0)
- goto done;
- cp = host->data->status;
- end = cp+1;
- }
- if (bitshift) {
- rotator = leftover << 8;
- rotator |= *cp << bitshift;
- cmd->resp[0] |= (rotator & 0xFF00);
- } else {
- cmd->resp[0] |= *cp << 8;
- }
- break;
-
- /* SPI R3, R4, or R7 == R1 + 4 bytes */
- case MMC_RSP_SPI_R3:
- rotator = leftover << 8;
- cmd->resp[1] = 0;
- for (i = 0; i < 4; i++) {
- cmd->resp[1] <<= 8;
- /* read the next byte */
- if (cp == end) {
- value = mmc_spi_readbytes(host, 1);
- if (value < 0)
- goto done;
- cp = host->data->status;
- end = cp+1;
- }
- if (bitshift) {
- rotator |= *cp++ << bitshift;
- cmd->resp[1] |= (rotator >> 8);
- rotator <<= 8;
- } else {
- cmd->resp[1] |= *cp++;
- }
- }
- break;
-
- /* SPI R1 == just one status byte */
- case MMC_RSP_SPI_R1:
- break;
-
- default:
- dev_dbg(&host->spi->dev, "bad response type %04x\n",
- mmc_spi_resp_type(cmd));
- if (value >= 0)
- value = -EINVAL;
- goto done;
- }
-
- if (value < 0)
- dev_dbg(&host->spi->dev, "%s: resp %04x %08x\n",
- tag, cmd->resp[0], cmd->resp[1]);
-
- /* disable chipselect on errors and some success cases */
- if (value >= 0 && cs_on)
- return value;
-done:
- if (value < 0)
- cmd->error = value;
- mmc_cs_off(host);
- return value;
-}
-
-/* Issue command and read its response.
- * Returns zero on success, negative for error.
- *
- * On error, caller must cope with mmc core retry mechanism. That
- * means immediate low-level resubmit, which affects the bus lock...
- */
-static int
-mmc_spi_command_send(struct mmc_spi_host *host,
- struct mmc_request *mrq,
- struct mmc_command *cmd, int cs_on)
-{
- struct scratch *data = host->data;
- u8 *cp = data->status;
- u32 arg = cmd->arg;
- int status;
- struct spi_transfer *t;
-
- /* We can handle most commands (except block reads) in one full
- * duplex I/O operation before either starting the next transfer
- * (data block or command) or else deselecting the card.
- *
- * First, write 7 bytes:
- * - an all-ones byte to ensure the card is ready
- * - opcode byte (plus start and transmission bits)
- * - four bytes of big-endian argument
- * - crc7 (plus end bit) ... always computed, it's cheap
- *
- * We init the whole buffer to all-ones, which is what we need
- * to write while we're reading (later) response data.
- */
- memset(cp++, 0xff, sizeof(data->status));
-
- *cp++ = 0x40 | cmd->opcode;
- *cp++ = (u8)(arg >> 24);
- *cp++ = (u8)(arg >> 16);
- *cp++ = (u8)(arg >> 8);
- *cp++ = (u8)arg;
- *cp++ = (crc7(0, &data->status[1], 5) << 1) | 0x01;
-
- /* Then, read up to 13 bytes (while writing all-ones):
- * - N(CR) (== 1..8) bytes of all-ones
- * - status byte (for all response types)
- * - the rest of the response, either:
- * + nothing, for R1 or R1B responses
- * + second status byte, for R2 responses
- * + four data bytes, for R3 and R7 responses
- *
- * Finally, read some more bytes ... in the nice cases we know in
- * advance how many, and reading 1 more is always OK:
- * - N(EC) (== 0..N) bytes of all-ones, before deselect/finish
- * - N(RC) (== 1..N) bytes of all-ones, before next command
- * - N(WR) (== 1..N) bytes of all-ones, before data write
- *
- * So in those cases one full duplex I/O of at most 21 bytes will
- * handle the whole command, leaving the card ready to receive a
- * data block or new command. We do that whenever we can, shaving
- * CPU and IRQ costs (especially when using DMA or FIFOs).
- *
- * There are two other cases, where it's not generally practical
- * to rely on a single I/O:
- *
- * - R1B responses need at least N(EC) bytes of all-zeroes.
- *
- * In this case we can *try* to fit it into one I/O, then
- * maybe read more data later.
- *
- * - Data block reads are more troublesome, since a variable
- * number of padding bytes precede the token and data.
- * + N(CX) (== 0..8) bytes of all-ones, before CSD or CID
- * + N(AC) (== 1..many) bytes of all-ones
- *
- * In this case we currently only have minimal speedups here:
- * when N(CR) == 1 we can avoid I/O in response_get().
- */
- if (cs_on && (mrq->data->flags & MMC_DATA_READ)) {
- cp += 2; /* min(N(CR)) + status */
- /* R1 */
- } else {
- cp += 10; /* max(N(CR)) + status + min(N(RC),N(WR)) */
- if (cmd->flags & MMC_RSP_SPI_S2) /* R2/R5 */
- cp++;
- else if (cmd->flags & MMC_RSP_SPI_B4) /* R3/R4/R7 */
- cp += 4;
- else if (cmd->flags & MMC_RSP_BUSY) /* R1B */
- cp = data->status + sizeof(data->status);
- /* else: R1 (most commands) */
- }
-
- dev_dbg(&host->spi->dev, " mmc_spi: CMD%d, resp %s\n",
- cmd->opcode, maptype(cmd));
-
- /* send command, leaving chipselect active */
- spi_message_init(&host->m);
-
- t = &host->t;
- memset(t, 0, sizeof(*t));
- t->tx_buf = t->rx_buf = data->status;
- t->tx_dma = t->rx_dma = host->data_dma;
- t->len = cp - data->status;
- t->cs_change = 1;
- spi_message_add_tail(t, &host->m);
-
- if (host->dma_dev) {
- host->m.is_dma_mapped = 1;
- dma_sync_single_for_device(host->dma_dev,
- host->data_dma, sizeof(*host->data),
- DMA_BIDIRECTIONAL);
- }
- status = spi_sync_locked(host->spi, &host->m);
-
- if (host->dma_dev)
- dma_sync_single_for_cpu(host->dma_dev,
- host->data_dma, sizeof(*host->data),
- DMA_BIDIRECTIONAL);
- if (status < 0) {
- dev_dbg(&host->spi->dev, " ... write returned %d\n", status);
- cmd->error = status;
- return status;
- }
-
- /* after no-data commands and STOP_TRANSMISSION, chipselect off */
- return mmc_spi_response_get(host, cmd, cs_on);
-}
-
-/* Build data message with up to four separate transfers. For TX, we
- * start by writing the data token. And in most cases, we finish with
- * a status transfer.
- *
- * We always provide TX data for data and CRC. The MMC/SD protocol
- * requires us to write ones; but Linux defaults to writing zeroes;
- * so we explicitly initialize it to all ones on RX paths.
- *
- * We also handle DMA mapping, so the underlying SPI controller does
- * not need to (re)do it for each message.
- */
-static void
-mmc_spi_setup_data_message(
- struct mmc_spi_host *host,
- int multiple,
- enum dma_data_direction direction)
-{
- struct spi_transfer *t;
- struct scratch *scratch = host->data;
- dma_addr_t dma = host->data_dma;
-
- spi_message_init(&host->m);
- if (dma)
- host->m.is_dma_mapped = 1;
-
- /* for reads, readblock() skips 0xff bytes before finding
- * the token; for writes, this transfer issues that token.
- */
- if (direction == DMA_TO_DEVICE) {
- t = &host->token;
- memset(t, 0, sizeof(*t));
- t->len = 1;
- if (multiple)
- scratch->data_token = SPI_TOKEN_MULTI_WRITE;
- else
- scratch->data_token = SPI_TOKEN_SINGLE;
- t->tx_buf = &scratch->data_token;
- if (dma)
- t->tx_dma = dma + offsetof(struct scratch, data_token);
- spi_message_add_tail(t, &host->m);
- }
-
- /* Body of transfer is buffer, then CRC ...
- * either TX-only, or RX with TX-ones.
- */
- t = &host->t;
- memset(t, 0, sizeof(*t));
- t->tx_buf = host->ones;
- t->tx_dma = host->ones_dma;
- /* length and actual buffer info are written later */
- spi_message_add_tail(t, &host->m);
-
- t = &host->crc;
- memset(t, 0, sizeof(*t));
- t->len = 2;
- if (direction == DMA_TO_DEVICE) {
- /* the actual CRC may get written later */
- t->tx_buf = &scratch->crc_val;
- if (dma)
- t->tx_dma = dma + offsetof(struct scratch, crc_val);
- } else {
- t->tx_buf = host->ones;
- t->tx_dma = host->ones_dma;
- t->rx_buf = &scratch->crc_val;
- if (dma)
- t->rx_dma = dma + offsetof(struct scratch, crc_val);
- }
- spi_message_add_tail(t, &host->m);
-
- /*
- * A single block read is followed by N(EC) [0+] all-ones bytes
- * before deselect ... don't bother.
- *
- * Multiblock reads are followed by N(AC) [1+] all-ones bytes before
- * the next block is read, or a STOP_TRANSMISSION is issued. We'll
- * collect that single byte, so readblock() doesn't need to.
- *
- * For a write, the one-byte data response follows immediately, then
- * come zero or more busy bytes, then N(WR) [1+] all-ones bytes.
- * Then single block reads may deselect, and multiblock ones issue
- * the next token (next data block, or STOP_TRAN). We can try to
- * minimize I/O ops by using a single read to collect end-of-busy.
- */
- if (multiple || direction == DMA_TO_DEVICE) {
- t = &host->early_status;
- memset(t, 0, sizeof(*t));
- t->len = (direction == DMA_TO_DEVICE)
- ? sizeof(scratch->status)
- : 1;
- t->tx_buf = host->ones;
- t->tx_dma = host->ones_dma;
- t->rx_buf = scratch->status;
- if (dma)
- t->rx_dma = dma + offsetof(struct scratch, status);
- t->cs_change = 1;
- spi_message_add_tail(t, &host->m);
- }
-}
-
-/*
- * Write one block:
- * - caller handled preceding N(WR) [1+] all-ones bytes
- * - data block
- * + token
- * + data bytes
- * + crc16
- * - an all-ones byte ... card writes a data-response byte
- * - followed by N(EC) [0+] all-ones bytes, card writes zero/'busy'
- *
- * Return negative errno, else success.
- */
-static int
-mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t,
- unsigned long timeout)
-{
- struct spi_device *spi = host->spi;
- int status, i;
- struct scratch *scratch = host->data;
- u32 pattern;
-
- if (host->mmc->use_spi_crc)
- scratch->crc_val = cpu_to_be16(
- crc_itu_t(0, t->tx_buf, t->len));
- if (host->dma_dev)
- dma_sync_single_for_device(host->dma_dev,
- host->data_dma, sizeof(*scratch),
- DMA_BIDIRECTIONAL);
-
- status = spi_sync_locked(spi, &host->m);
-
- if (status != 0) {
- dev_dbg(&spi->dev, "write error (%d)\n", status);
- return status;
- }
-
- if (host->dma_dev)
- dma_sync_single_for_cpu(host->dma_dev,
- host->data_dma, sizeof(*scratch),
- DMA_BIDIRECTIONAL);
-
- /*
- * Get the transmission data-response reply. It must follow
- * immediately after the data block we transferred. This reply
- * doesn't necessarily tell whether the write operation succeeded;
- * it just says if the transmission was ok and whether *earlier*
- * writes succeeded; see the standard.
- *
- * In practice, there are (even modern SDHC-)cards which are late
- * in sending the response, and miss the time frame by a few bits,
- * so we have to cope with this situation and check the response
- * bit-by-bit. Arggh!!!
- */
- pattern = scratch->status[0] << 24;
- pattern |= scratch->status[1] << 16;
- pattern |= scratch->status[2] << 8;
- pattern |= scratch->status[3];
-
- /* First 3 bit of pattern are undefined */
- pattern |= 0xE0000000;
-
- /* left-adjust to leading 0 bit */
- while (pattern & 0x80000000)
- pattern <<= 1;
- /* right-adjust for pattern matching. Code is in bit 4..0 now. */
- pattern >>= 27;
-
- switch (pattern) {
- case SPI_RESPONSE_ACCEPTED:
- status = 0;
- break;
- case SPI_RESPONSE_CRC_ERR:
- /* host shall then issue MMC_STOP_TRANSMISSION */
- status = -EILSEQ;
- break;
- case SPI_RESPONSE_WRITE_ERR:
- /* host shall then issue MMC_STOP_TRANSMISSION,
- * and should MMC_SEND_STATUS to sort it out
- */
- status = -EIO;
- break;
- default:
- status = -EPROTO;
- break;
- }
- if (status != 0) {
- dev_dbg(&spi->dev, "write error %02x (%d)\n",
- scratch->status[0], status);
- return status;
- }
-
- t->tx_buf += t->len;
- if (host->dma_dev)
- t->tx_dma += t->len;
-
- /* Return when not busy. If we didn't collect that status yet,
- * we'll need some more I/O.
- */
- for (i = 4; i < sizeof(scratch->status); i++) {
- /* card is non-busy if the most recent bit is 1 */
- if (scratch->status[i] & 0x01)
- return 0;
- }
- return mmc_spi_wait_unbusy(host, timeout);
-}
-
-/*
- * Read one block:
- * - skip leading all-ones bytes ... either
- * + N(AC) [1..f(clock,CSD)] usually, else
- * + N(CX) [0..8] when reading CSD or CID
- * - data block
- * + token ... if error token, no data or crc
- * + data bytes
- * + crc16
- *
- * After single block reads, we're done; N(EC) [0+] all-ones bytes follow
- * before dropping chipselect.
- *
- * For multiblock reads, caller either reads the next block or issues a
- * STOP_TRANSMISSION command.
- */
-static int
-mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t,
- unsigned long timeout)
-{
- struct spi_device *spi = host->spi;
- int status;
- struct scratch *scratch = host->data;
- unsigned int bitshift;
- u8 leftover;
-
- /* At least one SD card sends an all-zeroes byte when N(CX)
- * applies, before the all-ones bytes ... just cope with that.
- */
- status = mmc_spi_readbytes(host, 1);
- if (status < 0)
- return status;
- status = scratch->status[0];
- if (status == 0xff || status == 0)
- status = mmc_spi_readtoken(host, timeout);
-
- if (status < 0) {
- dev_dbg(&spi->dev, "read error %02x (%d)\n", status, status);
- return status;
- }
-
- /* The token may be bit-shifted...
- * the first 0-bit precedes the data stream.
- */
- bitshift = 7;
- while (status & 0x80) {
- status <<= 1;
- bitshift--;
- }
- leftover = status << 1;
-
- if (host->dma_dev) {
- dma_sync_single_for_device(host->dma_dev,
- host->data_dma, sizeof(*scratch),
- DMA_BIDIRECTIONAL);
- dma_sync_single_for_device(host->dma_dev,
- t->rx_dma, t->len,
- DMA_FROM_DEVICE);
- }
-
- status = spi_sync_locked(spi, &host->m);
-
- if (host->dma_dev) {
- dma_sync_single_for_cpu(host->dma_dev,
- host->data_dma, sizeof(*scratch),
- DMA_BIDIRECTIONAL);
- dma_sync_single_for_cpu(host->dma_dev,
- t->rx_dma, t->len,
- DMA_FROM_DEVICE);
- }
-
- if (bitshift) {
- /* Walk through the data and the crc and do
- * all the magic to get byte-aligned data.
- */
- u8 *cp = t->rx_buf;
- unsigned int len;
- unsigned int bitright = 8 - bitshift;
- u8 temp;
- for (len = t->len; len; len--) {
- temp = *cp;
- *cp++ = leftover | (temp >> bitshift);
- leftover = temp << bitright;
- }
- cp = (u8 *) &scratch->crc_val;
- temp = *cp;
- *cp++ = leftover | (temp >> bitshift);
- leftover = temp << bitright;
- temp = *cp;
- *cp = leftover | (temp >> bitshift);
- }
-
- if (host->mmc->use_spi_crc) {
- u16 crc = crc_itu_t(0, t->rx_buf, t->len);
-
- be16_to_cpus(&scratch->crc_val);
- if (scratch->crc_val != crc) {
- dev_dbg(&spi->dev, "read - crc error: crc_val=0x%04x, "
- "computed=0x%04x len=%d\n",
- scratch->crc_val, crc, t->len);
- return -EILSEQ;
- }
- }
-
- t->rx_buf += t->len;
- if (host->dma_dev)
- t->rx_dma += t->len;
-
- return 0;
-}
-
-/*
- * An MMC/SD data stage includes one or more blocks, optional CRCs,
- * and inline handshaking. That handhaking makes it unlike most
- * other SPI protocol stacks.
- */
-static void
-mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
- struct mmc_data *data, u32 blk_size)
-{
- struct spi_device *spi = host->spi;
- struct device *dma_dev = host->dma_dev;
- struct spi_transfer *t;
- enum dma_data_direction direction;
- struct scatterlist *sg;
- unsigned n_sg;
- int multiple = (data->blocks > 1);
- u32 clock_rate;
- unsigned long timeout;
-
- if (data->flags & MMC_DATA_READ)
- direction = DMA_FROM_DEVICE;
- else
- direction = DMA_TO_DEVICE;
- mmc_spi_setup_data_message(host, multiple, direction);
- t = &host->t;
-
- if (t->speed_hz)
- clock_rate = t->speed_hz;
- else
- clock_rate = spi->max_speed_hz;
-
- timeout = data->timeout_ns +
- data->timeout_clks * 1000000 / clock_rate;
- timeout = usecs_to_jiffies((unsigned int)(timeout / 1000)) + 1;
-
- /* Handle scatterlist segments one at a time, with synch for
- * each 512-byte block
- */
- for (sg = data->sg, n_sg = data->sg_len; n_sg; n_sg--, sg++) {
- int status = 0;
- dma_addr_t dma_addr = 0;
- void *kmap_addr;
- unsigned length = sg->length;
- enum dma_data_direction dir = direction;
-
- /* set up dma mapping for controller drivers that might
- * use DMA ... though they may fall back to PIO
- */
- if (dma_dev) {
- /* never invalidate whole *shared* pages ... */
- if ((sg->offset != 0 || length != PAGE_SIZE)
- && dir == DMA_FROM_DEVICE)
- dir = DMA_BIDIRECTIONAL;
-
- dma_addr = dma_map_page(dma_dev, sg_page(sg), 0,
- PAGE_SIZE, dir);
- if (direction == DMA_TO_DEVICE)
- t->tx_dma = dma_addr + sg->offset;
- else
- t->rx_dma = dma_addr + sg->offset;
- }
-
- /* allow pio too; we don't allow highmem */
- kmap_addr = kmap(sg_page(sg));
- if (direction == DMA_TO_DEVICE)
- t->tx_buf = kmap_addr + sg->offset;
- else
- t->rx_buf = kmap_addr + sg->offset;
-
- /* transfer each block, and update request status */
- while (length) {
- t->len = min(length, blk_size);
-
- dev_dbg(&host->spi->dev,
- " mmc_spi: %s block, %d bytes\n",
- (direction == DMA_TO_DEVICE)
- ? "write"
- : "read",
- t->len);
-
- if (direction == DMA_TO_DEVICE)
- status = mmc_spi_writeblock(host, t, timeout);
- else
- status = mmc_spi_readblock(host, t, timeout);
- if (status < 0)
- break;
-
- data->bytes_xfered += t->len;
- length -= t->len;
-
- if (!multiple)
- break;
- }
-
- /* discard mappings */
- if (direction == DMA_FROM_DEVICE)
- flush_kernel_dcache_page(sg_page(sg));
- kunmap(sg_page(sg));
- if (dma_dev)
- dma_unmap_page(dma_dev, dma_addr, PAGE_SIZE, dir);
-
- if (status < 0) {
- data->error = status;
- dev_dbg(&spi->dev, "%s status %d\n",
- (direction == DMA_TO_DEVICE)
- ? "write" : "read",
- status);
- break;
- }
- }
-
- /* NOTE some docs describe an MMC-only SET_BLOCK_COUNT (CMD23) that
- * can be issued before multiblock writes. Unlike its more widely
- * documented analogue for SD cards (SET_WR_BLK_ERASE_COUNT, ACMD23),
- * that can affect the STOP_TRAN logic. Complete (and current)
- * MMC specs should sort that out before Linux starts using CMD23.
- */
- if (direction == DMA_TO_DEVICE && multiple) {
- struct scratch *scratch = host->data;
- int tmp;
- const unsigned statlen = sizeof(scratch->status);
-
- dev_dbg(&spi->dev, " mmc_spi: STOP_TRAN\n");
-
- /* Tweak the per-block message we set up earlier by morphing
- * it to hold single buffer with the token followed by some
- * all-ones bytes ... skip N(BR) (0..1), scan the rest for
- * "not busy any longer" status, and leave chip selected.
- */
- INIT_LIST_HEAD(&host->m.transfers);
- list_add(&host->early_status.transfer_list,
- &host->m.transfers);
-
- memset(scratch->status, 0xff, statlen);
- scratch->status[0] = SPI_TOKEN_STOP_TRAN;
-
- host->early_status.tx_buf = host->early_status.rx_buf;
- host->early_status.tx_dma = host->early_status.rx_dma;
- host->early_status.len = statlen;
-
- if (host->dma_dev)
- dma_sync_single_for_device(host->dma_dev,
- host->data_dma, sizeof(*scratch),
- DMA_BIDIRECTIONAL);
-
- tmp = spi_sync_locked(spi, &host->m);
-
- if (host->dma_dev)
- dma_sync_single_for_cpu(host->dma_dev,
- host->data_dma, sizeof(*scratch),
- DMA_BIDIRECTIONAL);
-
- if (tmp < 0) {
- if (!data->error)
- data->error = tmp;
- return;
- }
-
- /* Ideally we collected "not busy" status with one I/O,
- * avoiding wasteful byte-at-a-time scanning... but more
- * I/O is often needed.
- */
- for (tmp = 2; tmp < statlen; tmp++) {
- if (scratch->status[tmp] != 0)
- return;
- }
- tmp = mmc_spi_wait_unbusy(host, timeout);
- if (tmp < 0 && !data->error)
- data->error = tmp;
- }
-}
-
-/****************************************************************************/
-
-/*
- * MMC driver implementation -- the interface to the MMC stack
- */
-
-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 */
- {
- struct mmc_command *cmd;
- int invalid = 0;
-
- cmd = mrq->cmd;
- if (!mmc_spi_resp_type(cmd)) {
- dev_dbg(&host->spi->dev, "bogus command\n");
- cmd->error = -EINVAL;
- invalid = 1;
- }
-
- cmd = mrq->stop;
- if (cmd && !mmc_spi_resp_type(cmd)) {
- dev_dbg(&host->spi->dev, "bogus STOP command\n");
- cmd->error = -EINVAL;
- invalid = 1;
- }
-
- if (invalid) {
- dump_stack();
- mmc_request_done(host->mmc, mrq);
- return;
- }
- }
-#endif
-
- /* 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
- mmc_cs_off(host);
- }
-
- /* release the bus */
- spi_bus_unlock(host->spi->master);
-
- mmc_request_done(host->mmc, mrq);
-}
-
-/* See Section 6.4.1, in SD "Simplified Physical Layer Specification 2.0"
- *
- * NOTE that here we can't know that the card has just been powered up;
- * not all MMC/SD sockets support power switching.
- *
- * FIXME when the card is still in SPI mode, e.g. from a previous kernel,
- * this doesn't seem to do the right thing at all...
- */
-static void mmc_spi_initsequence(struct mmc_spi_host *host)
-{
- /* Try to be very sure any previous command has completed;
- * wait till not-busy, skip debris from any old commands.
- */
- mmc_spi_wait_unbusy(host, r1b_timeout);
- mmc_spi_readbytes(host, 10);
-
- /*
- * Do a burst with chipselect active-high. We need to do this to
- * meet the requirement of 74 clock cycles with both chipselect
- * and CMD (MOSI) high before CMD0 ... after the card has been
- * powered up to Vdd(min), and so is ready to take commands.
- *
- * Some cards are particularly needy of this (e.g. Viking "SD256")
- * while most others don't seem to care.
- *
- * Note that this is one of the places MMC/SD plays games with the
- * SPI protocol. Another is that when chipselect is released while
- * the card returns BUSY status, the clock must issue several cycles
- * with chipselect high before the card will stop driving its output.
- */
- host->spi->mode |= SPI_CS_HIGH;
- if (spi_setup(host->spi) != 0) {
- /* Just warn; most cards work without it. */
- dev_warn(&host->spi->dev,
- "can't change chip-select polarity\n");
- host->spi->mode &= ~SPI_CS_HIGH;
- } else {
- mmc_spi_readbytes(host, 18);
-
- host->spi->mode &= ~SPI_CS_HIGH;
- if (spi_setup(host->spi) != 0) {
- /* Wot, we can't get the same setup we had before? */
- dev_err(&host->spi->dev,
- "can't restore chip-select polarity\n");
- }
- }
-}
-
-static char *mmc_powerstring(u8 power_mode)
-{
- switch (power_mode) {
- case MMC_POWER_OFF: return "off";
- case MMC_POWER_UP: return "up";
- case MMC_POWER_ON: return "on";
- }
- return "?";
-}
-
-static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct mmc_spi_host *host = mmc_priv(mmc);
-
- if (host->power_mode != ios->power_mode) {
- int canpower;
-
- canpower = host->pdata && host->pdata->setpower;
-
- dev_dbg(&host->spi->dev, "mmc_spi: power %s (%d)%s\n",
- mmc_powerstring(ios->power_mode),
- ios->vdd,
- canpower ? ", can switch" : "");
-
- /* switch power on/off if possible, accounting for
- * max 250msec powerup time if needed.
- */
- if (canpower) {
- switch (ios->power_mode) {
- case MMC_POWER_OFF:
- case MMC_POWER_UP:
- host->pdata->setpower(&host->spi->dev,
- ios->vdd);
- if (ios->power_mode == MMC_POWER_UP)
- msleep(host->powerup_msecs);
- }
- }
-
- /* See 6.4.1 in the simplified SD card physical spec 2.0 */
- if (ios->power_mode == MMC_POWER_ON)
- mmc_spi_initsequence(host);
-
- /* If powering down, ground all card inputs to avoid power
- * delivery from data lines! On a shared SPI bus, this
- * will probably be temporary; 6.4.2 of the simplified SD
- * spec says this must last at least 1msec.
- *
- * - Clock low means CPOL 0, e.g. mode 0
- * - MOSI low comes from writing zero
- * - Chipselect is usually active low...
- */
- if (canpower && ios->power_mode == MMC_POWER_OFF) {
- int mres;
- u8 nullbyte = 0;
-
- host->spi->mode &= ~(SPI_CPOL|SPI_CPHA);
- mres = spi_setup(host->spi);
- if (mres < 0)
- dev_dbg(&host->spi->dev,
- "switch to SPI mode 0 failed\n");
-
- if (spi_write(host->spi, &nullbyte, 1) < 0)
- dev_dbg(&host->spi->dev,
- "put spi signals to low failed\n");
-
- /*
- * Now clock should be low due to spi mode 0;
- * MOSI should be low because of written 0x00;
- * chipselect should be low (it is active low)
- * power supply is off, so now MMC is off too!
- *
- * FIXME no, chipselect can be high since the
- * device is inactive and SPI_CS_HIGH is clear...
- */
- msleep(10);
- if (mres == 0) {
- host->spi->mode |= (SPI_CPOL|SPI_CPHA);
- mres = spi_setup(host->spi);
- if (mres < 0)
- dev_dbg(&host->spi->dev,
- "switch back to SPI mode 3"
- " failed\n");
- }
- }
-
- host->power_mode = ios->power_mode;
- }
-
- if (host->spi->max_speed_hz != ios->clock && ios->clock != 0) {
- int status;
-
- host->spi->max_speed_hz = ios->clock;
- status = spi_setup(host->spi);
- dev_dbg(&host->spi->dev,
- "mmc_spi: clock to %d Hz, %d\n",
- host->spi->max_speed_hz, status);
- }
-}
-
-static int mmc_spi_get_ro(struct mmc_host *mmc)
-{
- struct mmc_spi_host *host = mmc_priv(mmc);
-
- if (host->pdata && host->pdata->get_ro)
- return !!host->pdata->get_ro(mmc->parent);
- /*
- * Board doesn't support read only detection; let the mmc core
- * decide what to do.
- */
- return -ENOSYS;
-}
-
-static int mmc_spi_get_cd(struct mmc_host *mmc)
-{
- struct mmc_spi_host *host = mmc_priv(mmc);
-
- if (host->pdata && host->pdata->get_cd)
- return !!host->pdata->get_cd(mmc->parent);
- return -ENOSYS;
-}
-
-static const struct mmc_host_ops mmc_spi_ops = {
- .request = mmc_spi_request,
- .set_ios = mmc_spi_set_ios,
- .get_ro = mmc_spi_get_ro,
- .get_cd = mmc_spi_get_cd,
-};
-
-
-/****************************************************************************/
-
-/*
- * SPI driver implementation
- */
-
-static irqreturn_t
-mmc_spi_detect_irq(int irq, void *mmc)
-{
- struct mmc_spi_host *host = mmc_priv(mmc);
- u16 delay_msec = max(host->pdata->detect_delay, (u16)100);
-
- mmc_detect_change(mmc, msecs_to_jiffies(delay_msec));
- return IRQ_HANDLED;
-}
-
-static int mmc_spi_probe(struct spi_device *spi)
-{
- void *ones;
- struct mmc_host *mmc;
- struct mmc_spi_host *host;
- int status;
-
- /* We rely on full duplex transfers, mostly to reduce
- * per-transfer overheads (by making fewer transfers).
- */
- if (spi->master->flags & SPI_MASTER_HALF_DUPLEX)
- return -EINVAL;
-
- /* MMC and SD specs only seem to care that sampling is on the
- * rising edge ... meaning SPI modes 0 or 3. So either SPI mode
- * should be legit. We'll use mode 0 since the steady state is 0,
- * which is appropriate for hotplugging, unless the platform data
- * specify mode 3 (if hardware is not compatible to mode 0).
- */
- if (spi->mode != SPI_MODE_3)
- spi->mode = SPI_MODE_0;
- spi->bits_per_word = 8;
-
- status = spi_setup(spi);
- if (status < 0) {
- dev_dbg(&spi->dev, "needs SPI mode %02x, %d KHz; %d\n",
- spi->mode, spi->max_speed_hz / 1000,
- status);
- return status;
- }
-
- /* We need a supply of ones to transmit. This is the only time
- * the CPU touches these, so cache coherency isn't a concern.
- *
- * NOTE if many systems use more than one MMC-over-SPI connector
- * it'd save some memory to share this. That's evidently rare.
- */
- status = -ENOMEM;
- ones = kmalloc(MMC_SPI_BLOCKSIZE, GFP_KERNEL);
- if (!ones)
- goto nomem;
- memset(ones, 0xff, MMC_SPI_BLOCKSIZE);
-
- mmc = mmc_alloc_host(sizeof(*host), &spi->dev);
- if (!mmc)
- goto nomem;
-
- mmc->ops = &mmc_spi_ops;
- mmc->max_blk_size = MMC_SPI_BLOCKSIZE;
- mmc->max_segs = MMC_SPI_BLOCKSATONCE;
- mmc->max_req_size = MMC_SPI_BLOCKSATONCE * MMC_SPI_BLOCKSIZE;
- mmc->max_blk_count = MMC_SPI_BLOCKSATONCE;
-
- mmc->caps = MMC_CAP_SPI;
-
- /* SPI doesn't need the lowspeed device identification thing for
- * MMC or SD cards, since it never comes up in open drain mode.
- * That's good; some SPI masters can't handle very low speeds!
- *
- * However, low speed SDIO cards need not handle over 400 KHz;
- * that's the only reason not to use a few MHz for f_min (until
- * the upper layer reads the target frequency from the CSD).
- */
- mmc->f_min = 400000;
- mmc->f_max = spi->max_speed_hz;
-
- host = mmc_priv(mmc);
- host->mmc = mmc;
- host->spi = spi;
-
- host->ones = ones;
-
- /* Platform data is used to hook up things like card sensing
- * and power switching gpios.
- */
- host->pdata = mmc_spi_get_pdata(spi);
- if (host->pdata)
- mmc->ocr_avail = host->pdata->ocr_mask;
- if (!mmc->ocr_avail) {
- dev_warn(&spi->dev, "ASSUMING 3.2-3.4 V slot power\n");
- mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
- }
- if (host->pdata && host->pdata->setpower) {
- host->powerup_msecs = host->pdata->powerup_msecs;
- if (!host->powerup_msecs || host->powerup_msecs > 250)
- host->powerup_msecs = 250;
- }
-
- dev_set_drvdata(&spi->dev, mmc);
-
- /* preallocate dma buffers */
- host->data = kmalloc(sizeof(*host->data), GFP_KERNEL);
- if (!host->data)
- goto fail_nobuf1;
-
- if (spi->master->dev.parent->dma_mask) {
- struct device *dev = spi->master->dev.parent;
-
- host->dma_dev = dev;
- host->ones_dma = dma_map_single(dev, ones,
- MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
- host->data_dma = dma_map_single(dev, host->data,
- sizeof(*host->data), DMA_BIDIRECTIONAL);
-
- /* REVISIT in theory those map operations can fail... */
-
- dma_sync_single_for_cpu(host->dma_dev,
- host->data_dma, sizeof(*host->data),
- DMA_BIDIRECTIONAL);
- }
-
- /* setup message for status/busy readback */
- spi_message_init(&host->readback);
- host->readback.is_dma_mapped = (host->dma_dev != NULL);
-
- spi_message_add_tail(&host->status, &host->readback);
- host->status.tx_buf = host->ones;
- host->status.tx_dma = host->ones_dma;
- host->status.rx_buf = &host->data->status;
- host->status.rx_dma = host->data_dma + offsetof(struct scratch, status);
- host->status.cs_change = 1;
-
- /* register card detect irq */
- if (host->pdata && host->pdata->init) {
- status = host->pdata->init(&spi->dev, mmc_spi_detect_irq, mmc);
- if (status != 0)
- goto fail_glue_init;
- }
-
- /* pass platform capabilities, if any */
- if (host->pdata)
- mmc->caps |= host->pdata->caps;
-
- status = mmc_add_host(mmc);
- if (status != 0)
- goto fail_add_host;
-
- dev_info(&spi->dev, "SD/MMC host %s%s%s%s%s\n",
- dev_name(&mmc->class_dev),
- host->dma_dev ? "" : ", no DMA",
- (host->pdata && host->pdata->get_ro)
- ? "" : ", no WP",
- (host->pdata && host->pdata->setpower)
- ? "" : ", no poweroff",
- (mmc->caps & MMC_CAP_NEEDS_POLL)
- ? ", cd polling" : "");
- return 0;
-
-fail_add_host:
- mmc_remove_host (mmc);
-fail_glue_init:
- if (host->dma_dev)
- dma_unmap_single(host->dma_dev, host->data_dma,
- sizeof(*host->data), DMA_BIDIRECTIONAL);
- kfree(host->data);
-
-fail_nobuf1:
- mmc_free_host(mmc);
- mmc_spi_put_pdata(spi);
- dev_set_drvdata(&spi->dev, NULL);
-
-nomem:
- kfree(ones);
- return status;
-}
-
-
-static int __devexit mmc_spi_remove(struct spi_device *spi)
-{
- struct mmc_host *mmc = dev_get_drvdata(&spi->dev);
- struct mmc_spi_host *host;
-
- if (mmc) {
- host = mmc_priv(mmc);
-
- /* prevent new mmc_detect_change() calls */
- if (host->pdata && host->pdata->exit)
- host->pdata->exit(&spi->dev, mmc);
-
- mmc_remove_host(mmc);
-
- if (host->dma_dev) {
- dma_unmap_single(host->dma_dev, host->ones_dma,
- MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
- dma_unmap_single(host->dma_dev, host->data_dma,
- sizeof(*host->data), DMA_BIDIRECTIONAL);
- }
-
- kfree(host->data);
- kfree(host->ones);
-
- spi->max_speed_hz = mmc->f_max;
- mmc_free_host(mmc);
- mmc_spi_put_pdata(spi);
- dev_set_drvdata(&spi->dev, NULL);
- }
- return 0;
-}
-
-static struct of_device_id mmc_spi_of_match_table[] __devinitdata = {
- { .compatible = "mmc-spi-slot", },
- {},
-};
-
-static struct spi_driver mmc_spi_driver = {
- .driver = {
- .name = "mmc_spi",
- .owner = THIS_MODULE,
- .of_match_table = mmc_spi_of_match_table,
- },
- .probe = mmc_spi_probe,
- .remove = __devexit_p(mmc_spi_remove),
-};
-
-
-static int __init mmc_spi_init(void)
-{
- return spi_register_driver(&mmc_spi_driver);
-}
-module_init(mmc_spi_init);
-
-
-static void __exit mmc_spi_exit(void)
-{
- spi_unregister_driver(&mmc_spi_driver);
-}
-module_exit(mmc_spi_exit);
-
-
-MODULE_AUTHOR("Mike Lavender, David Brownell, "
- "Hans-Peter Nilsson, Jan Nikitenko");
-MODULE_DESCRIPTION("SPI SD/MMC host driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("spi:mmc_spi");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/mmci.c b/ANDROID_3.4.5/drivers/mmc/host/mmci.c
deleted file mode 100644
index 032b8479..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/mmci.c
+++ /dev/null
@@ -1,1606 +0,0 @@
-/*
- * linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 driver
- *
- * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
- * Copyright (C) 2010 ST-Ericsson SA
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/highmem.h>
-#include <linux/log2.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/amba/bus.h>
-#include <linux/clk.h>
-#include <linux/scatterlist.h>
-#include <linux/gpio.h>
-#include <linux/regulator/consumer.h>
-#include <linux/dmaengine.h>
-#include <linux/dma-mapping.h>
-#include <linux/amba/mmci.h>
-#include <linux/pm_runtime.h>
-#include <linux/types.h>
-
-#include <asm/div64.h>
-#include <asm/io.h>
-#include <asm/sizes.h>
-
-#include "mmci.h"
-
-#define DRIVER_NAME "mmci-pl18x"
-
-static unsigned int fmax = 515633;
-
-/**
- * struct variant_data - MMCI variant-specific quirks
- * @clkreg: default value for MCICLOCK register
- * @clkreg_enable: enable value for MMCICLOCK register
- * @datalength_bits: number of bits in the MMCIDATALENGTH register
- * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
- * is asserted (likewise for RX)
- * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
- * is asserted (likewise for RX)
- * @sdio: variant supports SDIO
- * @st_clkdiv: true if using a ST-specific clock divider algorithm
- * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
- * @pwrreg_powerup: power up value for MMCIPOWER register
- * @signal_direction: input/out direction of bus signals can be indicated
- */
-struct variant_data {
- unsigned int clkreg;
- unsigned int clkreg_enable;
- unsigned int datalength_bits;
- unsigned int fifosize;
- unsigned int fifohalfsize;
- bool sdio;
- bool st_clkdiv;
- bool blksz_datactrl16;
- u32 pwrreg_powerup;
- bool signal_direction;
-};
-
-static struct variant_data variant_arm = {
- .fifosize = 16 * 4,
- .fifohalfsize = 8 * 4,
- .datalength_bits = 16,
- .pwrreg_powerup = MCI_PWR_UP,
-};
-
-static struct variant_data variant_arm_extended_fifo = {
- .fifosize = 128 * 4,
- .fifohalfsize = 64 * 4,
- .datalength_bits = 16,
- .pwrreg_powerup = MCI_PWR_UP,
-};
-
-static struct variant_data variant_u300 = {
- .fifosize = 16 * 4,
- .fifohalfsize = 8 * 4,
- .clkreg_enable = MCI_ST_U300_HWFCEN,
- .datalength_bits = 16,
- .sdio = true,
- .pwrreg_powerup = MCI_PWR_ON,
- .signal_direction = true,
-};
-
-static struct variant_data variant_ux500 = {
- .fifosize = 30 * 4,
- .fifohalfsize = 8 * 4,
- .clkreg = MCI_CLK_ENABLE,
- .clkreg_enable = MCI_ST_UX500_HWFCEN,
- .datalength_bits = 24,
- .sdio = true,
- .st_clkdiv = true,
- .pwrreg_powerup = MCI_PWR_ON,
- .signal_direction = true,
-};
-
-static struct variant_data variant_ux500v2 = {
- .fifosize = 30 * 4,
- .fifohalfsize = 8 * 4,
- .clkreg = MCI_CLK_ENABLE,
- .clkreg_enable = MCI_ST_UX500_HWFCEN,
- .datalength_bits = 24,
- .sdio = true,
- .st_clkdiv = true,
- .blksz_datactrl16 = true,
- .pwrreg_powerup = MCI_PWR_ON,
- .signal_direction = true,
-};
-
-/*
- * This must be called with host->lock held
- */
-static void mmci_write_clkreg(struct mmci_host *host, u32 clk)
-{
- if (host->clk_reg != clk) {
- host->clk_reg = clk;
- writel(clk, host->base + MMCICLOCK);
- }
-}
-
-/*
- * This must be called with host->lock held
- */
-static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
-{
- if (host->pwr_reg != pwr) {
- host->pwr_reg = pwr;
- writel(pwr, host->base + MMCIPOWER);
- }
-}
-
-/*
- * This must be called with host->lock held
- */
-static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
-{
- struct variant_data *variant = host->variant;
- u32 clk = variant->clkreg;
-
- if (desired) {
- if (desired >= host->mclk) {
- clk = MCI_CLK_BYPASS;
- if (variant->st_clkdiv)
- clk |= MCI_ST_UX500_NEG_EDGE;
- host->cclk = host->mclk;
- } else if (variant->st_clkdiv) {
- /*
- * DB8500 TRM says f = mclk / (clkdiv + 2)
- * => clkdiv = (mclk / f) - 2
- * Round the divider up so we don't exceed the max
- * frequency
- */
- clk = DIV_ROUND_UP(host->mclk, desired) - 2;
- if (clk >= 256)
- clk = 255;
- host->cclk = host->mclk / (clk + 2);
- } else {
- /*
- * PL180 TRM says f = mclk / (2 * (clkdiv + 1))
- * => clkdiv = mclk / (2 * f) - 1
- */
- clk = host->mclk / (2 * desired) - 1;
- if (clk >= 256)
- clk = 255;
- host->cclk = host->mclk / (2 * (clk + 1));
- }
-
- clk |= variant->clkreg_enable;
- clk |= MCI_CLK_ENABLE;
- /* This hasn't proven to be worthwhile */
- /* clk |= MCI_CLK_PWRSAVE; */
- }
-
- if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4)
- clk |= MCI_4BIT_BUS;
- if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
- clk |= MCI_ST_8BIT_BUS;
-
- mmci_write_clkreg(host, clk);
-}
-
-static void
-mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
-{
- writel(0, host->base + MMCICOMMAND);
-
- BUG_ON(host->data);
-
- host->mrq = NULL;
- host->cmd = NULL;
-
- mmc_request_done(host->mmc, mrq);
-
- pm_runtime_mark_last_busy(mmc_dev(host->mmc));
- pm_runtime_put_autosuspend(mmc_dev(host->mmc));
-}
-
-static void mmci_set_mask1(struct mmci_host *host, unsigned int mask)
-{
- void __iomem *base = host->base;
-
- if (host->singleirq) {
- unsigned int mask0 = readl(base + MMCIMASK0);
-
- mask0 &= ~MCI_IRQ1MASK;
- mask0 |= mask;
-
- writel(mask0, base + MMCIMASK0);
- }
-
- writel(mask, base + MMCIMASK1);
-}
-
-static void mmci_stop_data(struct mmci_host *host)
-{
- writel(0, host->base + MMCIDATACTRL);
- mmci_set_mask1(host, 0);
- host->data = NULL;
-}
-
-static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
-{
- unsigned int flags = SG_MITER_ATOMIC;
-
- if (data->flags & MMC_DATA_READ)
- flags |= SG_MITER_TO_SG;
- else
- flags |= SG_MITER_FROM_SG;
-
- sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
-}
-
-/*
- * All the DMA operation mode stuff goes inside this ifdef.
- * This assumes that you have a generic DMA device interface,
- * no custom DMA interfaces are supported.
- */
-#ifdef CONFIG_DMA_ENGINE
-static void __devinit mmci_dma_setup(struct mmci_host *host)
-{
- struct mmci_platform_data *plat = host->plat;
- const char *rxname, *txname;
- dma_cap_mask_t mask;
-
- if (!plat || !plat->dma_filter) {
- dev_info(mmc_dev(host->mmc), "no DMA platform data\n");
- return;
- }
-
- /* initialize pre request cookie */
- host->next_data.cookie = 1;
-
- /* Try to acquire a generic DMA engine slave channel */
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
-
- /*
- * If only an RX channel is specified, the driver will
- * attempt to use it bidirectionally, however if it is
- * is specified but cannot be located, DMA will be disabled.
- */
- if (plat->dma_rx_param) {
- host->dma_rx_channel = dma_request_channel(mask,
- plat->dma_filter,
- plat->dma_rx_param);
- /* E.g if no DMA hardware is present */
- if (!host->dma_rx_channel)
- dev_err(mmc_dev(host->mmc), "no RX DMA channel\n");
- }
-
- if (plat->dma_tx_param) {
- host->dma_tx_channel = dma_request_channel(mask,
- plat->dma_filter,
- plat->dma_tx_param);
- if (!host->dma_tx_channel)
- dev_warn(mmc_dev(host->mmc), "no TX DMA channel\n");
- } else {
- host->dma_tx_channel = host->dma_rx_channel;
- }
-
- if (host->dma_rx_channel)
- rxname = dma_chan_name(host->dma_rx_channel);
- else
- rxname = "none";
-
- if (host->dma_tx_channel)
- txname = dma_chan_name(host->dma_tx_channel);
- else
- txname = "none";
-
- dev_info(mmc_dev(host->mmc), "DMA channels RX %s, TX %s\n",
- rxname, txname);
-
- /*
- * Limit the maximum segment size in any SG entry according to
- * the parameters of the DMA engine device.
- */
- if (host->dma_tx_channel) {
- struct device *dev = host->dma_tx_channel->device->dev;
- unsigned int max_seg_size = dma_get_max_seg_size(dev);
-
- if (max_seg_size < host->mmc->max_seg_size)
- host->mmc->max_seg_size = max_seg_size;
- }
- if (host->dma_rx_channel) {
- struct device *dev = host->dma_rx_channel->device->dev;
- unsigned int max_seg_size = dma_get_max_seg_size(dev);
-
- if (max_seg_size < host->mmc->max_seg_size)
- host->mmc->max_seg_size = max_seg_size;
- }
-}
-
-/*
- * This is used in __devinit or __devexit so inline it
- * so it can be discarded.
- */
-static inline void mmci_dma_release(struct mmci_host *host)
-{
- struct mmci_platform_data *plat = host->plat;
-
- if (host->dma_rx_channel)
- dma_release_channel(host->dma_rx_channel);
- if (host->dma_tx_channel && plat->dma_tx_param)
- dma_release_channel(host->dma_tx_channel);
- host->dma_rx_channel = host->dma_tx_channel = NULL;
-}
-
-static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data)
-{
- struct dma_chan *chan = host->dma_current;
- enum dma_data_direction dir;
- u32 status;
- int i;
-
- /* Wait up to 1ms for the DMA to complete */
- for (i = 0; ; i++) {
- status = readl(host->base + MMCISTATUS);
- if (!(status & MCI_RXDATAAVLBLMASK) || i >= 100)
- break;
- udelay(10);
- }
-
- /*
- * Check to see whether we still have some data left in the FIFO -
- * this catches DMA controllers which are unable to monitor the
- * DMALBREQ and DMALSREQ signals while allowing us to DMA to non-
- * contiguous buffers. On TX, we'll get a FIFO underrun error.
- */
- if (status & MCI_RXDATAAVLBLMASK) {
- dmaengine_terminate_all(chan);
- if (!data->error)
- data->error = -EIO;
- }
-
- if (data->flags & MMC_DATA_WRITE) {
- dir = DMA_TO_DEVICE;
- } else {
- dir = DMA_FROM_DEVICE;
- }
-
- if (!data->host_cookie)
- dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir);
-
- /*
- * Use of DMA with scatter-gather is impossible.
- * Give up with DMA and switch back to PIO mode.
- */
- if (status & MCI_RXDATAAVLBLMASK) {
- dev_err(mmc_dev(host->mmc), "buggy DMA detected. Taking evasive action.\n");
- mmci_dma_release(host);
- }
-}
-
-static void mmci_dma_data_error(struct mmci_host *host)
-{
- dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n");
- dmaengine_terminate_all(host->dma_current);
-}
-
-static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
- struct mmci_host_next *next)
-{
- struct variant_data *variant = host->variant;
- struct dma_slave_config conf = {
- .src_addr = host->phybase + MMCIFIFO,
- .dst_addr = host->phybase + MMCIFIFO,
- .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
- .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
- .src_maxburst = variant->fifohalfsize >> 2, /* # of words */
- .dst_maxburst = variant->fifohalfsize >> 2, /* # of words */
- .device_fc = false,
- };
- struct dma_chan *chan;
- struct dma_device *device;
- struct dma_async_tx_descriptor *desc;
- enum dma_data_direction buffer_dirn;
- int nr_sg;
-
- /* Check if next job is already prepared */
- if (data->host_cookie && !next &&
- host->dma_current && host->dma_desc_current)
- return 0;
-
- if (!next) {
- host->dma_current = NULL;
- host->dma_desc_current = NULL;
- }
-
- if (data->flags & MMC_DATA_READ) {
- conf.direction = DMA_DEV_TO_MEM;
- buffer_dirn = DMA_FROM_DEVICE;
- chan = host->dma_rx_channel;
- } else {
- conf.direction = DMA_MEM_TO_DEV;
- buffer_dirn = DMA_TO_DEVICE;
- chan = host->dma_tx_channel;
- }
-
- /* If there's no DMA channel, fall back to PIO */
- if (!chan)
- return -EINVAL;
-
- /* If less than or equal to the fifo size, don't bother with DMA */
- if (data->blksz * data->blocks <= variant->fifosize)
- return -EINVAL;
-
- device = chan->device;
- nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len, buffer_dirn);
- if (nr_sg == 0)
- return -EINVAL;
-
- dmaengine_slave_config(chan, &conf);
- desc = dmaengine_prep_slave_sg(chan, data->sg, nr_sg,
- conf.direction, DMA_CTRL_ACK);
- if (!desc)
- goto unmap_exit;
-
- if (next) {
- next->dma_chan = chan;
- next->dma_desc = desc;
- } else {
- host->dma_current = chan;
- host->dma_desc_current = desc;
- }
-
- return 0;
-
- unmap_exit:
- if (!next)
- dmaengine_terminate_all(chan);
- dma_unmap_sg(device->dev, data->sg, data->sg_len, buffer_dirn);
- return -ENOMEM;
-}
-
-static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
-{
- int ret;
- struct mmc_data *data = host->data;
-
- ret = mmci_dma_prep_data(host, host->data, NULL);
- if (ret)
- return ret;
-
- /* Okay, go for it. */
- dev_vdbg(mmc_dev(host->mmc),
- "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n",
- data->sg_len, data->blksz, data->blocks, data->flags);
- dmaengine_submit(host->dma_desc_current);
- dma_async_issue_pending(host->dma_current);
-
- datactrl |= MCI_DPSM_DMAENABLE;
-
- /* Trigger the DMA transfer */
- writel(datactrl, host->base + MMCIDATACTRL);
-
- /*
- * Let the MMCI say when the data is ended and it's time
- * to fire next DMA request. When that happens, MMCI will
- * call mmci_data_end()
- */
- writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK,
- host->base + MMCIMASK0);
- return 0;
-}
-
-static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data)
-{
- struct mmci_host_next *next = &host->next_data;
-
- if (data->host_cookie && data->host_cookie != next->cookie) {
- pr_warning("[%s] invalid cookie: data->host_cookie %d"
- " host->next_data.cookie %d\n",
- __func__, data->host_cookie, host->next_data.cookie);
- data->host_cookie = 0;
- }
-
- if (!data->host_cookie)
- return;
-
- host->dma_desc_current = next->dma_desc;
- host->dma_current = next->dma_chan;
-
- next->dma_desc = NULL;
- next->dma_chan = NULL;
-}
-
-static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq,
- bool is_first_req)
-{
- struct mmci_host *host = mmc_priv(mmc);
- struct mmc_data *data = mrq->data;
- struct mmci_host_next *nd = &host->next_data;
-
- if (!data)
- return;
-
- if (data->host_cookie) {
- data->host_cookie = 0;
- return;
- }
-
- /* if config for dma */
- if (((data->flags & MMC_DATA_WRITE) && host->dma_tx_channel) ||
- ((data->flags & MMC_DATA_READ) && host->dma_rx_channel)) {
- if (mmci_dma_prep_data(host, data, nd))
- data->host_cookie = 0;
- else
- data->host_cookie = ++nd->cookie < 0 ? 1 : nd->cookie;
- }
-}
-
-static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq,
- int err)
-{
- struct mmci_host *host = mmc_priv(mmc);
- struct mmc_data *data = mrq->data;
- struct dma_chan *chan;
- enum dma_data_direction dir;
-
- if (!data)
- return;
-
- if (data->flags & MMC_DATA_READ) {
- dir = DMA_FROM_DEVICE;
- chan = host->dma_rx_channel;
- } else {
- dir = DMA_TO_DEVICE;
- chan = host->dma_tx_channel;
- }
-
-
- /* if config for dma */
- if (chan) {
- if (err)
- dmaengine_terminate_all(chan);
- if (data->host_cookie)
- dma_unmap_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, dir);
- mrq->data->host_cookie = 0;
- }
-}
-
-#else
-/* Blank functions if the DMA engine is not available */
-static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data)
-{
-}
-static inline void mmci_dma_setup(struct mmci_host *host)
-{
-}
-
-static inline void mmci_dma_release(struct mmci_host *host)
-{
-}
-
-static inline void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data)
-{
-}
-
-static inline void mmci_dma_data_error(struct mmci_host *host)
-{
-}
-
-static inline int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
-{
- return -ENOSYS;
-}
-
-#define mmci_pre_request NULL
-#define mmci_post_request NULL
-
-#endif
-
-static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
-{
- struct variant_data *variant = host->variant;
- unsigned int datactrl, timeout, irqmask;
- unsigned long long clks;
- void __iomem *base;
- int blksz_bits;
-
- dev_dbg(mmc_dev(host->mmc), "blksz %04x blks %04x flags %08x\n",
- data->blksz, data->blocks, data->flags);
-
- host->data = data;
- host->size = data->blksz * data->blocks;
- data->bytes_xfered = 0;
-
- clks = (unsigned long long)data->timeout_ns * host->cclk;
- do_div(clks, 1000000000UL);
-
- timeout = data->timeout_clks + (unsigned int)clks;
-
- base = host->base;
- writel(timeout, base + MMCIDATATIMER);
- writel(host->size, base + MMCIDATALENGTH);
-
- blksz_bits = ffs(data->blksz) - 1;
- BUG_ON(1 << blksz_bits != data->blksz);
-
- if (variant->blksz_datactrl16)
- datactrl = MCI_DPSM_ENABLE | (data->blksz << 16);
- else
- datactrl = MCI_DPSM_ENABLE | blksz_bits << 4;
-
- if (data->flags & MMC_DATA_READ)
- datactrl |= MCI_DPSM_DIRECTION;
-
- /* The ST Micro variants has a special bit to enable SDIO */
- if (variant->sdio && host->mmc->card)
- if (mmc_card_sdio(host->mmc->card))
- datactrl |= MCI_ST_DPSM_SDIOEN;
-
- /*
- * Attempt to use DMA operation mode, if this
- * should fail, fall back to PIO mode
- */
- if (!mmci_dma_start_data(host, datactrl))
- return;
-
- /* IRQ mode, map the SG list for CPU reading/writing */
- mmci_init_sg(host, data);
-
- if (data->flags & MMC_DATA_READ) {
- irqmask = MCI_RXFIFOHALFFULLMASK;
-
- /*
- * If we have less than the fifo 'half-full' threshold to
- * transfer, trigger a PIO interrupt as soon as any data
- * is available.
- */
- if (host->size < variant->fifohalfsize)
- irqmask |= MCI_RXDATAAVLBLMASK;
- } else {
- /*
- * We don't actually need to include "FIFO empty" here
- * since its implicit in "FIFO half empty".
- */
- irqmask = MCI_TXFIFOHALFEMPTYMASK;
- }
-
- writel(datactrl, base + MMCIDATACTRL);
- writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0);
- mmci_set_mask1(host, irqmask);
-}
-
-static void
-mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
-{
- void __iomem *base = host->base;
-
- dev_dbg(mmc_dev(host->mmc), "op %02x arg %08x flags %08x\n",
- cmd->opcode, cmd->arg, cmd->flags);
-
- if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
- writel(0, base + MMCICOMMAND);
- udelay(1);
- }
-
- c |= cmd->opcode | MCI_CPSM_ENABLE;
- if (cmd->flags & MMC_RSP_PRESENT) {
- if (cmd->flags & MMC_RSP_136)
- c |= MCI_CPSM_LONGRSP;
- c |= MCI_CPSM_RESPONSE;
- }
- if (/*interrupt*/0)
- c |= MCI_CPSM_INTERRUPT;
-
- host->cmd = cmd;
-
- writel(cmd->arg, base + MMCIARGUMENT);
- writel(c, base + MMCICOMMAND);
-}
-
-static void
-mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
- unsigned int status)
-{
- /* First check for errors */
- if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR|
- MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
- u32 remain, success;
-
- /* Terminate the DMA transfer */
- if (dma_inprogress(host))
- mmci_dma_data_error(host);
-
- /*
- * Calculate how far we are into the transfer. Note that
- * the data counter gives the number of bytes transferred
- * on the MMC bus, not on the host side. On reads, this
- * can be as much as a FIFO-worth of data ahead. This
- * matters for FIFO overruns only.
- */
- remain = readl(host->base + MMCIDATACNT);
- success = data->blksz * data->blocks - remain;
-
- dev_dbg(mmc_dev(host->mmc), "MCI ERROR IRQ, status 0x%08x at 0x%08x\n",
- status, success);
- if (status & MCI_DATACRCFAIL) {
- /* Last block was not successful */
- success -= 1;
- data->error = -EILSEQ;
- } else if (status & MCI_DATATIMEOUT) {
- data->error = -ETIMEDOUT;
- } else if (status & MCI_STARTBITERR) {
- data->error = -ECOMM;
- } else if (status & MCI_TXUNDERRUN) {
- data->error = -EIO;
- } else if (status & MCI_RXOVERRUN) {
- if (success > host->variant->fifosize)
- success -= host->variant->fifosize;
- else
- success = 0;
- data->error = -EIO;
- }
- data->bytes_xfered = round_down(success, data->blksz);
- }
-
- if (status & MCI_DATABLOCKEND)
- dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n");
-
- if (status & MCI_DATAEND || data->error) {
- if (dma_inprogress(host))
- mmci_dma_unmap(host, data);
- mmci_stop_data(host);
-
- if (!data->error)
- /* The error clause is handled above, success! */
- data->bytes_xfered = data->blksz * data->blocks;
-
- if (!data->stop) {
- mmci_request_end(host, data->mrq);
- } else {
- mmci_start_command(host, data->stop, 0);
- }
- }
-}
-
-static void
-mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
- unsigned int status)
-{
- void __iomem *base = host->base;
-
- host->cmd = NULL;
-
- if (status & MCI_CMDTIMEOUT) {
- cmd->error = -ETIMEDOUT;
- } else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) {
- cmd->error = -EILSEQ;
- } else {
- cmd->resp[0] = readl(base + MMCIRESPONSE0);
- cmd->resp[1] = readl(base + MMCIRESPONSE1);
- cmd->resp[2] = readl(base + MMCIRESPONSE2);
- cmd->resp[3] = readl(base + MMCIRESPONSE3);
- }
-
- if (!cmd->data || cmd->error) {
- if (host->data) {
- /* Terminate the DMA transfer */
- if (dma_inprogress(host))
- mmci_dma_data_error(host);
- mmci_stop_data(host);
- }
- mmci_request_end(host, cmd->mrq);
- } else if (!(cmd->data->flags & MMC_DATA_READ)) {
- mmci_start_data(host, cmd->data);
- }
-}
-
-static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int remain)
-{
- void __iomem *base = host->base;
- char *ptr = buffer;
- u32 status;
- int host_remain = host->size;
-
- do {
- int count = host_remain - (readl(base + MMCIFIFOCNT) << 2);
-
- if (count > remain)
- count = remain;
-
- if (count <= 0)
- break;
-
- /*
- * SDIO especially may want to send something that is
- * not divisible by 4 (as opposed to card sectors
- * etc). Therefore make sure to always read the last bytes
- * while only doing full 32-bit reads towards the FIFO.
- */
- if (unlikely(count & 0x3)) {
- if (count < 4) {
- unsigned char buf[4];
- readsl(base + MMCIFIFO, buf, 1);
- memcpy(ptr, buf, count);
- } else {
- readsl(base + MMCIFIFO, ptr, count >> 2);
- count &= ~0x3;
- }
- } else {
- readsl(base + MMCIFIFO, ptr, count >> 2);
- }
-
- ptr += count;
- remain -= count;
- host_remain -= count;
-
- if (remain == 0)
- break;
-
- status = readl(base + MMCISTATUS);
- } while (status & MCI_RXDATAAVLBL);
-
- return ptr - buffer;
-}
-
-static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int remain, u32 status)
-{
- struct variant_data *variant = host->variant;
- void __iomem *base = host->base;
- char *ptr = buffer;
-
- do {
- unsigned int count, maxcnt;
-
- maxcnt = status & MCI_TXFIFOEMPTY ?
- variant->fifosize : variant->fifohalfsize;
- count = min(remain, maxcnt);
-
- /*
- * The ST Micro variant for SDIO transfer sizes
- * less then 8 bytes should have clock H/W flow
- * control disabled.
- */
- if (variant->sdio &&
- mmc_card_sdio(host->mmc->card)) {
- u32 clk;
- if (count < 8)
- clk = host->clk_reg & ~variant->clkreg_enable;
- else
- clk = host->clk_reg | variant->clkreg_enable;
-
- mmci_write_clkreg(host, clk);
- }
-
- /*
- * SDIO especially may want to send something that is
- * not divisible by 4 (as opposed to card sectors
- * etc), and the FIFO only accept full 32-bit writes.
- * So compensate by adding +3 on the count, a single
- * byte become a 32bit write, 7 bytes will be two
- * 32bit writes etc.
- */
- writesl(base + MMCIFIFO, ptr, (count + 3) >> 2);
-
- ptr += count;
- remain -= count;
-
- if (remain == 0)
- break;
-
- status = readl(base + MMCISTATUS);
- } while (status & MCI_TXFIFOHALFEMPTY);
-
- return ptr - buffer;
-}
-
-/*
- * PIO data transfer IRQ handler.
- */
-static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
-{
- struct mmci_host *host = dev_id;
- struct sg_mapping_iter *sg_miter = &host->sg_miter;
- struct variant_data *variant = host->variant;
- void __iomem *base = host->base;
- unsigned long flags;
- u32 status;
-
- status = readl(base + MMCISTATUS);
-
- dev_dbg(mmc_dev(host->mmc), "irq1 (pio) %08x\n", status);
-
- local_irq_save(flags);
-
- do {
- unsigned int remain, len;
- char *buffer;
-
- /*
- * For write, we only need to test the half-empty flag
- * here - if the FIFO is completely empty, then by
- * definition it is more than half empty.
- *
- * For read, check for data available.
- */
- if (!(status & (MCI_TXFIFOHALFEMPTY|MCI_RXDATAAVLBL)))
- break;
-
- if (!sg_miter_next(sg_miter))
- break;
-
- buffer = sg_miter->addr;
- remain = sg_miter->length;
-
- len = 0;
- if (status & MCI_RXACTIVE)
- len = mmci_pio_read(host, buffer, remain);
- if (status & MCI_TXACTIVE)
- len = mmci_pio_write(host, buffer, remain, status);
-
- sg_miter->consumed = len;
-
- host->size -= len;
- remain -= len;
-
- if (remain)
- break;
-
- status = readl(base + MMCISTATUS);
- } while (1);
-
- sg_miter_stop(sg_miter);
-
- local_irq_restore(flags);
-
- /*
- * If we have less than the fifo 'half-full' threshold to transfer,
- * trigger a PIO interrupt as soon as any data is available.
- */
- if (status & MCI_RXACTIVE && host->size < variant->fifohalfsize)
- mmci_set_mask1(host, MCI_RXDATAAVLBLMASK);
-
- /*
- * If we run out of data, disable the data IRQs; this
- * prevents a race where the FIFO becomes empty before
- * the chip itself has disabled the data path, and
- * stops us racing with our data end IRQ.
- */
- if (host->size == 0) {
- mmci_set_mask1(host, 0);
- writel(readl(base + MMCIMASK0) | MCI_DATAENDMASK, base + MMCIMASK0);
- }
-
- return IRQ_HANDLED;
-}
-
-/*
- * Handle completion of command and data transfers.
- */
-static irqreturn_t mmci_irq(int irq, void *dev_id)
-{
- struct mmci_host *host = dev_id;
- u32 status;
- int ret = 0;
-
- spin_lock(&host->lock);
-
- do {
- struct mmc_command *cmd;
- struct mmc_data *data;
-
- status = readl(host->base + MMCISTATUS);
-
- if (host->singleirq) {
- if (status & readl(host->base + MMCIMASK1))
- mmci_pio_irq(irq, dev_id);
-
- status &= ~MCI_IRQ1MASK;
- }
-
- status &= readl(host->base + MMCIMASK0);
- writel(status, host->base + MMCICLEAR);
-
- dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status);
-
- data = host->data;
- if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR|
- MCI_TXUNDERRUN|MCI_RXOVERRUN|MCI_DATAEND|
- MCI_DATABLOCKEND) && data)
- mmci_data_irq(host, data, status);
-
- cmd = host->cmd;
- if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd)
- mmci_cmd_irq(host, cmd, status);
-
- ret = 1;
- } while (status);
-
- spin_unlock(&host->lock);
-
- return IRQ_RETVAL(ret);
-}
-
-static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct mmci_host *host = mmc_priv(mmc);
- unsigned long flags;
-
- WARN_ON(host->mrq != NULL);
-
- if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
- dev_err(mmc_dev(mmc), "unsupported block size (%d bytes)\n",
- mrq->data->blksz);
- mrq->cmd->error = -EINVAL;
- mmc_request_done(mmc, mrq);
- return;
- }
-
- pm_runtime_get_sync(mmc_dev(mmc));
-
- spin_lock_irqsave(&host->lock, flags);
-
- host->mrq = mrq;
-
- if (mrq->data)
- mmci_get_next_data(host, mrq->data);
-
- if (mrq->data && mrq->data->flags & MMC_DATA_READ)
- mmci_start_data(host, mrq->data);
-
- mmci_start_command(host, mrq->cmd, 0);
-
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct mmci_host *host = mmc_priv(mmc);
- struct variant_data *variant = host->variant;
- u32 pwr = 0;
- unsigned long flags;
- int ret;
-
- pm_runtime_get_sync(mmc_dev(mmc));
-
- if (host->plat->ios_handler &&
- host->plat->ios_handler(mmc_dev(mmc), ios))
- dev_err(mmc_dev(mmc), "platform ios_handler failed\n");
-
- switch (ios->power_mode) {
- case MMC_POWER_OFF:
- if (host->vcc)
- ret = mmc_regulator_set_ocr(mmc, host->vcc, 0);
- break;
- case MMC_POWER_UP:
- 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.
- */
- goto out;
- }
- }
- /*
- * The ST Micro variant doesn't have the PL180s MCI_PWR_UP
- * and instead uses MCI_PWR_ON so apply whatever value is
- * configured in the variant data.
- */
- pwr |= variant->pwrreg_powerup;
-
- break;
- case MMC_POWER_ON:
- pwr |= MCI_PWR_ON;
- break;
- }
-
- if (variant->signal_direction && ios->power_mode != MMC_POWER_OFF) {
- /*
- * The ST Micro variant has some additional bits
- * indicating signal direction for the signals in
- * the SD/MMC bus and feedback-clock usage.
- */
- pwr |= host->plat->sigdir;
-
- if (ios->bus_width == MMC_BUS_WIDTH_4)
- pwr &= ~MCI_ST_DATA74DIREN;
- else if (ios->bus_width == MMC_BUS_WIDTH_1)
- pwr &= (~MCI_ST_DATA74DIREN &
- ~MCI_ST_DATA31DIREN &
- ~MCI_ST_DATA2DIREN);
- }
-
- if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) {
- if (host->hw_designer != AMBA_VENDOR_ST)
- pwr |= MCI_ROD;
- else {
- /*
- * The ST Micro variant use the ROD bit for something
- * else and only has OD (Open Drain).
- */
- pwr |= MCI_OD;
- }
- }
-
- spin_lock_irqsave(&host->lock, flags);
-
- mmci_set_clkreg(host, ios->clock);
- mmci_write_pwrreg(host, pwr);
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- out:
- pm_runtime_mark_last_busy(mmc_dev(mmc));
- pm_runtime_put_autosuspend(mmc_dev(mmc));
-}
-
-static int mmci_get_ro(struct mmc_host *mmc)
-{
- struct mmci_host *host = mmc_priv(mmc);
-
- if (host->gpio_wp == -ENOSYS)
- return -ENOSYS;
-
- return gpio_get_value_cansleep(host->gpio_wp);
-}
-
-static int mmci_get_cd(struct mmc_host *mmc)
-{
- struct mmci_host *host = mmc_priv(mmc);
- struct mmci_platform_data *plat = host->plat;
- unsigned int status;
-
- if (host->gpio_cd == -ENOSYS) {
- if (!plat->status)
- return 1; /* Assume always present */
-
- status = plat->status(mmc_dev(host->mmc));
- } else
- status = !!gpio_get_value_cansleep(host->gpio_cd)
- ^ plat->cd_invert;
-
- /*
- * Use positive logic throughout - status is zero for no card,
- * non-zero for card inserted.
- */
- return status;
-}
-
-static irqreturn_t mmci_cd_irq(int irq, void *dev_id)
-{
- struct mmci_host *host = dev_id;
-
- mmc_detect_change(host->mmc, msecs_to_jiffies(500));
-
- return IRQ_HANDLED;
-}
-
-static const struct mmc_host_ops mmci_ops = {
- .request = mmci_request,
- .pre_req = mmci_pre_request,
- .post_req = mmci_post_request,
- .set_ios = mmci_set_ios,
- .get_ro = mmci_get_ro,
- .get_cd = mmci_get_cd,
-};
-
-static int __devinit mmci_probe(struct amba_device *dev,
- const struct amba_id *id)
-{
- struct mmci_platform_data *plat = dev->dev.platform_data;
- struct variant_data *variant = id->data;
- struct mmci_host *host;
- struct mmc_host *mmc;
- int ret;
-
- /* must have platform data */
- if (!plat) {
- ret = -EINVAL;
- goto out;
- }
-
- ret = amba_request_regions(dev, DRIVER_NAME);
- if (ret)
- goto out;
-
- mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev);
- if (!mmc) {
- ret = -ENOMEM;
- goto rel_regions;
- }
-
- host = mmc_priv(mmc);
- host->mmc = mmc;
-
- host->gpio_wp = -ENOSYS;
- host->gpio_cd = -ENOSYS;
- host->gpio_cd_irq = -1;
-
- host->hw_designer = amba_manf(dev);
- host->hw_revision = amba_rev(dev);
- dev_dbg(mmc_dev(mmc), "designer ID = 0x%02x\n", host->hw_designer);
- dev_dbg(mmc_dev(mmc), "revision = 0x%01x\n", host->hw_revision);
-
- host->clk = clk_get(&dev->dev, NULL);
- if (IS_ERR(host->clk)) {
- ret = PTR_ERR(host->clk);
- host->clk = NULL;
- goto host_free;
- }
-
- ret = clk_prepare(host->clk);
- if (ret)
- goto clk_free;
-
- ret = clk_enable(host->clk);
- if (ret)
- goto clk_unprep;
-
- host->plat = plat;
- host->variant = variant;
- host->mclk = clk_get_rate(host->clk);
- /*
- * According to the spec, mclk is max 100 MHz,
- * so we try to adjust the clock down to this,
- * (if possible).
- */
- if (host->mclk > 100000000) {
- ret = clk_set_rate(host->clk, 100000000);
- if (ret < 0)
- goto clk_disable;
- host->mclk = clk_get_rate(host->clk);
- dev_dbg(mmc_dev(mmc), "eventual mclk rate: %u Hz\n",
- host->mclk);
- }
- host->phybase = dev->res.start;
- host->base = ioremap(dev->res.start, resource_size(&dev->res));
- if (!host->base) {
- ret = -ENOMEM;
- goto clk_disable;
- }
-
- mmc->ops = &mmci_ops;
- /*
- * The ARM and ST versions of the block have slightly different
- * clock divider equations which means that the minimum divider
- * differs too.
- */
- if (variant->st_clkdiv)
- mmc->f_min = DIV_ROUND_UP(host->mclk, 257);
- else
- mmc->f_min = DIV_ROUND_UP(host->mclk, 512);
- /*
- * If the platform data supplies a maximum operating
- * frequency, this takes precedence. Else, we fall back
- * to using the module parameter, which has a (low)
- * default value in case it is not specified. Either
- * value must not exceed the clock rate into the block,
- * of course.
- */
- if (plat->f_max)
- mmc->f_max = min(host->mclk, plat->f_max);
- else
- mmc->f_max = min(host->mclk, fmax);
- dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max);
-
-#ifdef CONFIG_REGULATOR
- /* If we're using the regulator framework, try to fetch a regulator */
- host->vcc = regulator_get(&dev->dev, "vmmc");
- if (IS_ERR(host->vcc))
- host->vcc = NULL;
- else {
- int mask = mmc_regulator_get_ocrmask(host->vcc);
-
- if (mask < 0)
- dev_err(&dev->dev, "error getting OCR mask (%d)\n",
- mask);
- else {
- host->mmc->ocr_avail = (u32) mask;
- if (plat->ocr_mask)
- dev_warn(&dev->dev,
- "Provided ocr_mask/setpower will not be used "
- "(using regulator instead)\n");
- }
- }
-#endif
- /* Fall back to platform data if no regulator is found */
- if (host->vcc == NULL)
- mmc->ocr_avail = plat->ocr_mask;
- mmc->caps = plat->capabilities;
- mmc->caps2 = plat->capabilities2;
-
- /*
- * We can do SGIO
- */
- mmc->max_segs = NR_SG;
-
- /*
- * Since only a certain number of bits are valid in the data length
- * register, we must ensure that we don't exceed 2^num-1 bytes in a
- * single request.
- */
- mmc->max_req_size = (1 << variant->datalength_bits) - 1;
-
- /*
- * Set the maximum segment size. Since we aren't doing DMA
- * (yet) we are only limited by the data length register.
- */
- mmc->max_seg_size = mmc->max_req_size;
-
- /*
- * Block size can be up to 2048 bytes, but must be a power of two.
- */
- mmc->max_blk_size = 1 << 11;
-
- /*
- * Limit the number of blocks transferred so that we don't overflow
- * the maximum request size.
- */
- mmc->max_blk_count = mmc->max_req_size >> 11;
-
- spin_lock_init(&host->lock);
-
- writel(0, host->base + MMCIMASK0);
- writel(0, host->base + MMCIMASK1);
- writel(0xfff, host->base + MMCICLEAR);
-
- if (gpio_is_valid(plat->gpio_cd)) {
- ret = gpio_request(plat->gpio_cd, DRIVER_NAME " (cd)");
- if (ret == 0)
- ret = gpio_direction_input(plat->gpio_cd);
- if (ret == 0)
- host->gpio_cd = plat->gpio_cd;
- else if (ret != -ENOSYS)
- goto err_gpio_cd;
-
- /*
- * A gpio pin that will detect cards when inserted and removed
- * will most likely want to trigger on the edges if it is
- * 0 when ejected and 1 when inserted (or mutatis mutandis
- * for the inverted case) so we request triggers on both
- * edges.
- */
- ret = request_any_context_irq(gpio_to_irq(plat->gpio_cd),
- mmci_cd_irq,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- DRIVER_NAME " (cd)", host);
- if (ret >= 0)
- host->gpio_cd_irq = gpio_to_irq(plat->gpio_cd);
- }
- if (gpio_is_valid(plat->gpio_wp)) {
- ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)");
- if (ret == 0)
- ret = gpio_direction_input(plat->gpio_wp);
- if (ret == 0)
- host->gpio_wp = plat->gpio_wp;
- else if (ret != -ENOSYS)
- goto err_gpio_wp;
- }
-
- if ((host->plat->status || host->gpio_cd != -ENOSYS)
- && host->gpio_cd_irq < 0)
- mmc->caps |= MMC_CAP_NEEDS_POLL;
-
- ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host);
- if (ret)
- goto unmap;
-
- if (dev->irq[1] == NO_IRQ || !dev->irq[1])
- host->singleirq = true;
- else {
- ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED,
- DRIVER_NAME " (pio)", host);
- if (ret)
- goto irq0_free;
- }
-
- writel(MCI_IRQENABLE, host->base + MMCIMASK0);
-
- amba_set_drvdata(dev, mmc);
-
- dev_info(&dev->dev, "%s: PL%03x manf %x rev%u at 0x%08llx irq %d,%d (pio)\n",
- mmc_hostname(mmc), amba_part(dev), amba_manf(dev),
- amba_rev(dev), (unsigned long long)dev->res.start,
- dev->irq[0], dev->irq[1]);
-
- mmci_dma_setup(host);
-
- pm_runtime_set_autosuspend_delay(&dev->dev, 50);
- pm_runtime_use_autosuspend(&dev->dev);
- pm_runtime_put(&dev->dev);
-
- mmc_add_host(mmc);
-
- return 0;
-
- irq0_free:
- free_irq(dev->irq[0], host);
- unmap:
- if (host->gpio_wp != -ENOSYS)
- gpio_free(host->gpio_wp);
- err_gpio_wp:
- if (host->gpio_cd_irq >= 0)
- free_irq(host->gpio_cd_irq, host);
- if (host->gpio_cd != -ENOSYS)
- gpio_free(host->gpio_cd);
- err_gpio_cd:
- iounmap(host->base);
- clk_disable:
- clk_disable(host->clk);
- clk_unprep:
- clk_unprepare(host->clk);
- clk_free:
- clk_put(host->clk);
- host_free:
- mmc_free_host(mmc);
- rel_regions:
- amba_release_regions(dev);
- out:
- return ret;
-}
-
-static int __devexit mmci_remove(struct amba_device *dev)
-{
- struct mmc_host *mmc = amba_get_drvdata(dev);
-
- amba_set_drvdata(dev, NULL);
-
- if (mmc) {
- struct mmci_host *host = mmc_priv(mmc);
-
- /*
- * Undo pm_runtime_put() in probe. We use the _sync
- * version here so that we can access the primecell.
- */
- pm_runtime_get_sync(&dev->dev);
-
- mmc_remove_host(mmc);
-
- writel(0, host->base + MMCIMASK0);
- writel(0, host->base + MMCIMASK1);
-
- writel(0, host->base + MMCICOMMAND);
- writel(0, host->base + MMCIDATACTRL);
-
- mmci_dma_release(host);
- free_irq(dev->irq[0], host);
- if (!host->singleirq)
- free_irq(dev->irq[1], host);
-
- if (host->gpio_wp != -ENOSYS)
- gpio_free(host->gpio_wp);
- if (host->gpio_cd_irq >= 0)
- free_irq(host->gpio_cd_irq, host);
- if (host->gpio_cd != -ENOSYS)
- gpio_free(host->gpio_cd);
-
- iounmap(host->base);
- clk_disable(host->clk);
- clk_unprepare(host->clk);
- clk_put(host->clk);
-
- if (host->vcc)
- mmc_regulator_set_ocr(mmc, host->vcc, 0);
- regulator_put(host->vcc);
-
- mmc_free_host(mmc);
-
- amba_release_regions(dev);
- }
-
- return 0;
-}
-
-#ifdef CONFIG_SUSPEND
-static int mmci_suspend(struct device *dev)
-{
- struct amba_device *adev = to_amba_device(dev);
- struct mmc_host *mmc = amba_get_drvdata(adev);
- int ret = 0;
-
- if (mmc) {
- struct mmci_host *host = mmc_priv(mmc);
-
- ret = mmc_suspend_host(mmc);
- if (ret == 0) {
- pm_runtime_get_sync(dev);
- writel(0, host->base + MMCIMASK0);
- }
- }
-
- return ret;
-}
-
-static int mmci_resume(struct device *dev)
-{
- struct amba_device *adev = to_amba_device(dev);
- struct mmc_host *mmc = amba_get_drvdata(adev);
- int ret = 0;
-
- if (mmc) {
- struct mmci_host *host = mmc_priv(mmc);
-
- writel(MCI_IRQENABLE, host->base + MMCIMASK0);
- pm_runtime_put(dev);
-
- ret = mmc_resume_host(mmc);
- }
-
- return ret;
-}
-#endif
-
-static const struct dev_pm_ops mmci_dev_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(mmci_suspend, mmci_resume)
-};
-
-static struct amba_id mmci_ids[] = {
- {
- .id = 0x00041180,
- .mask = 0xff0fffff,
- .data = &variant_arm,
- },
- {
- .id = 0x01041180,
- .mask = 0xff0fffff,
- .data = &variant_arm_extended_fifo,
- },
- {
- .id = 0x00041181,
- .mask = 0x000fffff,
- .data = &variant_arm,
- },
- /* ST Micro variants */
- {
- .id = 0x00180180,
- .mask = 0x00ffffff,
- .data = &variant_u300,
- },
- {
- .id = 0x00280180,
- .mask = 0x00ffffff,
- .data = &variant_u300,
- },
- {
- .id = 0x00480180,
- .mask = 0xf0ffffff,
- .data = &variant_ux500,
- },
- {
- .id = 0x10480180,
- .mask = 0xf0ffffff,
- .data = &variant_ux500v2,
- },
- { 0, 0 },
-};
-
-MODULE_DEVICE_TABLE(amba, mmci_ids);
-
-static struct amba_driver mmci_driver = {
- .drv = {
- .name = DRIVER_NAME,
- .pm = &mmci_dev_pm_ops,
- },
- .probe = mmci_probe,
- .remove = __devexit_p(mmci_remove),
- .id_table = mmci_ids,
-};
-
-module_amba_driver(mmci_driver);
-
-module_param(fmax, uint, 0444);
-
-MODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver");
-MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/mmci.h b/ANDROID_3.4.5/drivers/mmc/host/mmci.h
deleted file mode 100644
index d437ccf6..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/mmci.h
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * linux/drivers/mmc/host/mmci.h - ARM PrimeCell MMCI PL180/1 driver
- *
- * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#define MMCIPOWER 0x000
-#define MCI_PWR_OFF 0x00
-#define MCI_PWR_UP 0x02
-#define MCI_PWR_ON 0x03
-#define MCI_OD (1 << 6)
-#define MCI_ROD (1 << 7)
-
-#define MMCICLOCK 0x004
-#define MCI_CLK_ENABLE (1 << 8)
-#define MCI_CLK_PWRSAVE (1 << 9)
-#define MCI_CLK_BYPASS (1 << 10)
-#define MCI_4BIT_BUS (1 << 11)
-/*
- * 8bit wide buses, hardware flow contronl, negative edges and clock inversion
- * supported in ST Micro U300 and Ux500 versions
- */
-#define MCI_ST_8BIT_BUS (1 << 12)
-#define MCI_ST_U300_HWFCEN (1 << 13)
-#define MCI_ST_UX500_NEG_EDGE (1 << 13)
-#define MCI_ST_UX500_HWFCEN (1 << 14)
-#define MCI_ST_UX500_CLK_INV (1 << 15)
-
-#define MMCIARGUMENT 0x008
-#define MMCICOMMAND 0x00c
-#define MCI_CPSM_RESPONSE (1 << 6)
-#define MCI_CPSM_LONGRSP (1 << 7)
-#define MCI_CPSM_INTERRUPT (1 << 8)
-#define MCI_CPSM_PENDING (1 << 9)
-#define MCI_CPSM_ENABLE (1 << 10)
-#define MCI_SDIO_SUSP (1 << 11)
-#define MCI_ENCMD_COMPL (1 << 12)
-#define MCI_NIEN (1 << 13)
-#define MCI_CE_ATACMD (1 << 14)
-
-#define MMCIRESPCMD 0x010
-#define MMCIRESPONSE0 0x014
-#define MMCIRESPONSE1 0x018
-#define MMCIRESPONSE2 0x01c
-#define MMCIRESPONSE3 0x020
-#define MMCIDATATIMER 0x024
-#define MMCIDATALENGTH 0x028
-#define MMCIDATACTRL 0x02c
-#define MCI_DPSM_ENABLE (1 << 0)
-#define MCI_DPSM_DIRECTION (1 << 1)
-#define MCI_DPSM_MODE (1 << 2)
-#define MCI_DPSM_DMAENABLE (1 << 3)
-#define MCI_DPSM_BLOCKSIZE (1 << 4)
-/* Control register extensions in the ST Micro U300 and Ux500 versions */
-#define MCI_ST_DPSM_RWSTART (1 << 8)
-#define MCI_ST_DPSM_RWSTOP (1 << 9)
-#define MCI_ST_DPSM_RWMOD (1 << 10)
-#define MCI_ST_DPSM_SDIOEN (1 << 11)
-/* Control register extensions in the ST Micro Ux500 versions */
-#define MCI_ST_DPSM_DMAREQCTL (1 << 12)
-#define MCI_ST_DPSM_DBOOTMODEEN (1 << 13)
-#define MCI_ST_DPSM_BUSYMODE (1 << 14)
-#define MCI_ST_DPSM_DDRMODE (1 << 15)
-
-#define MMCIDATACNT 0x030
-#define MMCISTATUS 0x034
-#define MCI_CMDCRCFAIL (1 << 0)
-#define MCI_DATACRCFAIL (1 << 1)
-#define MCI_CMDTIMEOUT (1 << 2)
-#define MCI_DATATIMEOUT (1 << 3)
-#define MCI_TXUNDERRUN (1 << 4)
-#define MCI_RXOVERRUN (1 << 5)
-#define MCI_CMDRESPEND (1 << 6)
-#define MCI_CMDSENT (1 << 7)
-#define MCI_DATAEND (1 << 8)
-#define MCI_STARTBITERR (1 << 9)
-#define MCI_DATABLOCKEND (1 << 10)
-#define MCI_CMDACTIVE (1 << 11)
-#define MCI_TXACTIVE (1 << 12)
-#define MCI_RXACTIVE (1 << 13)
-#define MCI_TXFIFOHALFEMPTY (1 << 14)
-#define MCI_RXFIFOHALFFULL (1 << 15)
-#define MCI_TXFIFOFULL (1 << 16)
-#define MCI_RXFIFOFULL (1 << 17)
-#define MCI_TXFIFOEMPTY (1 << 18)
-#define MCI_RXFIFOEMPTY (1 << 19)
-#define MCI_TXDATAAVLBL (1 << 20)
-#define MCI_RXDATAAVLBL (1 << 21)
-/* Extended status bits for the ST Micro variants */
-#define MCI_ST_SDIOIT (1 << 22)
-#define MCI_ST_CEATAEND (1 << 23)
-
-#define MMCICLEAR 0x038
-#define MCI_CMDCRCFAILCLR (1 << 0)
-#define MCI_DATACRCFAILCLR (1 << 1)
-#define MCI_CMDTIMEOUTCLR (1 << 2)
-#define MCI_DATATIMEOUTCLR (1 << 3)
-#define MCI_TXUNDERRUNCLR (1 << 4)
-#define MCI_RXOVERRUNCLR (1 << 5)
-#define MCI_CMDRESPENDCLR (1 << 6)
-#define MCI_CMDSENTCLR (1 << 7)
-#define MCI_DATAENDCLR (1 << 8)
-#define MCI_STARTBITERRCLR (1 << 9)
-#define MCI_DATABLOCKENDCLR (1 << 10)
-/* Extended status bits for the ST Micro variants */
-#define MCI_ST_SDIOITC (1 << 22)
-#define MCI_ST_CEATAENDC (1 << 23)
-
-#define MMCIMASK0 0x03c
-#define MCI_CMDCRCFAILMASK (1 << 0)
-#define MCI_DATACRCFAILMASK (1 << 1)
-#define MCI_CMDTIMEOUTMASK (1 << 2)
-#define MCI_DATATIMEOUTMASK (1 << 3)
-#define MCI_TXUNDERRUNMASK (1 << 4)
-#define MCI_RXOVERRUNMASK (1 << 5)
-#define MCI_CMDRESPENDMASK (1 << 6)
-#define MCI_CMDSENTMASK (1 << 7)
-#define MCI_DATAENDMASK (1 << 8)
-#define MCI_STARTBITERRMASK (1 << 9)
-#define MCI_DATABLOCKENDMASK (1 << 10)
-#define MCI_CMDACTIVEMASK (1 << 11)
-#define MCI_TXACTIVEMASK (1 << 12)
-#define MCI_RXACTIVEMASK (1 << 13)
-#define MCI_TXFIFOHALFEMPTYMASK (1 << 14)
-#define MCI_RXFIFOHALFFULLMASK (1 << 15)
-#define MCI_TXFIFOFULLMASK (1 << 16)
-#define MCI_RXFIFOFULLMASK (1 << 17)
-#define MCI_TXFIFOEMPTYMASK (1 << 18)
-#define MCI_RXFIFOEMPTYMASK (1 << 19)
-#define MCI_TXDATAAVLBLMASK (1 << 20)
-#define MCI_RXDATAAVLBLMASK (1 << 21)
-/* Extended status bits for the ST Micro variants */
-#define MCI_ST_SDIOITMASK (1 << 22)
-#define MCI_ST_CEATAENDMASK (1 << 23)
-
-#define MMCIMASK1 0x040
-#define MMCIFIFOCNT 0x048
-#define MMCIFIFO 0x080 /* to 0x0bc */
-
-#define MCI_IRQENABLE \
- (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \
- MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \
- MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_STARTBITERRMASK)
-
-/* These interrupts are directed to IRQ1 when two IRQ lines are available */
-#define MCI_IRQ1MASK \
- (MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \
- MCI_TXFIFOHALFEMPTYMASK)
-
-#define NR_SG 128
-
-struct clk;
-struct variant_data;
-struct dma_chan;
-
-struct mmci_host_next {
- struct dma_async_tx_descriptor *dma_desc;
- struct dma_chan *dma_chan;
- s32 cookie;
-};
-
-struct mmci_host {
- phys_addr_t phybase;
- void __iomem *base;
- struct mmc_request *mrq;
- struct mmc_command *cmd;
- struct mmc_data *data;
- struct mmc_host *mmc;
- struct clk *clk;
- int gpio_cd;
- int gpio_wp;
- int gpio_cd_irq;
- bool singleirq;
-
- spinlock_t lock;
-
- unsigned int mclk;
- unsigned int cclk;
- u32 pwr_reg;
- u32 clk_reg;
- struct mmci_platform_data *plat;
- struct variant_data *variant;
-
- u8 hw_designer;
- u8 hw_revision:4;
-
- struct timer_list timer;
- unsigned int oldstat;
-
- /* pio stuff */
- struct sg_mapping_iter sg_miter;
- unsigned int size;
- struct regulator *vcc;
-
-#ifdef CONFIG_DMA_ENGINE
- /* DMA stuff */
- struct dma_chan *dma_current;
- struct dma_chan *dma_rx_channel;
- struct dma_chan *dma_tx_channel;
- struct dma_async_tx_descriptor *dma_desc_current;
- struct mmci_host_next next_data;
-
-#define dma_inprogress(host) ((host)->dma_current)
-#else
-#define dma_inprogress(host) (0)
-#endif
-};
-
diff --git a/ANDROID_3.4.5/drivers/mmc/host/msm_sdcc.c b/ANDROID_3.4.5/drivers/mmc/host/msm_sdcc.c
deleted file mode 100644
index 1d14cda9..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/msm_sdcc.c
+++ /dev/null
@@ -1,1486 +0,0 @@
-/*
- * linux/drivers/mmc/host/msm_sdcc.c - Qualcomm MSM 7X00A SDCC Driver
- *
- * Copyright (C) 2007 Google Inc,
- * Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
- * Copyright (C) 2009, Code Aurora Forum. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Based on mmci.c
- *
- * Author: San Mehat (san@android.com)
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/highmem.h>
-#include <linux/log2.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sdio.h>
-#include <linux/clk.h>
-#include <linux/scatterlist.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-#include <linux/debugfs.h>
-#include <linux/io.h>
-#include <linux/memory.h>
-#include <linux/gfp.h>
-#include <linux/gpio.h>
-
-#include <asm/cacheflush.h>
-#include <asm/div64.h>
-#include <asm/sizes.h>
-
-#include <mach/mmc.h>
-#include <mach/msm_iomap.h>
-#include <mach/dma.h>
-#include <mach/clk.h>
-
-#include "msm_sdcc.h"
-
-#define DRIVER_NAME "msm-sdcc"
-
-#define BUSCLK_PWRSAVE 1
-#define BUSCLK_TIMEOUT (HZ)
-static unsigned int msmsdcc_fmin = 144000;
-static unsigned int msmsdcc_fmax = 50000000;
-static unsigned int msmsdcc_4bit = 1;
-static unsigned int msmsdcc_pwrsave = 1;
-static unsigned int msmsdcc_piopoll = 1;
-static unsigned int msmsdcc_sdioirq;
-
-#define PIO_SPINMAX 30
-#define CMD_SPINMAX 20
-
-
-static inline void
-msmsdcc_disable_clocks(struct msmsdcc_host *host, int deferr)
-{
- WARN_ON(!host->clks_on);
-
- BUG_ON(host->curr.mrq);
-
- if (deferr) {
- mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT);
- } else {
- del_timer_sync(&host->busclk_timer);
- /* Need to check clks_on again in case the busclk
- * timer fired
- */
- if (host->clks_on) {
- clk_disable(host->clk);
- clk_disable(host->pclk);
- host->clks_on = 0;
- }
- }
-}
-
-static inline int
-msmsdcc_enable_clocks(struct msmsdcc_host *host)
-{
- int rc;
-
- del_timer_sync(&host->busclk_timer);
-
- if (!host->clks_on) {
- rc = clk_enable(host->pclk);
- if (rc)
- return rc;
- rc = clk_enable(host->clk);
- if (rc) {
- clk_disable(host->pclk);
- return rc;
- }
- udelay(1 + ((3 * USEC_PER_SEC) /
- (host->clk_rate ? host->clk_rate : msmsdcc_fmin)));
- host->clks_on = 1;
- }
- return 0;
-}
-
-static inline unsigned int
-msmsdcc_readl(struct msmsdcc_host *host, unsigned int reg)
-{
- return readl(host->base + reg);
-}
-
-static inline void
-msmsdcc_writel(struct msmsdcc_host *host, u32 data, unsigned int reg)
-{
- writel(data, host->base + reg);
- /* 3 clk delay required! */
- udelay(1 + ((3 * USEC_PER_SEC) /
- (host->clk_rate ? host->clk_rate : msmsdcc_fmin)));
-}
-
-static void
-msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
- u32 c);
-
-static void msmsdcc_reset_and_restore(struct msmsdcc_host *host)
-{
- u32 mci_clk = 0;
- u32 mci_mask0 = 0;
- int ret = 0;
-
- /* Save the controller state */
- mci_clk = readl(host->base + MMCICLOCK);
- mci_mask0 = readl(host->base + MMCIMASK0);
-
- /* Reset the controller */
- ret = clk_reset(host->clk, CLK_RESET_ASSERT);
- if (ret)
- pr_err("%s: Clock assert failed at %u Hz with err %d\n",
- mmc_hostname(host->mmc), host->clk_rate, ret);
-
- ret = clk_reset(host->clk, CLK_RESET_DEASSERT);
- if (ret)
- pr_err("%s: Clock deassert failed at %u Hz with err %d\n",
- mmc_hostname(host->mmc), host->clk_rate, ret);
-
- pr_info("%s: Controller has been re-initialiazed\n",
- mmc_hostname(host->mmc));
-
- /* Restore the contoller state */
- writel(host->pwr, host->base + MMCIPOWER);
- writel(mci_clk, host->base + MMCICLOCK);
- writel(mci_mask0, host->base + MMCIMASK0);
- ret = clk_set_rate(host->clk, host->clk_rate);
- if (ret)
- pr_err("%s: Failed to set clk rate %u Hz (%d)\n",
- mmc_hostname(host->mmc), host->clk_rate, ret);
-}
-
-static void
-msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
-{
- BUG_ON(host->curr.data);
-
- host->curr.mrq = NULL;
- host->curr.cmd = NULL;
-
- if (mrq->data)
- mrq->data->bytes_xfered = host->curr.data_xfered;
- if (mrq->cmd->error == -ETIMEDOUT)
- mdelay(5);
-
-#if BUSCLK_PWRSAVE
- msmsdcc_disable_clocks(host, 1);
-#endif
- /*
- * Need to drop the host lock here; mmc_request_done may call
- * back into the driver...
- */
- spin_unlock(&host->lock);
- mmc_request_done(host->mmc, mrq);
- spin_lock(&host->lock);
-}
-
-static void
-msmsdcc_stop_data(struct msmsdcc_host *host)
-{
- host->curr.data = NULL;
- host->curr.got_dataend = 0;
-}
-
-uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host)
-{
- return host->memres->start + MMCIFIFO;
-}
-
-static inline void
-msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c) {
- msmsdcc_writel(host, arg, MMCIARGUMENT);
- msmsdcc_writel(host, c, MMCICOMMAND);
-}
-
-static void
-msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd)
-{
- struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->data;
-
- msmsdcc_writel(host, host->cmd_timeout, MMCIDATATIMER);
- msmsdcc_writel(host, (unsigned int)host->curr.xfer_size,
- MMCIDATALENGTH);
- msmsdcc_writel(host, (msmsdcc_readl(host, MMCIMASK0) &
- (~MCI_IRQ_PIO)) | host->cmd_pio_irqmask, MMCIMASK0);
- msmsdcc_writel(host, host->cmd_datactrl, MMCIDATACTRL);
-
- if (host->cmd_cmd) {
- msmsdcc_start_command_exec(host,
- (u32) host->cmd_cmd->arg,
- (u32) host->cmd_c);
- }
- host->dma.active = 1;
-}
-
-static void
-msmsdcc_dma_complete_tlet(unsigned long data)
-{
- struct msmsdcc_host *host = (struct msmsdcc_host *)data;
- unsigned long flags;
- struct mmc_request *mrq;
- struct msm_dmov_errdata err;
-
- spin_lock_irqsave(&host->lock, flags);
- host->dma.active = 0;
-
- err = host->dma.err;
- mrq = host->curr.mrq;
- BUG_ON(!mrq);
- WARN_ON(!mrq->data);
-
- if (!(host->dma.result & DMOV_RSLT_VALID)) {
- pr_err("msmsdcc: Invalid DataMover result\n");
- goto out;
- }
-
- if (host->dma.result & DMOV_RSLT_DONE) {
- host->curr.data_xfered = host->curr.xfer_size;
- } else {
- /* Error or flush */
- if (host->dma.result & DMOV_RSLT_ERROR)
- pr_err("%s: DMA error (0x%.8x)\n",
- mmc_hostname(host->mmc), host->dma.result);
- if (host->dma.result & DMOV_RSLT_FLUSH)
- pr_err("%s: DMA channel flushed (0x%.8x)\n",
- mmc_hostname(host->mmc), host->dma.result);
-
- pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n",
- err.flush[0], err.flush[1], err.flush[2],
- err.flush[3], err.flush[4], err.flush[5]);
-
- msmsdcc_reset_and_restore(host);
- if (!mrq->data->error)
- mrq->data->error = -EIO;
- }
- dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents,
- host->dma.dir);
-
- host->dma.sg = NULL;
- host->dma.busy = 0;
-
- if (host->curr.got_dataend || mrq->data->error) {
-
- /*
- * If we've already gotten our DATAEND / DATABLKEND
- * for this request, then complete it through here.
- */
- msmsdcc_stop_data(host);
-
- if (!mrq->data->error)
- host->curr.data_xfered = host->curr.xfer_size;
- if (!mrq->data->stop || mrq->cmd->error) {
- host->curr.mrq = NULL;
- host->curr.cmd = NULL;
- mrq->data->bytes_xfered = host->curr.data_xfered;
-
- spin_unlock_irqrestore(&host->lock, flags);
-#if BUSCLK_PWRSAVE
- msmsdcc_disable_clocks(host, 1);
-#endif
- mmc_request_done(host->mmc, mrq);
- return;
- } else
- msmsdcc_start_command(host, mrq->data->stop, 0);
- }
-
-out:
- spin_unlock_irqrestore(&host->lock, flags);
- return;
-}
-
-static void
-msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd,
- unsigned int result,
- struct msm_dmov_errdata *err)
-{
- struct msmsdcc_dma_data *dma_data =
- container_of(cmd, struct msmsdcc_dma_data, hdr);
- struct msmsdcc_host *host = dma_data->host;
-
- dma_data->result = result;
- if (err)
- memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata));
-
- tasklet_schedule(&host->dma_tlet);
-}
-
-static int validate_dma(struct msmsdcc_host *host, struct mmc_data *data)
-{
- if (host->dma.channel == -1)
- return -ENOENT;
-
- if ((data->blksz * data->blocks) < MCI_FIFOSIZE)
- return -EINVAL;
- if ((data->blksz * data->blocks) % MCI_FIFOSIZE)
- return -EINVAL;
- return 0;
-}
-
-static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data)
-{
- struct msmsdcc_nc_dmadata *nc;
- dmov_box *box;
- uint32_t rows;
- uint32_t crci;
- unsigned int n;
- int i, rc;
- struct scatterlist *sg = data->sg;
-
- rc = validate_dma(host, data);
- if (rc)
- return rc;
-
- host->dma.sg = data->sg;
- host->dma.num_ents = data->sg_len;
-
- BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */
-
- nc = host->dma.nc;
-
- switch (host->pdev_id) {
- case 1:
- crci = MSMSDCC_CRCI_SDC1;
- break;
- case 2:
- crci = MSMSDCC_CRCI_SDC2;
- break;
- case 3:
- crci = MSMSDCC_CRCI_SDC3;
- break;
- case 4:
- crci = MSMSDCC_CRCI_SDC4;
- break;
- default:
- host->dma.sg = NULL;
- host->dma.num_ents = 0;
- return -ENOENT;
- }
-
- if (data->flags & MMC_DATA_READ)
- host->dma.dir = DMA_FROM_DEVICE;
- else
- host->dma.dir = DMA_TO_DEVICE;
-
- host->curr.user_pages = 0;
-
- box = &nc->cmd[0];
-
- /* location of command block must be 64 bit aligned */
- BUG_ON(host->dma.cmd_busaddr & 0x07);
-
- nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP;
- host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST |
- DMOV_CMD_ADDR(host->dma.cmdptr_busaddr);
- host->dma.hdr.complete_func = msmsdcc_dma_complete_func;
-
- n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg,
- host->dma.num_ents, host->dma.dir);
- if (n == 0) {
- pr_err("%s: Unable to map in all sg elements\n",
- mmc_hostname(host->mmc));
- host->dma.sg = NULL;
- host->dma.num_ents = 0;
- return -ENOMEM;
- }
-
- for_each_sg(host->dma.sg, sg, n, i) {
-
- box->cmd = CMD_MODE_BOX;
-
- if (i == n - 1)
- box->cmd |= CMD_LC;
- rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ?
- (sg_dma_len(sg) / MCI_FIFOSIZE) + 1 :
- (sg_dma_len(sg) / MCI_FIFOSIZE) ;
-
- if (data->flags & MMC_DATA_READ) {
- box->src_row_addr = msmsdcc_fifo_addr(host);
- box->dst_row_addr = sg_dma_address(sg);
-
- box->src_dst_len = (MCI_FIFOSIZE << 16) |
- (MCI_FIFOSIZE);
- box->row_offset = MCI_FIFOSIZE;
-
- box->num_rows = rows * ((1 << 16) + 1);
- box->cmd |= CMD_SRC_CRCI(crci);
- } else {
- box->src_row_addr = sg_dma_address(sg);
- box->dst_row_addr = msmsdcc_fifo_addr(host);
-
- box->src_dst_len = (MCI_FIFOSIZE << 16) |
- (MCI_FIFOSIZE);
- box->row_offset = (MCI_FIFOSIZE << 16);
-
- box->num_rows = rows * ((1 << 16) + 1);
- box->cmd |= CMD_DST_CRCI(crci);
- }
- box++;
- }
-
- return 0;
-}
-
-static int
-snoop_cccr_abort(struct mmc_command *cmd)
-{
- if ((cmd->opcode == 52) &&
- (cmd->arg & 0x80000000) &&
- (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT))
- return 1;
- return 0;
-}
-
-static void
-msmsdcc_start_command_deferred(struct msmsdcc_host *host,
- struct mmc_command *cmd, u32 *c)
-{
- *c |= (cmd->opcode | MCI_CPSM_ENABLE);
-
- if (cmd->flags & MMC_RSP_PRESENT) {
- if (cmd->flags & MMC_RSP_136)
- *c |= MCI_CPSM_LONGRSP;
- *c |= MCI_CPSM_RESPONSE;
- }
-
- if (/*interrupt*/0)
- *c |= MCI_CPSM_INTERRUPT;
-
- if ((((cmd->opcode == 17) || (cmd->opcode == 18)) ||
- ((cmd->opcode == 24) || (cmd->opcode == 25))) ||
- (cmd->opcode == 53))
- *c |= MCI_CSPM_DATCMD;
-
- if (host->prog_scan && (cmd->opcode == 12)) {
- *c |= MCI_CPSM_PROGENA;
- host->prog_enable = true;
- }
-
- if (cmd == cmd->mrq->stop)
- *c |= MCI_CSPM_MCIABORT;
-
- if (snoop_cccr_abort(cmd))
- *c |= MCI_CSPM_MCIABORT;
-
- if (host->curr.cmd != NULL) {
- pr_err("%s: Overlapping command requests\n",
- mmc_hostname(host->mmc));
- }
- host->curr.cmd = cmd;
-}
-
-static void
-msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data,
- struct mmc_command *cmd, u32 c)
-{
- unsigned int datactrl, timeout;
- unsigned long long clks;
- unsigned int pio_irqmask = 0;
-
- host->curr.data = data;
- host->curr.xfer_size = data->blksz * data->blocks;
- host->curr.xfer_remain = host->curr.xfer_size;
- host->curr.data_xfered = 0;
- host->curr.got_dataend = 0;
-
- memset(&host->pio, 0, sizeof(host->pio));
-
- datactrl = MCI_DPSM_ENABLE | (data->blksz << 4);
-
- if (!msmsdcc_config_dma(host, data))
- datactrl |= MCI_DPSM_DMAENABLE;
- else {
- host->pio.sg = data->sg;
- host->pio.sg_len = data->sg_len;
- host->pio.sg_off = 0;
-
- if (data->flags & MMC_DATA_READ) {
- pio_irqmask = MCI_RXFIFOHALFFULLMASK;
- if (host->curr.xfer_remain < MCI_FIFOSIZE)
- pio_irqmask |= MCI_RXDATAAVLBLMASK;
- } else
- pio_irqmask = MCI_TXFIFOHALFEMPTYMASK;
- }
-
- if (data->flags & MMC_DATA_READ)
- datactrl |= MCI_DPSM_DIRECTION;
-
- clks = (unsigned long long)data->timeout_ns * host->clk_rate;
- do_div(clks, NSEC_PER_SEC);
- timeout = data->timeout_clks + (unsigned int)clks*2 ;
-
- if (datactrl & MCI_DPSM_DMAENABLE) {
- /* Save parameters for the exec function */
- host->cmd_timeout = timeout;
- host->cmd_pio_irqmask = pio_irqmask;
- host->cmd_datactrl = datactrl;
- host->cmd_cmd = cmd;
-
- host->dma.hdr.execute_func = msmsdcc_dma_exec_func;
- host->dma.hdr.data = (void *)host;
- host->dma.busy = 1;
-
- if (cmd) {
- msmsdcc_start_command_deferred(host, cmd, &c);
- host->cmd_c = c;
- }
- msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr);
- if (data->flags & MMC_DATA_WRITE)
- host->prog_scan = true;
- } else {
- msmsdcc_writel(host, timeout, MMCIDATATIMER);
-
- msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH);
-
- msmsdcc_writel(host, (msmsdcc_readl(host, MMCIMASK0) &
- (~MCI_IRQ_PIO)) | pio_irqmask, MMCIMASK0);
-
- msmsdcc_writel(host, datactrl, MMCIDATACTRL);
-
- if (cmd) {
- /* Daisy-chain the command if requested */
- msmsdcc_start_command(host, cmd, c);
- }
- }
-}
-
-static void
-msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c)
-{
- if (cmd == cmd->mrq->stop)
- c |= MCI_CSPM_MCIABORT;
-
- host->stats.cmds++;
-
- msmsdcc_start_command_deferred(host, cmd, &c);
- msmsdcc_start_command_exec(host, cmd->arg, c);
-}
-
-static void
-msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data,
- unsigned int status)
-{
- if (status & MCI_DATACRCFAIL) {
- pr_err("%s: Data CRC error\n", mmc_hostname(host->mmc));
- pr_err("%s: opcode 0x%.8x\n", __func__,
- data->mrq->cmd->opcode);
- pr_err("%s: blksz %d, blocks %d\n", __func__,
- data->blksz, data->blocks);
- data->error = -EILSEQ;
- } else if (status & MCI_DATATIMEOUT) {
- pr_err("%s: Data timeout\n", mmc_hostname(host->mmc));
- data->error = -ETIMEDOUT;
- } else if (status & MCI_RXOVERRUN) {
- pr_err("%s: RX overrun\n", mmc_hostname(host->mmc));
- data->error = -EIO;
- } else if (status & MCI_TXUNDERRUN) {
- pr_err("%s: TX underrun\n", mmc_hostname(host->mmc));
- data->error = -EIO;
- } else {
- pr_err("%s: Unknown error (0x%.8x)\n",
- mmc_hostname(host->mmc), status);
- data->error = -EIO;
- }
-}
-
-
-static int
-msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain)
-{
- uint32_t *ptr = (uint32_t *) buffer;
- int count = 0;
-
- if (remain % 4)
- remain = ((remain >> 2) + 1) << 2;
-
- while (msmsdcc_readl(host, MMCISTATUS) & MCI_RXDATAAVLBL) {
- *ptr = msmsdcc_readl(host, MMCIFIFO + (count % MCI_FIFOSIZE));
- ptr++;
- count += sizeof(uint32_t);
-
- remain -= sizeof(uint32_t);
- if (remain == 0)
- break;
- }
- return count;
-}
-
-static int
-msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer,
- unsigned int remain, u32 status)
-{
- void __iomem *base = host->base;
- char *ptr = buffer;
-
- do {
- unsigned int count, maxcnt, sz;
-
- maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE :
- MCI_FIFOHALFSIZE;
- count = min(remain, maxcnt);
-
- sz = count % 4 ? (count >> 2) + 1 : (count >> 2);
- writesl(base + MMCIFIFO, ptr, sz);
- ptr += count;
- remain -= count;
-
- if (remain == 0)
- break;
-
- status = msmsdcc_readl(host, MMCISTATUS);
- } while (status & MCI_TXFIFOHALFEMPTY);
-
- return ptr - buffer;
-}
-
-static int
-msmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin)
-{
- while (maxspin) {
- if ((msmsdcc_readl(host, MMCISTATUS) & mask))
- return 0;
- udelay(1);
- --maxspin;
- }
- return -ETIMEDOUT;
-}
-
-static irqreturn_t
-msmsdcc_pio_irq(int irq, void *dev_id)
-{
- struct msmsdcc_host *host = dev_id;
- uint32_t status;
- u32 mci_mask0;
-
- status = msmsdcc_readl(host, MMCISTATUS);
- mci_mask0 = msmsdcc_readl(host, MMCIMASK0);
-
- if (((mci_mask0 & status) & MCI_IRQ_PIO) == 0)
- return IRQ_NONE;
-
- do {
- unsigned long flags;
- unsigned int remain, len;
- char *buffer;
-
- if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_RXDATAAVLBL))) {
- if (host->curr.xfer_remain == 0 || !msmsdcc_piopoll)
- break;
-
- if (msmsdcc_spin_on_status(host,
- (MCI_TXFIFOHALFEMPTY |
- MCI_RXDATAAVLBL),
- PIO_SPINMAX)) {
- break;
- }
- }
-
- /* Map the current scatter buffer */
- local_irq_save(flags);
- buffer = kmap_atomic(sg_page(host->pio.sg))
- + host->pio.sg->offset;
- buffer += host->pio.sg_off;
- remain = host->pio.sg->length - host->pio.sg_off;
- len = 0;
- if (status & MCI_RXACTIVE)
- len = msmsdcc_pio_read(host, buffer, remain);
- if (status & MCI_TXACTIVE)
- len = msmsdcc_pio_write(host, buffer, remain, status);
-
- /* Unmap the buffer */
- kunmap_atomic(buffer);
- local_irq_restore(flags);
-
- host->pio.sg_off += len;
- host->curr.xfer_remain -= len;
- host->curr.data_xfered += len;
- remain -= len;
-
- if (remain == 0) {
- /* This sg page is full - do some housekeeping */
- if (status & MCI_RXACTIVE && host->curr.user_pages)
- flush_dcache_page(sg_page(host->pio.sg));
-
- if (!--host->pio.sg_len) {
- memset(&host->pio, 0, sizeof(host->pio));
- break;
- }
-
- /* Advance to next sg */
- host->pio.sg++;
- host->pio.sg_off = 0;
- }
-
- status = msmsdcc_readl(host, MMCISTATUS);
- } while (1);
-
- if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE)
- msmsdcc_writel(host, (mci_mask0 & (~MCI_IRQ_PIO)) |
- MCI_RXDATAAVLBLMASK, MMCIMASK0);
-
- if (!host->curr.xfer_remain)
- msmsdcc_writel(host, (mci_mask0 & (~MCI_IRQ_PIO)) | 0,
- MMCIMASK0);
-
- return IRQ_HANDLED;
-}
-
-static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status)
-{
- struct mmc_command *cmd = host->curr.cmd;
-
- host->curr.cmd = NULL;
- cmd->resp[0] = msmsdcc_readl(host, MMCIRESPONSE0);
- cmd->resp[1] = msmsdcc_readl(host, MMCIRESPONSE1);
- cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2);
- cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3);
-
- if (status & MCI_CMDTIMEOUT) {
- cmd->error = -ETIMEDOUT;
- } else if (status & MCI_CMDCRCFAIL &&
- cmd->flags & MMC_RSP_CRC) {
- pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc));
- cmd->error = -EILSEQ;
- }
-
- if (!cmd->data || cmd->error) {
- if (host->curr.data && host->dma.sg)
- msm_dmov_stop_cmd(host->dma.channel,
- &host->dma.hdr, 0);
- else if (host->curr.data) { /* Non DMA */
- msmsdcc_reset_and_restore(host);
- msmsdcc_stop_data(host);
- msmsdcc_request_end(host, cmd->mrq);
- } else { /* host->data == NULL */
- if (!cmd->error && host->prog_enable) {
- if (status & MCI_PROGDONE) {
- host->prog_scan = false;
- host->prog_enable = false;
- msmsdcc_request_end(host, cmd->mrq);
- } else {
- host->curr.cmd = cmd;
- }
- } else {
- if (host->prog_enable) {
- host->prog_scan = false;
- host->prog_enable = false;
- }
- msmsdcc_request_end(host, cmd->mrq);
- }
- }
- } else if (cmd->data)
- if (!(cmd->data->flags & MMC_DATA_READ))
- msmsdcc_start_data(host, cmd->data,
- NULL, 0);
-}
-
-static void
-msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status,
- void __iomem *base)
-{
- struct mmc_data *data = host->curr.data;
-
- if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
- MCI_CMDTIMEOUT | MCI_PROGDONE) && host->curr.cmd) {
- msmsdcc_do_cmdirq(host, status);
- }
-
- if (!data)
- return;
-
- /* Check for data errors */
- if (status & (MCI_DATACRCFAIL | MCI_DATATIMEOUT |
- MCI_TXUNDERRUN | MCI_RXOVERRUN)) {
- msmsdcc_data_err(host, data, status);
- host->curr.data_xfered = 0;
- if (host->dma.sg)
- msm_dmov_stop_cmd(host->dma.channel,
- &host->dma.hdr, 0);
- else {
- msmsdcc_reset_and_restore(host);
- if (host->curr.data)
- msmsdcc_stop_data(host);
- if (!data->stop)
- msmsdcc_request_end(host, data->mrq);
- else
- msmsdcc_start_command(host, data->stop, 0);
- }
- }
-
- /* Check for data done */
- if (!host->curr.got_dataend && (status & MCI_DATAEND))
- host->curr.got_dataend = 1;
-
- /*
- * If DMA is still in progress, we complete via the completion handler
- */
- if (host->curr.got_dataend && !host->dma.busy) {
- /*
- * There appears to be an issue in the controller where
- * if you request a small block transfer (< fifo size),
- * you may get your DATAEND/DATABLKEND irq without the
- * PIO data irq.
- *
- * Check to see if there is still data to be read,
- * and simulate a PIO irq.
- */
- if (readl(base + MMCISTATUS) & MCI_RXDATAAVLBL)
- msmsdcc_pio_irq(1, host);
-
- msmsdcc_stop_data(host);
- if (!data->error)
- host->curr.data_xfered = host->curr.xfer_size;
-
- if (!data->stop)
- msmsdcc_request_end(host, data->mrq);
- else
- msmsdcc_start_command(host, data->stop, 0);
- }
-}
-
-static irqreturn_t
-msmsdcc_irq(int irq, void *dev_id)
-{
- struct msmsdcc_host *host = dev_id;
- void __iomem *base = host->base;
- u32 status;
- int ret = 0;
- int cardint = 0;
-
- spin_lock(&host->lock);
-
- do {
- status = msmsdcc_readl(host, MMCISTATUS);
- status &= msmsdcc_readl(host, MMCIMASK0);
- if ((status & (~MCI_IRQ_PIO)) == 0)
- break;
- msmsdcc_writel(host, status, MMCICLEAR);
-
- if (status & MCI_SDIOINTR)
- status &= ~MCI_SDIOINTR;
-
- if (!status)
- break;
-
- msmsdcc_handle_irq_data(host, status, base);
-
- if (status & MCI_SDIOINTOPER) {
- cardint = 1;
- status &= ~MCI_SDIOINTOPER;
- }
- ret = 1;
- } while (status);
-
- spin_unlock(&host->lock);
-
- /*
- * We have to delay handling the card interrupt as it calls
- * back into the driver.
- */
- if (cardint)
- mmc_signal_sdio_irq(host->mmc);
-
- return IRQ_RETVAL(ret);
-}
-
-static void
-msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct msmsdcc_host *host = mmc_priv(mmc);
- unsigned long flags;
-
- WARN_ON(host->curr.mrq != NULL);
- WARN_ON(host->pwr == 0);
-
- spin_lock_irqsave(&host->lock, flags);
-
- host->stats.reqs++;
-
- if (host->eject) {
- if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) {
- mrq->cmd->error = 0;
- mrq->data->bytes_xfered = mrq->data->blksz *
- mrq->data->blocks;
- } else
- mrq->cmd->error = -ENOMEDIUM;
-
- spin_unlock_irqrestore(&host->lock, flags);
- mmc_request_done(mmc, mrq);
- return;
- }
-
- msmsdcc_enable_clocks(host);
-
- host->curr.mrq = mrq;
-
- if (mrq->data && mrq->data->flags & MMC_DATA_READ)
- /* Queue/read data, daisy-chain command when data starts */
- msmsdcc_start_data(host, mrq->data, mrq->cmd, 0);
- else
- msmsdcc_start_command(host, mrq->cmd, 0);
-
- if (host->cmdpoll && !msmsdcc_spin_on_status(host,
- MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT,
- CMD_SPINMAX)) {
- uint32_t status = msmsdcc_readl(host, MMCISTATUS);
- msmsdcc_do_cmdirq(host, status);
- msmsdcc_writel(host,
- MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT,
- MMCICLEAR);
- host->stats.cmdpoll_hits++;
- } else {
- host->stats.cmdpoll_misses++;
- }
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable)
-{
- struct msm_mmc_gpio_data *curr;
- int i, rc = 0;
-
- if (!host->plat->gpio_data || host->gpio_config_status == enable)
- return;
-
- curr = host->plat->gpio_data;
- for (i = 0; i < curr->size; i++) {
- if (enable) {
- rc = gpio_request(curr->gpio[i].no,
- curr->gpio[i].name);
- if (rc) {
- pr_err("%s: gpio_request(%d, %s) failed %d\n",
- mmc_hostname(host->mmc),
- curr->gpio[i].no,
- curr->gpio[i].name, rc);
- goto free_gpios;
- }
- } else {
- gpio_free(curr->gpio[i].no);
- }
- }
- host->gpio_config_status = enable;
- return;
-
-free_gpios:
- for (; i >= 0; i--)
- gpio_free(curr->gpio[i].no);
-}
-
-static void
-msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct msmsdcc_host *host = mmc_priv(mmc);
- u32 clk = 0, pwr = 0;
- int rc;
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
-
- msmsdcc_enable_clocks(host);
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- if (ios->clock) {
- if (ios->clock != host->clk_rate) {
- rc = clk_set_rate(host->clk, ios->clock);
- if (rc < 0)
- pr_err("%s: Error setting clock rate (%d)\n",
- mmc_hostname(host->mmc), rc);
- else
- host->clk_rate = ios->clock;
- }
- clk |= MCI_CLK_ENABLE;
- }
-
- if (ios->bus_width == MMC_BUS_WIDTH_4)
- clk |= (2 << 10); /* Set WIDEBUS */
-
- if (ios->clock > 400000 && msmsdcc_pwrsave)
- clk |= (1 << 9); /* PWRSAVE */
-
- clk |= (1 << 12); /* FLOW_ENA */
- clk |= (1 << 15); /* feedback clock */
-
- if (host->plat->translate_vdd)
- pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
-
- switch (ios->power_mode) {
- case MMC_POWER_OFF:
- msmsdcc_setup_gpio(host, false);
- break;
- case MMC_POWER_UP:
- pwr |= MCI_PWR_UP;
- msmsdcc_setup_gpio(host, true);
- break;
- case MMC_POWER_ON:
- pwr |= MCI_PWR_ON;
- break;
- }
-
- if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
- pwr |= MCI_OD;
-
- msmsdcc_writel(host, clk, MMCICLOCK);
-
- if (host->pwr != pwr) {
- host->pwr = pwr;
- msmsdcc_writel(host, pwr, MMCIPOWER);
- }
-#if BUSCLK_PWRSAVE
- spin_lock_irqsave(&host->lock, flags);
- msmsdcc_disable_clocks(host, 1);
- spin_unlock_irqrestore(&host->lock, flags);
-#endif
-}
-
-static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
- struct msmsdcc_host *host = mmc_priv(mmc);
- unsigned long flags;
- u32 status;
-
- spin_lock_irqsave(&host->lock, flags);
- if (msmsdcc_sdioirq == 1) {
- status = msmsdcc_readl(host, MMCIMASK0);
- if (enable)
- status |= MCI_SDIOINTOPERMASK;
- else
- status &= ~MCI_SDIOINTOPERMASK;
- host->saved_irq0mask = status;
- msmsdcc_writel(host, status, MMCIMASK0);
- }
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void msmsdcc_init_card(struct mmc_host *mmc, struct mmc_card *card)
-{
- struct msmsdcc_host *host = mmc_priv(mmc);
-
- if (host->plat->init_card)
- host->plat->init_card(card);
-}
-
-static const struct mmc_host_ops msmsdcc_ops = {
- .request = msmsdcc_request,
- .set_ios = msmsdcc_set_ios,
- .enable_sdio_irq = msmsdcc_enable_sdio_irq,
- .init_card = msmsdcc_init_card,
-};
-
-static void
-msmsdcc_check_status(unsigned long data)
-{
- struct msmsdcc_host *host = (struct msmsdcc_host *)data;
- unsigned int status;
-
- if (!host->plat->status) {
- mmc_detect_change(host->mmc, 0);
- goto out;
- }
-
- status = host->plat->status(mmc_dev(host->mmc));
- host->eject = !status;
- if (status ^ host->oldstat) {
- pr_info("%s: Slot status change detected (%d -> %d)\n",
- mmc_hostname(host->mmc), host->oldstat, status);
- if (status)
- mmc_detect_change(host->mmc, (5 * HZ) / 2);
- else
- mmc_detect_change(host->mmc, 0);
- }
-
- host->oldstat = status;
-
-out:
- if (host->timer.function)
- mod_timer(&host->timer, jiffies + HZ);
-}
-
-static irqreturn_t
-msmsdcc_platform_status_irq(int irq, void *dev_id)
-{
- struct msmsdcc_host *host = dev_id;
-
- pr_debug("%s: %d\n", __func__, irq);
- msmsdcc_check_status((unsigned long) host);
- return IRQ_HANDLED;
-}
-
-static void
-msmsdcc_status_notify_cb(int card_present, void *dev_id)
-{
- struct msmsdcc_host *host = dev_id;
-
- pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc),
- card_present);
- msmsdcc_check_status((unsigned long) host);
-}
-
-static void
-msmsdcc_busclk_expired(unsigned long _data)
-{
- struct msmsdcc_host *host = (struct msmsdcc_host *) _data;
-
- if (host->clks_on)
- msmsdcc_disable_clocks(host, 0);
-}
-
-static int
-msmsdcc_init_dma(struct msmsdcc_host *host)
-{
- memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data));
- host->dma.host = host;
- host->dma.channel = -1;
-
- if (!host->dmares)
- return -ENODEV;
-
- host->dma.nc = dma_alloc_coherent(NULL,
- sizeof(struct msmsdcc_nc_dmadata),
- &host->dma.nc_busaddr,
- GFP_KERNEL);
- if (host->dma.nc == NULL) {
- pr_err("Unable to allocate DMA buffer\n");
- return -ENOMEM;
- }
- memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata));
- host->dma.cmd_busaddr = host->dma.nc_busaddr;
- host->dma.cmdptr_busaddr = host->dma.nc_busaddr +
- offsetof(struct msmsdcc_nc_dmadata, cmdptr);
- host->dma.channel = host->dmares->start;
-
- return 0;
-}
-
-static int
-msmsdcc_probe(struct platform_device *pdev)
-{
- struct msm_mmc_platform_data *plat = pdev->dev.platform_data;
- struct msmsdcc_host *host;
- struct mmc_host *mmc;
- struct resource *cmd_irqres = NULL;
- struct resource *stat_irqres = NULL;
- struct resource *memres = NULL;
- struct resource *dmares = NULL;
- int ret;
-
- /* must have platform data */
- if (!plat) {
- pr_err("%s: Platform data not available\n", __func__);
- ret = -EINVAL;
- goto out;
- }
-
- if (pdev->id < 1 || pdev->id > 4)
- return -EINVAL;
-
- if (pdev->resource == NULL || pdev->num_resources < 2) {
- pr_err("%s: Invalid resource\n", __func__);
- return -ENXIO;
- }
-
- memres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- cmd_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
- "cmd_irq");
- stat_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
- "status_irq");
-
- if (!cmd_irqres || !memres) {
- pr_err("%s: Invalid resource\n", __func__);
- return -ENXIO;
- }
-
- /*
- * Setup our host structure
- */
-
- mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev);
- if (!mmc) {
- ret = -ENOMEM;
- goto out;
- }
-
- host = mmc_priv(mmc);
- host->pdev_id = pdev->id;
- host->plat = plat;
- host->mmc = mmc;
- host->curr.cmd = NULL;
- init_timer(&host->busclk_timer);
- host->busclk_timer.data = (unsigned long) host;
- host->busclk_timer.function = msmsdcc_busclk_expired;
-
-
- host->cmdpoll = 1;
-
- host->base = ioremap(memres->start, PAGE_SIZE);
- if (!host->base) {
- ret = -ENOMEM;
- goto host_free;
- }
-
- host->cmd_irqres = cmd_irqres;
- host->memres = memres;
- host->dmares = dmares;
- spin_lock_init(&host->lock);
-
- tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet,
- (unsigned long)host);
-
- /*
- * Setup DMA
- */
- if (host->dmares) {
- ret = msmsdcc_init_dma(host);
- if (ret)
- goto ioremap_free;
- } else {
- host->dma.channel = -1;
- }
-
- /* Get our clocks */
- host->pclk = clk_get(&pdev->dev, "sdc_pclk");
- if (IS_ERR(host->pclk)) {
- ret = PTR_ERR(host->pclk);
- goto dma_free;
- }
-
- host->clk = clk_get(&pdev->dev, "sdc_clk");
- if (IS_ERR(host->clk)) {
- ret = PTR_ERR(host->clk);
- goto pclk_put;
- }
-
- ret = clk_set_rate(host->clk, msmsdcc_fmin);
- if (ret) {
- pr_err("%s: Clock rate set failed (%d)\n", __func__, ret);
- goto clk_put;
- }
-
- /* Enable clocks */
- ret = msmsdcc_enable_clocks(host);
- if (ret)
- goto clk_put;
-
- host->pclk_rate = clk_get_rate(host->pclk);
- host->clk_rate = clk_get_rate(host->clk);
-
- /*
- * Setup MMC host structure
- */
- mmc->ops = &msmsdcc_ops;
- mmc->f_min = msmsdcc_fmin;
- mmc->f_max = msmsdcc_fmax;
- mmc->ocr_avail = plat->ocr_mask;
-
- if (msmsdcc_4bit)
- mmc->caps |= MMC_CAP_4_BIT_DATA;
- if (msmsdcc_sdioirq)
- mmc->caps |= MMC_CAP_SDIO_IRQ;
- mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
-
- mmc->max_segs = NR_SG;
- mmc->max_blk_size = 4096; /* MCI_DATA_CTL BLOCKSIZE up to 4096 */
- mmc->max_blk_count = 65536;
-
- mmc->max_req_size = 33554432; /* MCI_DATA_LENGTH is 25 bits */
- mmc->max_seg_size = mmc->max_req_size;
-
- msmsdcc_writel(host, 0, MMCIMASK0);
- msmsdcc_writel(host, 0x5e007ff, MMCICLEAR);
-
- msmsdcc_writel(host, MCI_IRQENABLE, MMCIMASK0);
- host->saved_irq0mask = MCI_IRQENABLE;
-
- /*
- * Setup card detect change
- */
-
- memset(&host->timer, 0, sizeof(host->timer));
-
- if (stat_irqres && !(stat_irqres->flags & IORESOURCE_DISABLED)) {
- unsigned long irqflags = IRQF_SHARED |
- (stat_irqres->flags & IRQF_TRIGGER_MASK);
-
- host->stat_irq = stat_irqres->start;
- ret = request_irq(host->stat_irq,
- msmsdcc_platform_status_irq,
- irqflags,
- DRIVER_NAME " (slot)",
- host);
- if (ret) {
- pr_err("%s: Unable to get slot IRQ %d (%d)\n",
- mmc_hostname(mmc), host->stat_irq, ret);
- goto clk_disable;
- }
- } else if (plat->register_status_notify) {
- plat->register_status_notify(msmsdcc_status_notify_cb, host);
- } else if (!plat->status)
- pr_err("%s: No card detect facilities available\n",
- mmc_hostname(mmc));
- else {
- init_timer(&host->timer);
- host->timer.data = (unsigned long)host;
- host->timer.function = msmsdcc_check_status;
- host->timer.expires = jiffies + HZ;
- add_timer(&host->timer);
- }
-
- if (plat->status) {
- host->oldstat = host->plat->status(mmc_dev(host->mmc));
- host->eject = !host->oldstat;
- }
-
- ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED,
- DRIVER_NAME " (cmd)", host);
- if (ret)
- goto stat_irq_free;
-
- ret = request_irq(cmd_irqres->start, msmsdcc_pio_irq, IRQF_SHARED,
- DRIVER_NAME " (pio)", host);
- if (ret)
- goto cmd_irq_free;
-
- mmc_set_drvdata(pdev, mmc);
- mmc_add_host(mmc);
-
- pr_info("%s: Qualcomm MSM SDCC at 0x%016llx irq %d,%d dma %d\n",
- mmc_hostname(mmc), (unsigned long long)memres->start,
- (unsigned int) cmd_irqres->start,
- (unsigned int) host->stat_irq, host->dma.channel);
- pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc),
- (mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled"));
- pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n",
- mmc_hostname(mmc), msmsdcc_fmin, msmsdcc_fmax, host->pclk_rate);
- pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc), host->eject);
- pr_info("%s: Power save feature enable = %d\n",
- mmc_hostname(mmc), msmsdcc_pwrsave);
-
- if (host->dma.channel != -1) {
- pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n",
- mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr);
- pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n",
- mmc_hostname(mmc), host->dma.cmd_busaddr,
- host->dma.cmdptr_busaddr);
- } else
- pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc));
- if (host->timer.function)
- pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc));
-
- return 0;
- cmd_irq_free:
- free_irq(cmd_irqres->start, host);
- stat_irq_free:
- if (host->stat_irq)
- free_irq(host->stat_irq, host);
- clk_disable:
- msmsdcc_disable_clocks(host, 0);
- clk_put:
- clk_put(host->clk);
- pclk_put:
- clk_put(host->pclk);
-dma_free:
- if (host->dmares)
- dma_free_coherent(NULL, sizeof(struct msmsdcc_nc_dmadata),
- host->dma.nc, host->dma.nc_busaddr);
-ioremap_free:
- tasklet_kill(&host->dma_tlet);
- iounmap(host->base);
- host_free:
- mmc_free_host(mmc);
- out:
- return ret;
-}
-
-#ifdef CONFIG_PM
-#ifdef CONFIG_MMC_MSM7X00A_RESUME_IN_WQ
-static void
-do_resume_work(struct work_struct *work)
-{
- struct msmsdcc_host *host =
- container_of(work, struct msmsdcc_host, resume_task);
- struct mmc_host *mmc = host->mmc;
-
- if (mmc) {
- mmc_resume_host(mmc);
- if (host->stat_irq)
- enable_irq(host->stat_irq);
- }
-}
-#endif
-
-
-static int
-msmsdcc_suspend(struct platform_device *dev, pm_message_t state)
-{
- struct mmc_host *mmc = mmc_get_drvdata(dev);
- int rc = 0;
-
- if (mmc) {
- struct msmsdcc_host *host = mmc_priv(mmc);
-
- if (host->stat_irq)
- disable_irq(host->stat_irq);
-
- if (mmc->card && mmc->card->type != MMC_TYPE_SDIO)
- rc = mmc_suspend_host(mmc);
- if (!rc)
- msmsdcc_writel(host, 0, MMCIMASK0);
- if (host->clks_on)
- msmsdcc_disable_clocks(host, 0);
- }
- return rc;
-}
-
-static int
-msmsdcc_resume(struct platform_device *dev)
-{
- struct mmc_host *mmc = mmc_get_drvdata(dev);
-
- if (mmc) {
- struct msmsdcc_host *host = mmc_priv(mmc);
-
- msmsdcc_enable_clocks(host);
-
- msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0);
-
- if (mmc->card && mmc->card->type != MMC_TYPE_SDIO)
- mmc_resume_host(mmc);
- if (host->stat_irq)
- enable_irq(host->stat_irq);
-#if BUSCLK_PWRSAVE
- msmsdcc_disable_clocks(host, 1);
-#endif
- }
- return 0;
-}
-#else
-#define msmsdcc_suspend 0
-#define msmsdcc_resume 0
-#endif
-
-static struct platform_driver msmsdcc_driver = {
- .probe = msmsdcc_probe,
- .suspend = msmsdcc_suspend,
- .resume = msmsdcc_resume,
- .driver = {
- .name = "msm_sdcc",
- },
-};
-
-module_platform_driver(msmsdcc_driver);
-
-MODULE_DESCRIPTION("Qualcomm MSM 7X00A Multimedia Card Interface driver");
-MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/msm_sdcc.h b/ANDROID_3.4.5/drivers/mmc/host/msm_sdcc.h
deleted file mode 100644
index 402028d1..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/msm_sdcc.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * linux/drivers/mmc/host/msmsdcc.h - QCT MSM7K SDC Controller
- *
- * Copyright (C) 2008 Google, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * - Based on mmci.h
- */
-
-#ifndef _MSM_SDCC_H
-#define _MSM_SDCC_H
-
-#define MSMSDCC_CRCI_SDC1 6
-#define MSMSDCC_CRCI_SDC2 7
-#define MSMSDCC_CRCI_SDC3 12
-#define MSMSDCC_CRCI_SDC4 13
-
-#define MMCIPOWER 0x000
-#define MCI_PWR_OFF 0x00
-#define MCI_PWR_UP 0x02
-#define MCI_PWR_ON 0x03
-#define MCI_OD (1 << 6)
-
-#define MMCICLOCK 0x004
-#define MCI_CLK_ENABLE (1 << 8)
-#define MCI_CLK_PWRSAVE (1 << 9)
-#define MCI_CLK_WIDEBUS (1 << 10)
-#define MCI_CLK_FLOWENA (1 << 12)
-#define MCI_CLK_INVERTOUT (1 << 13)
-#define MCI_CLK_SELECTIN (1 << 14)
-
-#define MMCIARGUMENT 0x008
-#define MMCICOMMAND 0x00c
-#define MCI_CPSM_RESPONSE (1 << 6)
-#define MCI_CPSM_LONGRSP (1 << 7)
-#define MCI_CPSM_INTERRUPT (1 << 8)
-#define MCI_CPSM_PENDING (1 << 9)
-#define MCI_CPSM_ENABLE (1 << 10)
-#define MCI_CPSM_PROGENA (1 << 11)
-#define MCI_CSPM_DATCMD (1 << 12)
-#define MCI_CSPM_MCIABORT (1 << 13)
-#define MCI_CSPM_CCSENABLE (1 << 14)
-#define MCI_CSPM_CCSDISABLE (1 << 15)
-
-
-#define MMCIRESPCMD 0x010
-#define MMCIRESPONSE0 0x014
-#define MMCIRESPONSE1 0x018
-#define MMCIRESPONSE2 0x01c
-#define MMCIRESPONSE3 0x020
-#define MMCIDATATIMER 0x024
-#define MMCIDATALENGTH 0x028
-
-#define MMCIDATACTRL 0x02c
-#define MCI_DPSM_ENABLE (1 << 0)
-#define MCI_DPSM_DIRECTION (1 << 1)
-#define MCI_DPSM_MODE (1 << 2)
-#define MCI_DPSM_DMAENABLE (1 << 3)
-
-#define MMCIDATACNT 0x030
-#define MMCISTATUS 0x034
-#define MCI_CMDCRCFAIL (1 << 0)
-#define MCI_DATACRCFAIL (1 << 1)
-#define MCI_CMDTIMEOUT (1 << 2)
-#define MCI_DATATIMEOUT (1 << 3)
-#define MCI_TXUNDERRUN (1 << 4)
-#define MCI_RXOVERRUN (1 << 5)
-#define MCI_CMDRESPEND (1 << 6)
-#define MCI_CMDSENT (1 << 7)
-#define MCI_DATAEND (1 << 8)
-#define MCI_DATABLOCKEND (1 << 10)
-#define MCI_CMDACTIVE (1 << 11)
-#define MCI_TXACTIVE (1 << 12)
-#define MCI_RXACTIVE (1 << 13)
-#define MCI_TXFIFOHALFEMPTY (1 << 14)
-#define MCI_RXFIFOHALFFULL (1 << 15)
-#define MCI_TXFIFOFULL (1 << 16)
-#define MCI_RXFIFOFULL (1 << 17)
-#define MCI_TXFIFOEMPTY (1 << 18)
-#define MCI_RXFIFOEMPTY (1 << 19)
-#define MCI_TXDATAAVLBL (1 << 20)
-#define MCI_RXDATAAVLBL (1 << 21)
-#define MCI_SDIOINTR (1 << 22)
-#define MCI_PROGDONE (1 << 23)
-#define MCI_ATACMDCOMPL (1 << 24)
-#define MCI_SDIOINTOPER (1 << 25)
-#define MCI_CCSTIMEOUT (1 << 26)
-
-#define MMCICLEAR 0x038
-#define MCI_CMDCRCFAILCLR (1 << 0)
-#define MCI_DATACRCFAILCLR (1 << 1)
-#define MCI_CMDTIMEOUTCLR (1 << 2)
-#define MCI_DATATIMEOUTCLR (1 << 3)
-#define MCI_TXUNDERRUNCLR (1 << 4)
-#define MCI_RXOVERRUNCLR (1 << 5)
-#define MCI_CMDRESPENDCLR (1 << 6)
-#define MCI_CMDSENTCLR (1 << 7)
-#define MCI_DATAENDCLR (1 << 8)
-#define MCI_DATABLOCKENDCLR (1 << 10)
-
-#define MMCIMASK0 0x03c
-#define MCI_CMDCRCFAILMASK (1 << 0)
-#define MCI_DATACRCFAILMASK (1 << 1)
-#define MCI_CMDTIMEOUTMASK (1 << 2)
-#define MCI_DATATIMEOUTMASK (1 << 3)
-#define MCI_TXUNDERRUNMASK (1 << 4)
-#define MCI_RXOVERRUNMASK (1 << 5)
-#define MCI_CMDRESPENDMASK (1 << 6)
-#define MCI_CMDSENTMASK (1 << 7)
-#define MCI_DATAENDMASK (1 << 8)
-#define MCI_DATABLOCKENDMASK (1 << 10)
-#define MCI_CMDACTIVEMASK (1 << 11)
-#define MCI_TXACTIVEMASK (1 << 12)
-#define MCI_RXACTIVEMASK (1 << 13)
-#define MCI_TXFIFOHALFEMPTYMASK (1 << 14)
-#define MCI_RXFIFOHALFFULLMASK (1 << 15)
-#define MCI_TXFIFOFULLMASK (1 << 16)
-#define MCI_RXFIFOFULLMASK (1 << 17)
-#define MCI_TXFIFOEMPTYMASK (1 << 18)
-#define MCI_RXFIFOEMPTYMASK (1 << 19)
-#define MCI_TXDATAAVLBLMASK (1 << 20)
-#define MCI_RXDATAAVLBLMASK (1 << 21)
-#define MCI_SDIOINTMASK (1 << 22)
-#define MCI_PROGDONEMASK (1 << 23)
-#define MCI_ATACMDCOMPLMASK (1 << 24)
-#define MCI_SDIOINTOPERMASK (1 << 25)
-#define MCI_CCSTIMEOUTMASK (1 << 26)
-
-#define MMCIMASK1 0x040
-#define MMCIFIFOCNT 0x044
-#define MCICCSTIMER 0x058
-
-#define MMCIFIFO 0x080 /* to 0x0bc */
-
-#define MCI_IRQENABLE \
- (MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK| \
- MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK| \
- MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATAENDMASK|MCI_PROGDONEMASK)
-
-#define MCI_IRQ_PIO \
- (MCI_RXDATAAVLBLMASK | MCI_TXDATAAVLBLMASK | MCI_RXFIFOEMPTYMASK | \
- MCI_TXFIFOEMPTYMASK | MCI_RXFIFOFULLMASK | MCI_TXFIFOFULLMASK | \
- MCI_RXFIFOHALFFULLMASK | MCI_TXFIFOHALFEMPTYMASK | \
- MCI_RXACTIVEMASK | MCI_TXACTIVEMASK)
-/*
- * The size of the FIFO in bytes.
- */
-#define MCI_FIFOSIZE (16*4)
-
-#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2)
-
-#define NR_SG 32
-
-struct clk;
-
-struct msmsdcc_nc_dmadata {
- dmov_box cmd[NR_SG];
- uint32_t cmdptr;
-};
-
-struct msmsdcc_dma_data {
- struct msmsdcc_nc_dmadata *nc;
- dma_addr_t nc_busaddr;
- dma_addr_t cmd_busaddr;
- dma_addr_t cmdptr_busaddr;
-
- struct msm_dmov_cmd hdr;
- enum dma_data_direction dir;
-
- struct scatterlist *sg;
- int num_ents;
-
- int channel;
- struct msmsdcc_host *host;
- int busy; /* Set if DM is busy */
- int active;
- unsigned int result;
- struct msm_dmov_errdata err;
-};
-
-struct msmsdcc_pio_data {
- struct scatterlist *sg;
- unsigned int sg_len;
- unsigned int sg_off;
-};
-
-struct msmsdcc_curr_req {
- struct mmc_request *mrq;
- struct mmc_command *cmd;
- struct mmc_data *data;
- unsigned int xfer_size; /* Total data size */
- unsigned int xfer_remain; /* Bytes remaining to send */
- unsigned int data_xfered; /* Bytes acked by BLKEND irq */
- int got_dataend;
- int user_pages;
-};
-
-struct msmsdcc_stats {
- unsigned int reqs;
- unsigned int cmds;
- unsigned int cmdpoll_hits;
- unsigned int cmdpoll_misses;
-};
-
-struct msmsdcc_host {
- struct resource *cmd_irqres;
- struct resource *memres;
- struct resource *dmares;
- void __iomem *base;
- int pdev_id;
- unsigned int stat_irq;
-
- struct msmsdcc_curr_req curr;
-
- struct mmc_host *mmc;
- struct clk *clk; /* main MMC bus clock */
- struct clk *pclk; /* SDCC peripheral bus clock */
- unsigned int clks_on; /* set if clocks are enabled */
- struct timer_list busclk_timer;
-
- unsigned int eject; /* eject state */
-
- spinlock_t lock;
-
- unsigned int clk_rate; /* Current clock rate */
- unsigned int pclk_rate;
-
- u32 pwr;
- u32 saved_irq0mask; /* MMCIMASK0 reg value */
- struct msm_mmc_platform_data *plat;
-
- struct timer_list timer;
- unsigned int oldstat;
-
- struct msmsdcc_dma_data dma;
- struct msmsdcc_pio_data pio;
- int cmdpoll;
- struct msmsdcc_stats stats;
-
- struct tasklet_struct dma_tlet;
- /* Command parameters */
- unsigned int cmd_timeout;
- unsigned int cmd_pio_irqmask;
- unsigned int cmd_datactrl;
- struct mmc_command *cmd_cmd;
- u32 cmd_c;
- bool gpio_config_status;
-
- bool prog_scan;
- bool prog_enable;
-};
-
-#endif
diff --git a/ANDROID_3.4.5/drivers/mmc/host/mvsdio.c b/ANDROID_3.4.5/drivers/mmc/host/mvsdio.c
deleted file mode 100644
index eeb8cd12..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/mvsdio.c
+++ /dev/null
@@ -1,921 +0,0 @@
-/*
- * Marvell MMC/SD/SDIO driver
- *
- * Authors: Maen Suleiman, Nicolas Pitre
- * Copyright (C) 2008-2009 Marvell Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/mbus.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/scatterlist.h>
-#include <linux/irq.h>
-#include <linux/gpio.h>
-#include <linux/mmc/host.h>
-
-#include <asm/sizes.h>
-#include <asm/unaligned.h>
-#include <plat/mvsdio.h>
-
-#include "mvsdio.h"
-
-#define DRIVER_NAME "mvsdio"
-
-static int maxfreq = MVSD_CLOCKRATE_MAX;
-static int nodma;
-
-struct mvsd_host {
- void __iomem *base;
- struct mmc_request *mrq;
- spinlock_t lock;
- unsigned int xfer_mode;
- unsigned int intr_en;
- unsigned int ctrl;
- unsigned int pio_size;
- void *pio_ptr;
- unsigned int sg_frags;
- unsigned int ns_per_clk;
- unsigned int clock;
- unsigned int base_clock;
- struct timer_list timer;
- struct mmc_host *mmc;
- struct device *dev;
- struct resource *res;
- int irq;
- int gpio_card_detect;
- int gpio_write_protect;
-};
-
-#define mvsd_write(offs, val) writel(val, iobase + (offs))
-#define mvsd_read(offs) readl(iobase + (offs))
-
-static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data)
-{
- void __iomem *iobase = host->base;
- unsigned int tmout;
- int tmout_index;
-
- /*
- * Hardware weirdness. The FIFO_EMPTY bit of the HW_STATE
- * register is sometimes not set before a while when some
- * "unusual" data block sizes are used (such as with the SWITCH
- * command), even despite the fact that the XFER_DONE interrupt
- * was raised. And if another data transfer starts before
- * this bit comes to good sense (which eventually happens by
- * itself) then the new transfer simply fails with a timeout.
- */
- if (!(mvsd_read(MVSD_HW_STATE) & (1 << 13))) {
- unsigned long t = jiffies + HZ;
- unsigned int hw_state, count = 0;
- do {
- if (time_after(jiffies, t)) {
- dev_warn(host->dev, "FIFO_EMPTY bit missing\n");
- break;
- }
- hw_state = mvsd_read(MVSD_HW_STATE);
- count++;
- } while (!(hw_state & (1 << 13)));
- dev_dbg(host->dev, "*** wait for FIFO_EMPTY bit "
- "(hw=0x%04x, count=%d, jiffies=%ld)\n",
- hw_state, count, jiffies - (t - HZ));
- }
-
- /* If timeout=0 then maximum timeout index is used. */
- tmout = DIV_ROUND_UP(data->timeout_ns, host->ns_per_clk);
- tmout += data->timeout_clks;
- tmout_index = fls(tmout - 1) - 12;
- if (tmout_index < 0)
- tmout_index = 0;
- if (tmout_index > MVSD_HOST_CTRL_TMOUT_MAX)
- tmout_index = MVSD_HOST_CTRL_TMOUT_MAX;
-
- dev_dbg(host->dev, "data %s at 0x%08x: blocks=%d blksz=%d tmout=%u (%d)\n",
- (data->flags & MMC_DATA_READ) ? "read" : "write",
- (u32)sg_virt(data->sg), data->blocks, data->blksz,
- tmout, tmout_index);
-
- host->ctrl &= ~MVSD_HOST_CTRL_TMOUT_MASK;
- host->ctrl |= MVSD_HOST_CTRL_TMOUT(tmout_index);
- mvsd_write(MVSD_HOST_CTRL, host->ctrl);
- mvsd_write(MVSD_BLK_COUNT, data->blocks);
- mvsd_write(MVSD_BLK_SIZE, data->blksz);
-
- if (nodma || (data->blksz | data->sg->offset) & 3) {
- /*
- * We cannot do DMA on a buffer which offset or size
- * is not aligned on a 4-byte boundary.
- */
- host->pio_size = data->blocks * data->blksz;
- host->pio_ptr = sg_virt(data->sg);
- if (!nodma)
- pr_debug("%s: fallback to PIO for data "
- "at 0x%p size %d\n",
- mmc_hostname(host->mmc),
- host->pio_ptr, host->pio_size);
- return 1;
- } else {
- dma_addr_t phys_addr;
- int dma_dir = (data->flags & MMC_DATA_READ) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE;
- host->sg_frags = dma_map_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, dma_dir);
- phys_addr = sg_dma_address(data->sg);
- mvsd_write(MVSD_SYS_ADDR_LOW, (u32)phys_addr & 0xffff);
- mvsd_write(MVSD_SYS_ADDR_HI, (u32)phys_addr >> 16);
- return 0;
- }
-}
-
-static void mvsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct mvsd_host *host = mmc_priv(mmc);
- void __iomem *iobase = host->base;
- struct mmc_command *cmd = mrq->cmd;
- u32 cmdreg = 0, xfer = 0, intr = 0;
- unsigned long flags;
-
- BUG_ON(host->mrq != NULL);
- host->mrq = mrq;
-
- dev_dbg(host->dev, "cmd %d (hw state 0x%04x)\n",
- cmd->opcode, mvsd_read(MVSD_HW_STATE));
-
- cmdreg = MVSD_CMD_INDEX(cmd->opcode);
-
- if (cmd->flags & MMC_RSP_BUSY)
- cmdreg |= MVSD_CMD_RSP_48BUSY;
- else if (cmd->flags & MMC_RSP_136)
- cmdreg |= MVSD_CMD_RSP_136;
- else if (cmd->flags & MMC_RSP_PRESENT)
- cmdreg |= MVSD_CMD_RSP_48;
- else
- cmdreg |= MVSD_CMD_RSP_NONE;
-
- if (cmd->flags & MMC_RSP_CRC)
- cmdreg |= MVSD_CMD_CHECK_CMDCRC;
-
- if (cmd->flags & MMC_RSP_OPCODE)
- cmdreg |= MVSD_CMD_INDX_CHECK;
-
- if (cmd->flags & MMC_RSP_PRESENT) {
- cmdreg |= MVSD_UNEXPECTED_RESP;
- intr |= MVSD_NOR_UNEXP_RSP;
- }
-
- if (mrq->data) {
- struct mmc_data *data = mrq->data;
- int pio;
-
- cmdreg |= MVSD_CMD_DATA_PRESENT | MVSD_CMD_CHECK_DATACRC16;
- xfer |= MVSD_XFER_MODE_HW_WR_DATA_EN;
- if (data->flags & MMC_DATA_READ)
- xfer |= MVSD_XFER_MODE_TO_HOST;
-
- pio = mvsd_setup_data(host, data);
- if (pio) {
- xfer |= MVSD_XFER_MODE_PIO;
- /* PIO section of mvsd_irq has comments on those bits */
- if (data->flags & MMC_DATA_WRITE)
- intr |= MVSD_NOR_TX_AVAIL;
- else if (host->pio_size > 32)
- intr |= MVSD_NOR_RX_FIFO_8W;
- else
- intr |= MVSD_NOR_RX_READY;
- }
-
- if (data->stop) {
- struct mmc_command *stop = data->stop;
- u32 cmd12reg = 0;
-
- mvsd_write(MVSD_AUTOCMD12_ARG_LOW, stop->arg & 0xffff);
- mvsd_write(MVSD_AUTOCMD12_ARG_HI, stop->arg >> 16);
-
- if (stop->flags & MMC_RSP_BUSY)
- cmd12reg |= MVSD_AUTOCMD12_BUSY;
- if (stop->flags & MMC_RSP_OPCODE)
- cmd12reg |= MVSD_AUTOCMD12_INDX_CHECK;
- cmd12reg |= MVSD_AUTOCMD12_INDEX(stop->opcode);
- mvsd_write(MVSD_AUTOCMD12_CMD, cmd12reg);
-
- xfer |= MVSD_XFER_MODE_AUTO_CMD12;
- intr |= MVSD_NOR_AUTOCMD12_DONE;
- } else {
- intr |= MVSD_NOR_XFER_DONE;
- }
- } else {
- intr |= MVSD_NOR_CMD_DONE;
- }
-
- mvsd_write(MVSD_ARG_LOW, cmd->arg & 0xffff);
- mvsd_write(MVSD_ARG_HI, cmd->arg >> 16);
-
- spin_lock_irqsave(&host->lock, flags);
-
- host->xfer_mode &= MVSD_XFER_MODE_INT_CHK_EN;
- host->xfer_mode |= xfer;
- mvsd_write(MVSD_XFER_MODE, host->xfer_mode);
-
- mvsd_write(MVSD_NOR_INTR_STATUS, ~MVSD_NOR_CARD_INT);
- mvsd_write(MVSD_ERR_INTR_STATUS, 0xffff);
- mvsd_write(MVSD_CMD, cmdreg);
-
- host->intr_en &= MVSD_NOR_CARD_INT;
- host->intr_en |= intr | MVSD_NOR_ERROR;
- mvsd_write(MVSD_NOR_INTR_EN, host->intr_en);
- mvsd_write(MVSD_ERR_INTR_EN, 0xffff);
-
- mod_timer(&host->timer, jiffies + 5 * HZ);
-
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static u32 mvsd_finish_cmd(struct mvsd_host *host, struct mmc_command *cmd,
- u32 err_status)
-{
- void __iomem *iobase = host->base;
-
- if (cmd->flags & MMC_RSP_136) {
- unsigned int response[8], i;
- for (i = 0; i < 8; i++)
- response[i] = mvsd_read(MVSD_RSP(i));
- cmd->resp[0] = ((response[0] & 0x03ff) << 22) |
- ((response[1] & 0xffff) << 6) |
- ((response[2] & 0xfc00) >> 10);
- cmd->resp[1] = ((response[2] & 0x03ff) << 22) |
- ((response[3] & 0xffff) << 6) |
- ((response[4] & 0xfc00) >> 10);
- cmd->resp[2] = ((response[4] & 0x03ff) << 22) |
- ((response[5] & 0xffff) << 6) |
- ((response[6] & 0xfc00) >> 10);
- cmd->resp[3] = ((response[6] & 0x03ff) << 22) |
- ((response[7] & 0x3fff) << 8);
- } else if (cmd->flags & MMC_RSP_PRESENT) {
- unsigned int response[3], i;
- for (i = 0; i < 3; i++)
- response[i] = mvsd_read(MVSD_RSP(i));
- cmd->resp[0] = ((response[2] & 0x003f) << (8 - 8)) |
- ((response[1] & 0xffff) << (14 - 8)) |
- ((response[0] & 0x03ff) << (30 - 8));
- cmd->resp[1] = ((response[0] & 0xfc00) >> 10);
- cmd->resp[2] = 0;
- cmd->resp[3] = 0;
- }
-
- if (err_status & MVSD_ERR_CMD_TIMEOUT) {
- cmd->error = -ETIMEDOUT;
- } else if (err_status & (MVSD_ERR_CMD_CRC | MVSD_ERR_CMD_ENDBIT |
- MVSD_ERR_CMD_INDEX | MVSD_ERR_CMD_STARTBIT)) {
- cmd->error = -EILSEQ;
- }
- err_status &= ~(MVSD_ERR_CMD_TIMEOUT | MVSD_ERR_CMD_CRC |
- MVSD_ERR_CMD_ENDBIT | MVSD_ERR_CMD_INDEX |
- MVSD_ERR_CMD_STARTBIT);
-
- return err_status;
-}
-
-static u32 mvsd_finish_data(struct mvsd_host *host, struct mmc_data *data,
- u32 err_status)
-{
- void __iomem *iobase = host->base;
-
- if (host->pio_ptr) {
- host->pio_ptr = NULL;
- host->pio_size = 0;
- } else {
- dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_frags,
- (data->flags & MMC_DATA_READ) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
- }
-
- if (err_status & MVSD_ERR_DATA_TIMEOUT)
- data->error = -ETIMEDOUT;
- else if (err_status & (MVSD_ERR_DATA_CRC | MVSD_ERR_DATA_ENDBIT))
- data->error = -EILSEQ;
- else if (err_status & MVSD_ERR_XFER_SIZE)
- data->error = -EBADE;
- err_status &= ~(MVSD_ERR_DATA_TIMEOUT | MVSD_ERR_DATA_CRC |
- MVSD_ERR_DATA_ENDBIT | MVSD_ERR_XFER_SIZE);
-
- dev_dbg(host->dev, "data done: blocks_left=%d, bytes_left=%d\n",
- mvsd_read(MVSD_CURR_BLK_LEFT), mvsd_read(MVSD_CURR_BYTE_LEFT));
- data->bytes_xfered =
- (data->blocks - mvsd_read(MVSD_CURR_BLK_LEFT)) * data->blksz;
- /* We can't be sure about the last block when errors are detected */
- if (data->bytes_xfered && data->error)
- data->bytes_xfered -= data->blksz;
-
- /* Handle Auto cmd 12 response */
- if (data->stop) {
- unsigned int response[3], i;
- for (i = 0; i < 3; i++)
- response[i] = mvsd_read(MVSD_AUTO_RSP(i));
- data->stop->resp[0] = ((response[2] & 0x003f) << (8 - 8)) |
- ((response[1] & 0xffff) << (14 - 8)) |
- ((response[0] & 0x03ff) << (30 - 8));
- data->stop->resp[1] = ((response[0] & 0xfc00) >> 10);
- data->stop->resp[2] = 0;
- data->stop->resp[3] = 0;
-
- if (err_status & MVSD_ERR_AUTOCMD12) {
- u32 err_cmd12 = mvsd_read(MVSD_AUTOCMD12_ERR_STATUS);
- dev_dbg(host->dev, "c12err 0x%04x\n", err_cmd12);
- if (err_cmd12 & MVSD_AUTOCMD12_ERR_NOTEXE)
- data->stop->error = -ENOEXEC;
- else if (err_cmd12 & MVSD_AUTOCMD12_ERR_TIMEOUT)
- data->stop->error = -ETIMEDOUT;
- else if (err_cmd12)
- data->stop->error = -EILSEQ;
- err_status &= ~MVSD_ERR_AUTOCMD12;
- }
- }
-
- return err_status;
-}
-
-static irqreturn_t mvsd_irq(int irq, void *dev)
-{
- struct mvsd_host *host = dev;
- void __iomem *iobase = host->base;
- u32 intr_status, intr_done_mask;
- int irq_handled = 0;
-
- intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);
- dev_dbg(host->dev, "intr 0x%04x intr_en 0x%04x hw_state 0x%04x\n",
- intr_status, mvsd_read(MVSD_NOR_INTR_EN),
- mvsd_read(MVSD_HW_STATE));
-
- spin_lock(&host->lock);
-
- /* PIO handling, if needed. Messy business... */
- if (host->pio_size &&
- (intr_status & host->intr_en &
- (MVSD_NOR_RX_READY | MVSD_NOR_RX_FIFO_8W))) {
- u16 *p = host->pio_ptr;
- int s = host->pio_size;
- while (s >= 32 && (intr_status & MVSD_NOR_RX_FIFO_8W)) {
- readsw(iobase + MVSD_FIFO, p, 16);
- p += 16;
- s -= 32;
- intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);
- }
- /*
- * Normally we'd use < 32 here, but the RX_FIFO_8W bit
- * doesn't appear to assert when there is exactly 32 bytes
- * (8 words) left to fetch in a transfer.
- */
- if (s <= 32) {
- while (s >= 4 && (intr_status & MVSD_NOR_RX_READY)) {
- put_unaligned(mvsd_read(MVSD_FIFO), p++);
- put_unaligned(mvsd_read(MVSD_FIFO), p++);
- s -= 4;
- intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);
- }
- if (s && s < 4 && (intr_status & MVSD_NOR_RX_READY)) {
- u16 val[2] = {0, 0};
- val[0] = mvsd_read(MVSD_FIFO);
- val[1] = mvsd_read(MVSD_FIFO);
- memcpy(p, ((void *)&val) + 4 - s, s);
- s = 0;
- intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);
- }
- if (s == 0) {
- host->intr_en &=
- ~(MVSD_NOR_RX_READY | MVSD_NOR_RX_FIFO_8W);
- mvsd_write(MVSD_NOR_INTR_EN, host->intr_en);
- } else if (host->intr_en & MVSD_NOR_RX_FIFO_8W) {
- host->intr_en &= ~MVSD_NOR_RX_FIFO_8W;
- host->intr_en |= MVSD_NOR_RX_READY;
- mvsd_write(MVSD_NOR_INTR_EN, host->intr_en);
- }
- }
- dev_dbg(host->dev, "pio %d intr 0x%04x hw_state 0x%04x\n",
- s, intr_status, mvsd_read(MVSD_HW_STATE));
- host->pio_ptr = p;
- host->pio_size = s;
- irq_handled = 1;
- } else if (host->pio_size &&
- (intr_status & host->intr_en &
- (MVSD_NOR_TX_AVAIL | MVSD_NOR_TX_FIFO_8W))) {
- u16 *p = host->pio_ptr;
- int s = host->pio_size;
- /*
- * The TX_FIFO_8W bit is unreliable. When set, bursting
- * 16 halfwords all at once in the FIFO drops data. Actually
- * TX_AVAIL does go off after only one word is pushed even if
- * TX_FIFO_8W remains set.
- */
- while (s >= 4 && (intr_status & MVSD_NOR_TX_AVAIL)) {
- mvsd_write(MVSD_FIFO, get_unaligned(p++));
- mvsd_write(MVSD_FIFO, get_unaligned(p++));
- s -= 4;
- intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);
- }
- if (s < 4) {
- if (s && (intr_status & MVSD_NOR_TX_AVAIL)) {
- u16 val[2] = {0, 0};
- memcpy(((void *)&val) + 4 - s, p, s);
- mvsd_write(MVSD_FIFO, val[0]);
- mvsd_write(MVSD_FIFO, val[1]);
- s = 0;
- intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);
- }
- if (s == 0) {
- host->intr_en &=
- ~(MVSD_NOR_TX_AVAIL | MVSD_NOR_TX_FIFO_8W);
- mvsd_write(MVSD_NOR_INTR_EN, host->intr_en);
- }
- }
- dev_dbg(host->dev, "pio %d intr 0x%04x hw_state 0x%04x\n",
- s, intr_status, mvsd_read(MVSD_HW_STATE));
- host->pio_ptr = p;
- host->pio_size = s;
- irq_handled = 1;
- }
-
- mvsd_write(MVSD_NOR_INTR_STATUS, intr_status);
-
- intr_done_mask = MVSD_NOR_CARD_INT | MVSD_NOR_RX_READY |
- MVSD_NOR_RX_FIFO_8W | MVSD_NOR_TX_FIFO_8W;
- if (intr_status & host->intr_en & ~intr_done_mask) {
- struct mmc_request *mrq = host->mrq;
- struct mmc_command *cmd = mrq->cmd;
- u32 err_status = 0;
-
- del_timer(&host->timer);
- host->mrq = NULL;
-
- host->intr_en &= MVSD_NOR_CARD_INT;
- mvsd_write(MVSD_NOR_INTR_EN, host->intr_en);
- mvsd_write(MVSD_ERR_INTR_EN, 0);
-
- spin_unlock(&host->lock);
-
- if (intr_status & MVSD_NOR_UNEXP_RSP) {
- cmd->error = -EPROTO;
- } else if (intr_status & MVSD_NOR_ERROR) {
- err_status = mvsd_read(MVSD_ERR_INTR_STATUS);
- dev_dbg(host->dev, "err 0x%04x\n", err_status);
- }
-
- err_status = mvsd_finish_cmd(host, cmd, err_status);
- if (mrq->data)
- err_status = mvsd_finish_data(host, mrq->data, err_status);
- if (err_status) {
- pr_err("%s: unhandled error status %#04x\n",
- mmc_hostname(host->mmc), err_status);
- cmd->error = -ENOMSG;
- }
-
- mmc_request_done(host->mmc, mrq);
- irq_handled = 1;
- } else
- spin_unlock(&host->lock);
-
- if (intr_status & MVSD_NOR_CARD_INT) {
- mmc_signal_sdio_irq(host->mmc);
- irq_handled = 1;
- }
-
- if (irq_handled)
- return IRQ_HANDLED;
-
- pr_err("%s: unhandled interrupt status=0x%04x en=0x%04x "
- "pio=%d\n", mmc_hostname(host->mmc), intr_status,
- host->intr_en, host->pio_size);
- return IRQ_NONE;
-}
-
-static void mvsd_timeout_timer(unsigned long data)
-{
- struct mvsd_host *host = (struct mvsd_host *)data;
- void __iomem *iobase = host->base;
- struct mmc_request *mrq;
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- mrq = host->mrq;
- if (mrq) {
- pr_err("%s: Timeout waiting for hardware interrupt.\n",
- mmc_hostname(host->mmc));
- pr_err("%s: hw_state=0x%04x, intr_status=0x%04x "
- "intr_en=0x%04x\n", mmc_hostname(host->mmc),
- mvsd_read(MVSD_HW_STATE),
- mvsd_read(MVSD_NOR_INTR_STATUS),
- mvsd_read(MVSD_NOR_INTR_EN));
-
- host->mrq = NULL;
-
- mvsd_write(MVSD_SW_RESET, MVSD_SW_RESET_NOW);
-
- host->xfer_mode &= MVSD_XFER_MODE_INT_CHK_EN;
- mvsd_write(MVSD_XFER_MODE, host->xfer_mode);
-
- host->intr_en &= MVSD_NOR_CARD_INT;
- mvsd_write(MVSD_NOR_INTR_EN, host->intr_en);
- mvsd_write(MVSD_ERR_INTR_EN, 0);
- mvsd_write(MVSD_ERR_INTR_STATUS, 0xffff);
-
- mrq->cmd->error = -ETIMEDOUT;
- mvsd_finish_cmd(host, mrq->cmd, 0);
- if (mrq->data) {
- mrq->data->error = -ETIMEDOUT;
- mvsd_finish_data(host, mrq->data, 0);
- }
- }
- spin_unlock_irqrestore(&host->lock, flags);
-
- if (mrq)
- mmc_request_done(host->mmc, mrq);
-}
-
-static irqreturn_t mvsd_card_detect_irq(int irq, void *dev)
-{
- struct mvsd_host *host = dev;
- mmc_detect_change(host->mmc, msecs_to_jiffies(100));
- return IRQ_HANDLED;
-}
-
-static void mvsd_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
- struct mvsd_host *host = mmc_priv(mmc);
- void __iomem *iobase = host->base;
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- if (enable) {
- host->xfer_mode |= MVSD_XFER_MODE_INT_CHK_EN;
- host->intr_en |= MVSD_NOR_CARD_INT;
- } else {
- host->xfer_mode &= ~MVSD_XFER_MODE_INT_CHK_EN;
- host->intr_en &= ~MVSD_NOR_CARD_INT;
- }
- mvsd_write(MVSD_XFER_MODE, host->xfer_mode);
- mvsd_write(MVSD_NOR_INTR_EN, host->intr_en);
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static int mvsd_get_ro(struct mmc_host *mmc)
-{
- struct mvsd_host *host = mmc_priv(mmc);
-
- if (host->gpio_write_protect)
- return gpio_get_value(host->gpio_write_protect);
-
- /*
- * Board doesn't support read only detection; let the mmc core
- * decide what to do.
- */
- return -ENOSYS;
-}
-
-static void mvsd_power_up(struct mvsd_host *host)
-{
- void __iomem *iobase = host->base;
- dev_dbg(host->dev, "power up\n");
- mvsd_write(MVSD_NOR_INTR_EN, 0);
- mvsd_write(MVSD_ERR_INTR_EN, 0);
- mvsd_write(MVSD_SW_RESET, MVSD_SW_RESET_NOW);
- mvsd_write(MVSD_XFER_MODE, 0);
- mvsd_write(MVSD_NOR_STATUS_EN, 0xffff);
- mvsd_write(MVSD_ERR_STATUS_EN, 0xffff);
- mvsd_write(MVSD_NOR_INTR_STATUS, 0xffff);
- mvsd_write(MVSD_ERR_INTR_STATUS, 0xffff);
-}
-
-static void mvsd_power_down(struct mvsd_host *host)
-{
- void __iomem *iobase = host->base;
- dev_dbg(host->dev, "power down\n");
- mvsd_write(MVSD_NOR_INTR_EN, 0);
- mvsd_write(MVSD_ERR_INTR_EN, 0);
- mvsd_write(MVSD_SW_RESET, MVSD_SW_RESET_NOW);
- mvsd_write(MVSD_XFER_MODE, MVSD_XFER_MODE_STOP_CLK);
- mvsd_write(MVSD_NOR_STATUS_EN, 0);
- mvsd_write(MVSD_ERR_STATUS_EN, 0);
- mvsd_write(MVSD_NOR_INTR_STATUS, 0xffff);
- mvsd_write(MVSD_ERR_INTR_STATUS, 0xffff);
-}
-
-static void mvsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct mvsd_host *host = mmc_priv(mmc);
- void __iomem *iobase = host->base;
- u32 ctrl_reg = 0;
-
- if (ios->power_mode == MMC_POWER_UP)
- mvsd_power_up(host);
-
- if (ios->clock == 0) {
- mvsd_write(MVSD_XFER_MODE, MVSD_XFER_MODE_STOP_CLK);
- mvsd_write(MVSD_CLK_DIV, MVSD_BASE_DIV_MAX);
- host->clock = 0;
- dev_dbg(host->dev, "clock off\n");
- } else if (ios->clock != host->clock) {
- u32 m = DIV_ROUND_UP(host->base_clock, ios->clock) - 1;
- if (m > MVSD_BASE_DIV_MAX)
- m = MVSD_BASE_DIV_MAX;
- mvsd_write(MVSD_CLK_DIV, m);
- host->clock = ios->clock;
- host->ns_per_clk = 1000000000 / (host->base_clock / (m+1));
- dev_dbg(host->dev, "clock=%d (%d), div=0x%04x\n",
- ios->clock, host->base_clock / (m+1), m);
- }
-
- /* default transfer mode */
- ctrl_reg |= MVSD_HOST_CTRL_BIG_ENDIAN;
- ctrl_reg &= ~MVSD_HOST_CTRL_LSB_FIRST;
-
- /* default to maximum timeout */
- ctrl_reg |= MVSD_HOST_CTRL_TMOUT_MASK;
- ctrl_reg |= MVSD_HOST_CTRL_TMOUT_EN;
-
- if (ios->bus_mode == MMC_BUSMODE_PUSHPULL)
- ctrl_reg |= MVSD_HOST_CTRL_PUSH_PULL_EN;
-
- if (ios->bus_width == MMC_BUS_WIDTH_4)
- ctrl_reg |= MVSD_HOST_CTRL_DATA_WIDTH_4_BITS;
-
- /*
- * The HI_SPEED_EN bit is causing trouble with many (but not all)
- * high speed SD, SDHC and SDIO cards. Not enabling that bit
- * makes all cards work. So let's just ignore that bit for now
- * and revisit this issue if problems for not enabling this bit
- * are ever reported.
- */
-#if 0
- if (ios->timing == MMC_TIMING_MMC_HS ||
- ios->timing == MMC_TIMING_SD_HS)
- ctrl_reg |= MVSD_HOST_CTRL_HI_SPEED_EN;
-#endif
-
- host->ctrl = ctrl_reg;
- mvsd_write(MVSD_HOST_CTRL, ctrl_reg);
- dev_dbg(host->dev, "ctrl 0x%04x: %s %s %s\n", ctrl_reg,
- (ctrl_reg & MVSD_HOST_CTRL_PUSH_PULL_EN) ?
- "push-pull" : "open-drain",
- (ctrl_reg & MVSD_HOST_CTRL_DATA_WIDTH_4_BITS) ?
- "4bit-width" : "1bit-width",
- (ctrl_reg & MVSD_HOST_CTRL_HI_SPEED_EN) ?
- "high-speed" : "");
-
- if (ios->power_mode == MMC_POWER_OFF)
- mvsd_power_down(host);
-}
-
-static const struct mmc_host_ops mvsd_ops = {
- .request = mvsd_request,
- .get_ro = mvsd_get_ro,
- .set_ios = mvsd_set_ios,
- .enable_sdio_irq = mvsd_enable_sdio_irq,
-};
-
-static void __init
-mv_conf_mbus_windows(struct mvsd_host *host,
- const struct mbus_dram_target_info *dram)
-{
- void __iomem *iobase = host->base;
- int i;
-
- for (i = 0; i < 4; i++) {
- writel(0, iobase + MVSD_WINDOW_CTRL(i));
- writel(0, iobase + MVSD_WINDOW_BASE(i));
- }
-
- for (i = 0; i < dram->num_cs; i++) {
- const struct mbus_dram_window *cs = dram->cs + i;
- writel(((cs->size - 1) & 0xffff0000) |
- (cs->mbus_attr << 8) |
- (dram->mbus_dram_target_id << 4) | 1,
- iobase + MVSD_WINDOW_CTRL(i));
- writel(cs->base, iobase + MVSD_WINDOW_BASE(i));
- }
-}
-
-static int __init mvsd_probe(struct platform_device *pdev)
-{
- struct mmc_host *mmc = NULL;
- struct mvsd_host *host = NULL;
- const struct mvsdio_platform_data *mvsd_data;
- const struct mbus_dram_target_info *dram;
- struct resource *r;
- int ret, irq;
-
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
- mvsd_data = pdev->dev.platform_data;
- if (!r || irq < 0 || !mvsd_data)
- return -ENXIO;
-
- r = request_mem_region(r->start, SZ_1K, DRIVER_NAME);
- if (!r)
- return -EBUSY;
-
- mmc = mmc_alloc_host(sizeof(struct mvsd_host), &pdev->dev);
- if (!mmc) {
- ret = -ENOMEM;
- goto out;
- }
-
- host = mmc_priv(mmc);
- host->mmc = mmc;
- host->dev = &pdev->dev;
- host->res = r;
- host->base_clock = mvsd_data->clock / 2;
-
- mmc->ops = &mvsd_ops;
-
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ |
- MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
-
- mmc->f_min = DIV_ROUND_UP(host->base_clock, MVSD_BASE_DIV_MAX);
- mmc->f_max = maxfreq;
-
- mmc->max_blk_size = 2048;
- mmc->max_blk_count = 65535;
-
- mmc->max_segs = 1;
- mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count;
- mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
-
- spin_lock_init(&host->lock);
-
- host->base = ioremap(r->start, SZ_4K);
- if (!host->base) {
- ret = -ENOMEM;
- goto out;
- }
-
- /* (Re-)program MBUS remapping windows if we are asked to. */
- dram = mv_mbus_dram_info();
- if (dram)
- mv_conf_mbus_windows(host, dram);
-
- mvsd_power_down(host);
-
- ret = request_irq(irq, mvsd_irq, 0, DRIVER_NAME, host);
- if (ret) {
- pr_err("%s: cannot assign irq %d\n", DRIVER_NAME, irq);
- goto out;
- } else
- host->irq = irq;
-
- if (mvsd_data->gpio_card_detect) {
- ret = gpio_request(mvsd_data->gpio_card_detect,
- DRIVER_NAME " cd");
- if (ret == 0) {
- gpio_direction_input(mvsd_data->gpio_card_detect);
- irq = gpio_to_irq(mvsd_data->gpio_card_detect);
- ret = request_irq(irq, mvsd_card_detect_irq,
- IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING,
- DRIVER_NAME " cd", host);
- if (ret == 0)
- host->gpio_card_detect =
- mvsd_data->gpio_card_detect;
- else
- gpio_free(mvsd_data->gpio_card_detect);
- }
- }
- if (!host->gpio_card_detect)
- mmc->caps |= MMC_CAP_NEEDS_POLL;
-
- if (mvsd_data->gpio_write_protect) {
- ret = gpio_request(mvsd_data->gpio_write_protect,
- DRIVER_NAME " wp");
- if (ret == 0) {
- gpio_direction_input(mvsd_data->gpio_write_protect);
- host->gpio_write_protect =
- mvsd_data->gpio_write_protect;
- }
- }
-
- setup_timer(&host->timer, mvsd_timeout_timer, (unsigned long)host);
- platform_set_drvdata(pdev, mmc);
- ret = mmc_add_host(mmc);
- if (ret)
- goto out;
-
- pr_notice("%s: %s driver initialized, ",
- mmc_hostname(mmc), DRIVER_NAME);
- if (host->gpio_card_detect)
- printk("using GPIO %d for card detection\n",
- host->gpio_card_detect);
- else
- printk("lacking card detect (fall back to polling)\n");
- return 0;
-
-out:
- if (host) {
- if (host->irq)
- free_irq(host->irq, host);
- if (host->gpio_card_detect) {
- free_irq(gpio_to_irq(host->gpio_card_detect), host);
- gpio_free(host->gpio_card_detect);
- }
- if (host->gpio_write_protect)
- gpio_free(host->gpio_write_protect);
- if (host->base)
- iounmap(host->base);
- }
- if (r)
- release_resource(r);
- if (mmc)
- mmc_free_host(mmc);
-
- return ret;
-}
-
-static int __exit mvsd_remove(struct platform_device *pdev)
-{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
-
- if (mmc) {
- struct mvsd_host *host = mmc_priv(mmc);
-
- if (host->gpio_card_detect) {
- free_irq(gpio_to_irq(host->gpio_card_detect), host);
- gpio_free(host->gpio_card_detect);
- }
- mmc_remove_host(mmc);
- free_irq(host->irq, host);
- if (host->gpio_write_protect)
- gpio_free(host->gpio_write_protect);
- del_timer_sync(&host->timer);
- mvsd_power_down(host);
- iounmap(host->base);
- release_resource(host->res);
- mmc_free_host(mmc);
- }
- platform_set_drvdata(pdev, NULL);
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int mvsd_suspend(struct platform_device *dev, pm_message_t state)
-{
- struct mmc_host *mmc = platform_get_drvdata(dev);
- int ret = 0;
-
- if (mmc)
- ret = mmc_suspend_host(mmc);
-
- return ret;
-}
-
-static int mvsd_resume(struct platform_device *dev)
-{
- struct mmc_host *mmc = platform_get_drvdata(dev);
- int ret = 0;
-
- if (mmc)
- ret = mmc_resume_host(mmc);
-
- return ret;
-}
-#else
-#define mvsd_suspend NULL
-#define mvsd_resume NULL
-#endif
-
-static struct platform_driver mvsd_driver = {
- .remove = __exit_p(mvsd_remove),
- .suspend = mvsd_suspend,
- .resume = mvsd_resume,
- .driver = {
- .name = DRIVER_NAME,
- },
-};
-
-static int __init mvsd_init(void)
-{
- return platform_driver_probe(&mvsd_driver, mvsd_probe);
-}
-
-static void __exit mvsd_exit(void)
-{
- platform_driver_unregister(&mvsd_driver);
-}
-
-module_init(mvsd_init);
-module_exit(mvsd_exit);
-
-/* maximum card clock frequency (default 50MHz) */
-module_param(maxfreq, int, 0);
-
-/* force PIO transfers all the time */
-module_param(nodma, int, 0);
-
-MODULE_AUTHOR("Maen Suleiman, Nicolas Pitre");
-MODULE_DESCRIPTION("Marvell MMC,SD,SDIO Host Controller driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:mvsdio");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/mvsdio.h b/ANDROID_3.4.5/drivers/mmc/host/mvsdio.h
deleted file mode 100644
index 7d9727b9..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/mvsdio.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2008 Marvell Semiconductors, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __MVSDIO_H
-#define __MVSDIO_H
-
-/*
- * Clock rates
- */
-
-#define MVSD_CLOCKRATE_MAX 50000000
-#define MVSD_BASE_DIV_MAX 0x7ff
-
-
-/*
- * Register offsets
- */
-
-#define MVSD_SYS_ADDR_LOW 0x000
-#define MVSD_SYS_ADDR_HI 0x004
-#define MVSD_BLK_SIZE 0x008
-#define MVSD_BLK_COUNT 0x00c
-#define MVSD_ARG_LOW 0x010
-#define MVSD_ARG_HI 0x014
-#define MVSD_XFER_MODE 0x018
-#define MVSD_CMD 0x01c
-#define MVSD_RSP(i) (0x020 + ((i)<<2))
-#define MVSD_RSP0 0x020
-#define MVSD_RSP1 0x024
-#define MVSD_RSP2 0x028
-#define MVSD_RSP3 0x02c
-#define MVSD_RSP4 0x030
-#define MVSD_RSP5 0x034
-#define MVSD_RSP6 0x038
-#define MVSD_RSP7 0x03c
-#define MVSD_FIFO 0x040
-#define MVSD_RSP_CRC7 0x044
-#define MVSD_HW_STATE 0x048
-#define MVSD_HOST_CTRL 0x050
-#define MVSD_BLK_GAP_CTRL 0x054
-#define MVSD_CLK_CTRL 0x058
-#define MVSD_SW_RESET 0x05c
-#define MVSD_NOR_INTR_STATUS 0x060
-#define MVSD_ERR_INTR_STATUS 0x064
-#define MVSD_NOR_STATUS_EN 0x068
-#define MVSD_ERR_STATUS_EN 0x06c
-#define MVSD_NOR_INTR_EN 0x070
-#define MVSD_ERR_INTR_EN 0x074
-#define MVSD_AUTOCMD12_ERR_STATUS 0x078
-#define MVSD_CURR_BYTE_LEFT 0x07c
-#define MVSD_CURR_BLK_LEFT 0x080
-#define MVSD_AUTOCMD12_ARG_LOW 0x084
-#define MVSD_AUTOCMD12_ARG_HI 0x088
-#define MVSD_AUTOCMD12_CMD 0x08c
-#define MVSD_AUTO_RSP(i) (0x090 + ((i)<<2))
-#define MVSD_AUTO_RSP0 0x090
-#define MVSD_AUTO_RSP1 0x094
-#define MVSD_AUTO_RSP2 0x098
-#define MVSD_CLK_DIV 0x128
-
-#define MVSD_WINDOW_CTRL(i) (0x108 + ((i) << 3))
-#define MVSD_WINDOW_BASE(i) (0x10c + ((i) << 3))
-
-
-/*
- * MVSD_CMD
- */
-
-#define MVSD_CMD_RSP_NONE (0 << 0)
-#define MVSD_CMD_RSP_136 (1 << 0)
-#define MVSD_CMD_RSP_48 (2 << 0)
-#define MVSD_CMD_RSP_48BUSY (3 << 0)
-
-#define MVSD_CMD_CHECK_DATACRC16 (1 << 2)
-#define MVSD_CMD_CHECK_CMDCRC (1 << 3)
-#define MVSD_CMD_INDX_CHECK (1 << 4)
-#define MVSD_CMD_DATA_PRESENT (1 << 5)
-#define MVSD_UNEXPECTED_RESP (1 << 7)
-#define MVSD_CMD_INDEX(x) ((x) << 8)
-
-
-/*
- * MVSD_AUTOCMD12_CMD
- */
-
-#define MVSD_AUTOCMD12_BUSY (1 << 0)
-#define MVSD_AUTOCMD12_INDX_CHECK (1 << 1)
-#define MVSD_AUTOCMD12_INDEX(x) ((x) << 8)
-
-/*
- * MVSD_XFER_MODE
- */
-
-#define MVSD_XFER_MODE_WR_DATA_START (1 << 0)
-#define MVSD_XFER_MODE_HW_WR_DATA_EN (1 << 1)
-#define MVSD_XFER_MODE_AUTO_CMD12 (1 << 2)
-#define MVSD_XFER_MODE_INT_CHK_EN (1 << 3)
-#define MVSD_XFER_MODE_TO_HOST (1 << 4)
-#define MVSD_XFER_MODE_STOP_CLK (1 << 5)
-#define MVSD_XFER_MODE_PIO (1 << 6)
-
-
-/*
- * MVSD_HOST_CTRL
- */
-
-#define MVSD_HOST_CTRL_PUSH_PULL_EN (1 << 0)
-
-#define MVSD_HOST_CTRL_CARD_TYPE_MEM_ONLY (0 << 1)
-#define MVSD_HOST_CTRL_CARD_TYPE_IO_ONLY (1 << 1)
-#define MVSD_HOST_CTRL_CARD_TYPE_IO_MEM_COMBO (2 << 1)
-#define MVSD_HOST_CTRL_CARD_TYPE_IO_MMC (3 << 1)
-#define MVSD_HOST_CTRL_CARD_TYPE_MASK (3 << 1)
-
-#define MVSD_HOST_CTRL_BIG_ENDIAN (1 << 3)
-#define MVSD_HOST_CTRL_LSB_FIRST (1 << 4)
-#define MVSD_HOST_CTRL_DATA_WIDTH_4_BITS (1 << 9)
-#define MVSD_HOST_CTRL_HI_SPEED_EN (1 << 10)
-
-#define MVSD_HOST_CTRL_TMOUT_MAX 0xf
-#define MVSD_HOST_CTRL_TMOUT_MASK (0xf << 11)
-#define MVSD_HOST_CTRL_TMOUT(x) ((x) << 11)
-#define MVSD_HOST_CTRL_TMOUT_EN (1 << 15)
-
-
-/*
- * MVSD_SW_RESET
- */
-
-#define MVSD_SW_RESET_NOW (1 << 8)
-
-
-/*
- * Normal interrupt status bits
- */
-
-#define MVSD_NOR_CMD_DONE (1 << 0)
-#define MVSD_NOR_XFER_DONE (1 << 1)
-#define MVSD_NOR_BLK_GAP_EVT (1 << 2)
-#define MVSD_NOR_DMA_DONE (1 << 3)
-#define MVSD_NOR_TX_AVAIL (1 << 4)
-#define MVSD_NOR_RX_READY (1 << 5)
-#define MVSD_NOR_CARD_INT (1 << 8)
-#define MVSD_NOR_READ_WAIT_ON (1 << 9)
-#define MVSD_NOR_RX_FIFO_8W (1 << 10)
-#define MVSD_NOR_TX_FIFO_8W (1 << 11)
-#define MVSD_NOR_SUSPEND_ON (1 << 12)
-#define MVSD_NOR_AUTOCMD12_DONE (1 << 13)
-#define MVSD_NOR_UNEXP_RSP (1 << 14)
-#define MVSD_NOR_ERROR (1 << 15)
-
-
-/*
- * Error status bits
- */
-
-#define MVSD_ERR_CMD_TIMEOUT (1 << 0)
-#define MVSD_ERR_CMD_CRC (1 << 1)
-#define MVSD_ERR_CMD_ENDBIT (1 << 2)
-#define MVSD_ERR_CMD_INDEX (1 << 3)
-#define MVSD_ERR_DATA_TIMEOUT (1 << 4)
-#define MVSD_ERR_DATA_CRC (1 << 5)
-#define MVSD_ERR_DATA_ENDBIT (1 << 6)
-#define MVSD_ERR_AUTOCMD12 (1 << 8)
-#define MVSD_ERR_CMD_STARTBIT (1 << 9)
-#define MVSD_ERR_XFER_SIZE (1 << 10)
-#define MVSD_ERR_RESP_T_BIT (1 << 11)
-#define MVSD_ERR_CRC_ENDBIT (1 << 12)
-#define MVSD_ERR_CRC_STARTBIT (1 << 13)
-#define MVSD_ERR_CRC_STATUS (1 << 14)
-
-
-/*
- * CMD12 error status bits
- */
-
-#define MVSD_AUTOCMD12_ERR_NOTEXE (1 << 0)
-#define MVSD_AUTOCMD12_ERR_TIMEOUT (1 << 1)
-#define MVSD_AUTOCMD12_ERR_CRC (1 << 2)
-#define MVSD_AUTOCMD12_ERR_ENDBIT (1 << 3)
-#define MVSD_AUTOCMD12_ERR_INDEX (1 << 4)
-#define MVSD_AUTOCMD12_ERR_RESP_T_BIT (1 << 5)
-#define MVSD_AUTOCMD12_ERR_RESP_STARTBIT (1 << 6)
-
-#endif
diff --git a/ANDROID_3.4.5/drivers/mmc/host/mxcmmc.c b/ANDROID_3.4.5/drivers/mmc/host/mxcmmc.c
deleted file mode 100644
index b2058b43..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/mxcmmc.c
+++ /dev/null
@@ -1,1062 +0,0 @@
-/*
- * linux/drivers/mmc/host/mxcmmc.c - Freescale i.MX MMCI driver
- *
- * This is a driver for the SDHC controller found in Freescale MX2/MX3
- * SoCs. It is basically the same hardware as found on MX1 (imxmmc.c).
- * Unlike the hardware found on MX1, this hardware just works and does
- * not need all the quirks found in imxmmc.c, hence the separate driver.
- *
- * Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
- * Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com>
- *
- * derived from pxamci.c by Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/blkdev.h>
-#include <linux/dma-mapping.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/regulator/consumer.h>
-#include <linux/dmaengine.h>
-#include <linux/types.h>
-
-#include <asm/dma.h>
-#include <asm/irq.h>
-#include <asm/sizes.h>
-#include <mach/mmc.h>
-
-#include <mach/dma.h>
-#include <mach/hardware.h>
-
-#define DRIVER_NAME "mxc-mmc"
-
-#define MMC_REG_STR_STP_CLK 0x00
-#define MMC_REG_STATUS 0x04
-#define MMC_REG_CLK_RATE 0x08
-#define MMC_REG_CMD_DAT_CONT 0x0C
-#define MMC_REG_RES_TO 0x10
-#define MMC_REG_READ_TO 0x14
-#define MMC_REG_BLK_LEN 0x18
-#define MMC_REG_NOB 0x1C
-#define MMC_REG_REV_NO 0x20
-#define MMC_REG_INT_CNTR 0x24
-#define MMC_REG_CMD 0x28
-#define MMC_REG_ARG 0x2C
-#define MMC_REG_RES_FIFO 0x34
-#define MMC_REG_BUFFER_ACCESS 0x38
-
-#define STR_STP_CLK_RESET (1 << 3)
-#define STR_STP_CLK_START_CLK (1 << 1)
-#define STR_STP_CLK_STOP_CLK (1 << 0)
-
-#define STATUS_CARD_INSERTION (1 << 31)
-#define STATUS_CARD_REMOVAL (1 << 30)
-#define STATUS_YBUF_EMPTY (1 << 29)
-#define STATUS_XBUF_EMPTY (1 << 28)
-#define STATUS_YBUF_FULL (1 << 27)
-#define STATUS_XBUF_FULL (1 << 26)
-#define STATUS_BUF_UND_RUN (1 << 25)
-#define STATUS_BUF_OVFL (1 << 24)
-#define STATUS_SDIO_INT_ACTIVE (1 << 14)
-#define STATUS_END_CMD_RESP (1 << 13)
-#define STATUS_WRITE_OP_DONE (1 << 12)
-#define STATUS_DATA_TRANS_DONE (1 << 11)
-#define STATUS_READ_OP_DONE (1 << 11)
-#define STATUS_WR_CRC_ERROR_CODE_MASK (3 << 10)
-#define STATUS_CARD_BUS_CLK_RUN (1 << 8)
-#define STATUS_BUF_READ_RDY (1 << 7)
-#define STATUS_BUF_WRITE_RDY (1 << 6)
-#define STATUS_RESP_CRC_ERR (1 << 5)
-#define STATUS_CRC_READ_ERR (1 << 3)
-#define STATUS_CRC_WRITE_ERR (1 << 2)
-#define STATUS_TIME_OUT_RESP (1 << 1)
-#define STATUS_TIME_OUT_READ (1 << 0)
-#define STATUS_ERR_MASK 0x2f
-
-#define CMD_DAT_CONT_CMD_RESP_LONG_OFF (1 << 12)
-#define CMD_DAT_CONT_STOP_READWAIT (1 << 11)
-#define CMD_DAT_CONT_START_READWAIT (1 << 10)
-#define CMD_DAT_CONT_BUS_WIDTH_4 (2 << 8)
-#define CMD_DAT_CONT_INIT (1 << 7)
-#define CMD_DAT_CONT_WRITE (1 << 4)
-#define CMD_DAT_CONT_DATA_ENABLE (1 << 3)
-#define CMD_DAT_CONT_RESPONSE_48BIT_CRC (1 << 0)
-#define CMD_DAT_CONT_RESPONSE_136BIT (2 << 0)
-#define CMD_DAT_CONT_RESPONSE_48BIT (3 << 0)
-
-#define INT_SDIO_INT_WKP_EN (1 << 18)
-#define INT_CARD_INSERTION_WKP_EN (1 << 17)
-#define INT_CARD_REMOVAL_WKP_EN (1 << 16)
-#define INT_CARD_INSERTION_EN (1 << 15)
-#define INT_CARD_REMOVAL_EN (1 << 14)
-#define INT_SDIO_IRQ_EN (1 << 13)
-#define INT_DAT0_EN (1 << 12)
-#define INT_BUF_READ_EN (1 << 4)
-#define INT_BUF_WRITE_EN (1 << 3)
-#define INT_END_CMD_RES_EN (1 << 2)
-#define INT_WRITE_OP_DONE_EN (1 << 1)
-#define INT_READ_OP_EN (1 << 0)
-
-struct mxcmci_host {
- struct mmc_host *mmc;
- struct resource *res;
- void __iomem *base;
- int irq;
- int detect_irq;
- struct dma_chan *dma;
- struct dma_async_tx_descriptor *desc;
- int do_dma;
- int default_irq_mask;
- int use_sdio;
- unsigned int power_mode;
- struct imxmmc_platform_data *pdata;
-
- struct mmc_request *req;
- struct mmc_command *cmd;
- struct mmc_data *data;
-
- unsigned int datasize;
- unsigned int dma_dir;
-
- u16 rev_no;
- unsigned int cmdat;
-
- struct clk *clk;
-
- int clock;
-
- struct work_struct datawork;
- spinlock_t lock;
-
- struct regulator *vcc;
-
- int burstlen;
- int dmareq;
- struct dma_slave_config dma_slave_config;
- struct imx_dma_data dma_data;
-};
-
-static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios);
-
-static inline void mxcmci_init_ocr(struct mxcmci_host *host)
-{
- host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc");
-
- if (IS_ERR(host->vcc)) {
- host->vcc = NULL;
- } else {
- host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc);
- if (host->pdata && host->pdata->ocr_avail)
- dev_warn(mmc_dev(host->mmc),
- "pdata->ocr_avail will not be used\n");
- }
-
- if (host->vcc == NULL) {
- /* fall-back to platform data */
- if (host->pdata && host->pdata->ocr_avail)
- host->mmc->ocr_avail = host->pdata->ocr_avail;
- else
- host->mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- }
-}
-
-static inline void mxcmci_set_power(struct mxcmci_host *host,
- unsigned char power_mode,
- unsigned int vdd)
-{
- if (host->vcc) {
- if (power_mode == MMC_POWER_UP)
- mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
- else if (power_mode == MMC_POWER_OFF)
- mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
- }
-
- if (host->pdata && host->pdata->setpower)
- host->pdata->setpower(mmc_dev(host->mmc), vdd);
-}
-
-static inline int mxcmci_use_dma(struct mxcmci_host *host)
-{
- return host->do_dma;
-}
-
-static void mxcmci_softreset(struct mxcmci_host *host)
-{
- int i;
-
- dev_dbg(mmc_dev(host->mmc), "mxcmci_softreset\n");
-
- /* reset sequence */
- writew(STR_STP_CLK_RESET, host->base + MMC_REG_STR_STP_CLK);
- writew(STR_STP_CLK_RESET | STR_STP_CLK_START_CLK,
- host->base + MMC_REG_STR_STP_CLK);
-
- for (i = 0; i < 8; i++)
- writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK);
-
- writew(0xff, host->base + MMC_REG_RES_TO);
-}
-static int mxcmci_setup_dma(struct mmc_host *mmc);
-
-static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
-{
- unsigned int nob = data->blocks;
- unsigned int blksz = data->blksz;
- unsigned int datasize = nob * blksz;
- struct scatterlist *sg;
- enum dma_transfer_direction slave_dirn;
- int i, nents;
-
- if (data->flags & MMC_DATA_STREAM)
- nob = 0xffff;
-
- host->data = data;
- data->bytes_xfered = 0;
-
- writew(nob, host->base + MMC_REG_NOB);
- writew(blksz, host->base + MMC_REG_BLK_LEN);
- host->datasize = datasize;
-
- if (!mxcmci_use_dma(host))
- return 0;
-
- for_each_sg(data->sg, sg, data->sg_len, i) {
- if (sg->offset & 3 || sg->length & 3) {
- host->do_dma = 0;
- return 0;
- }
- }
-
- if (data->flags & MMC_DATA_READ) {
- host->dma_dir = DMA_FROM_DEVICE;
- slave_dirn = DMA_DEV_TO_MEM;
- } else {
- host->dma_dir = DMA_TO_DEVICE;
- slave_dirn = DMA_MEM_TO_DEV;
- }
-
- nents = dma_map_sg(host->dma->device->dev, data->sg,
- data->sg_len, host->dma_dir);
- if (nents != data->sg_len)
- return -EINVAL;
-
- host->desc = dmaengine_prep_slave_sg(host->dma,
- data->sg, data->sg_len, slave_dirn,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-
- if (!host->desc) {
- dma_unmap_sg(host->dma->device->dev, data->sg, data->sg_len,
- host->dma_dir);
- host->do_dma = 0;
- return 0; /* Fall back to PIO */
- }
- wmb();
-
- dmaengine_submit(host->desc);
- dma_async_issue_pending(host->dma);
-
- return 0;
-}
-
-static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
- unsigned int cmdat)
-{
- u32 int_cntr = host->default_irq_mask;
- unsigned long flags;
-
- WARN_ON(host->cmd != NULL);
- host->cmd = cmd;
-
- switch (mmc_resp_type(cmd)) {
- case MMC_RSP_R1: /* short CRC, OPCODE */
- case MMC_RSP_R1B:/* short CRC, OPCODE, BUSY */
- cmdat |= CMD_DAT_CONT_RESPONSE_48BIT_CRC;
- break;
- case MMC_RSP_R2: /* long 136 bit + CRC */
- cmdat |= CMD_DAT_CONT_RESPONSE_136BIT;
- break;
- case MMC_RSP_R3: /* short */
- cmdat |= CMD_DAT_CONT_RESPONSE_48BIT;
- break;
- case MMC_RSP_NONE:
- break;
- default:
- dev_err(mmc_dev(host->mmc), "unhandled response type 0x%x\n",
- mmc_resp_type(cmd));
- cmd->error = -EINVAL;
- return -EINVAL;
- }
-
- int_cntr = INT_END_CMD_RES_EN;
-
- if (mxcmci_use_dma(host))
- int_cntr |= INT_READ_OP_EN | INT_WRITE_OP_DONE_EN;
-
- spin_lock_irqsave(&host->lock, flags);
- if (host->use_sdio)
- int_cntr |= INT_SDIO_IRQ_EN;
- writel(int_cntr, host->base + MMC_REG_INT_CNTR);
- spin_unlock_irqrestore(&host->lock, flags);
-
- writew(cmd->opcode, host->base + MMC_REG_CMD);
- writel(cmd->arg, host->base + MMC_REG_ARG);
- writew(cmdat, host->base + MMC_REG_CMD_DAT_CONT);
-
- return 0;
-}
-
-static void mxcmci_finish_request(struct mxcmci_host *host,
- struct mmc_request *req)
-{
- u32 int_cntr = host->default_irq_mask;
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- if (host->use_sdio)
- int_cntr |= INT_SDIO_IRQ_EN;
- writel(int_cntr, host->base + MMC_REG_INT_CNTR);
- spin_unlock_irqrestore(&host->lock, flags);
-
- host->req = NULL;
- host->cmd = NULL;
- host->data = NULL;
-
- mmc_request_done(host->mmc, req);
-}
-
-static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat)
-{
- struct mmc_data *data = host->data;
- int data_error;
-
- if (mxcmci_use_dma(host)) {
- dmaengine_terminate_all(host->dma);
- dma_unmap_sg(host->dma->device->dev, data->sg, data->sg_len,
- host->dma_dir);
- }
-
- if (stat & STATUS_ERR_MASK) {
- dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",
- stat);
- if (stat & STATUS_CRC_READ_ERR) {
- dev_err(mmc_dev(host->mmc), "%s: -EILSEQ\n", __func__);
- data->error = -EILSEQ;
- } else if (stat & STATUS_CRC_WRITE_ERR) {
- u32 err_code = (stat >> 9) & 0x3;
- if (err_code == 2) { /* No CRC response */
- dev_err(mmc_dev(host->mmc),
- "%s: No CRC -ETIMEDOUT\n", __func__);
- data->error = -ETIMEDOUT;
- } else {
- dev_err(mmc_dev(host->mmc),
- "%s: -EILSEQ\n", __func__);
- data->error = -EILSEQ;
- }
- } else if (stat & STATUS_TIME_OUT_READ) {
- dev_err(mmc_dev(host->mmc),
- "%s: read -ETIMEDOUT\n", __func__);
- data->error = -ETIMEDOUT;
- } else {
- dev_err(mmc_dev(host->mmc), "%s: -EIO\n", __func__);
- data->error = -EIO;
- }
- } else {
- data->bytes_xfered = host->datasize;
- }
-
- data_error = data->error;
-
- host->data = NULL;
-
- return data_error;
-}
-
-static void mxcmci_read_response(struct mxcmci_host *host, unsigned int stat)
-{
- struct mmc_command *cmd = host->cmd;
- int i;
- u32 a, b, c;
-
- if (!cmd)
- return;
-
- if (stat & STATUS_TIME_OUT_RESP) {
- dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n");
- cmd->error = -ETIMEDOUT;
- } else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
- dev_dbg(mmc_dev(host->mmc), "cmd crc error\n");
- cmd->error = -EILSEQ;
- }
-
- if (cmd->flags & MMC_RSP_PRESENT) {
- if (cmd->flags & MMC_RSP_136) {
- for (i = 0; i < 4; i++) {
- a = readw(host->base + MMC_REG_RES_FIFO);
- b = readw(host->base + MMC_REG_RES_FIFO);
- cmd->resp[i] = a << 16 | b;
- }
- } else {
- a = readw(host->base + MMC_REG_RES_FIFO);
- b = readw(host->base + MMC_REG_RES_FIFO);
- c = readw(host->base + MMC_REG_RES_FIFO);
- cmd->resp[0] = a << 24 | b << 8 | c >> 8;
- }
- }
-}
-
-static int mxcmci_poll_status(struct mxcmci_host *host, u32 mask)
-{
- u32 stat;
- unsigned long timeout = jiffies + HZ;
-
- do {
- stat = readl(host->base + MMC_REG_STATUS);
- if (stat & STATUS_ERR_MASK)
- return stat;
- if (time_after(jiffies, timeout)) {
- mxcmci_softreset(host);
- mxcmci_set_clk_rate(host, host->clock);
- return STATUS_TIME_OUT_READ;
- }
- if (stat & mask)
- return 0;
- cpu_relax();
- } while (1);
-}
-
-static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes)
-{
- unsigned int stat;
- u32 *buf = _buf;
-
- while (bytes > 3) {
- stat = mxcmci_poll_status(host,
- STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE);
- if (stat)
- return stat;
- *buf++ = readl(host->base + MMC_REG_BUFFER_ACCESS);
- bytes -= 4;
- }
-
- if (bytes) {
- u8 *b = (u8 *)buf;
- u32 tmp;
-
- stat = mxcmci_poll_status(host,
- STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE);
- if (stat)
- return stat;
- tmp = readl(host->base + MMC_REG_BUFFER_ACCESS);
- memcpy(b, &tmp, bytes);
- }
-
- return 0;
-}
-
-static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes)
-{
- unsigned int stat;
- u32 *buf = _buf;
-
- while (bytes > 3) {
- stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
- if (stat)
- return stat;
- writel(*buf++, host->base + MMC_REG_BUFFER_ACCESS);
- bytes -= 4;
- }
-
- if (bytes) {
- u8 *b = (u8 *)buf;
- u32 tmp;
-
- stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
- if (stat)
- return stat;
-
- memcpy(&tmp, b, bytes);
- writel(tmp, host->base + MMC_REG_BUFFER_ACCESS);
- }
-
- stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
- if (stat)
- return stat;
-
- return 0;
-}
-
-static int mxcmci_transfer_data(struct mxcmci_host *host)
-{
- struct mmc_data *data = host->req->data;
- struct scatterlist *sg;
- int stat, i;
-
- host->data = data;
- host->datasize = 0;
-
- if (data->flags & MMC_DATA_READ) {
- for_each_sg(data->sg, sg, data->sg_len, i) {
- stat = mxcmci_pull(host, sg_virt(sg), sg->length);
- if (stat)
- return stat;
- host->datasize += sg->length;
- }
- } else {
- for_each_sg(data->sg, sg, data->sg_len, i) {
- stat = mxcmci_push(host, sg_virt(sg), sg->length);
- if (stat)
- return stat;
- host->datasize += sg->length;
- }
- stat = mxcmci_poll_status(host, STATUS_WRITE_OP_DONE);
- if (stat)
- return stat;
- }
- return 0;
-}
-
-static void mxcmci_datawork(struct work_struct *work)
-{
- struct mxcmci_host *host = container_of(work, struct mxcmci_host,
- datawork);
- int datastat = mxcmci_transfer_data(host);
-
- writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
- host->base + MMC_REG_STATUS);
- mxcmci_finish_data(host, datastat);
-
- if (host->req->stop) {
- if (mxcmci_start_cmd(host, host->req->stop, 0)) {
- mxcmci_finish_request(host, host->req);
- return;
- }
- } else {
- mxcmci_finish_request(host, host->req);
- }
-}
-
-static void mxcmci_data_done(struct mxcmci_host *host, unsigned int stat)
-{
- struct mmc_data *data = host->data;
- int data_error;
-
- if (!data)
- return;
-
- data_error = mxcmci_finish_data(host, stat);
-
- mxcmci_read_response(host, stat);
- host->cmd = NULL;
-
- if (host->req->stop) {
- if (mxcmci_start_cmd(host, host->req->stop, 0)) {
- mxcmci_finish_request(host, host->req);
- return;
- }
- } else {
- mxcmci_finish_request(host, host->req);
- }
-}
-
-static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat)
-{
- mxcmci_read_response(host, stat);
- host->cmd = NULL;
-
- if (!host->data && host->req) {
- mxcmci_finish_request(host, host->req);
- return;
- }
-
- /* For the DMA case the DMA engine handles the data transfer
- * automatically. For non DMA we have to do it ourselves.
- * Don't do it in interrupt context though.
- */
- if (!mxcmci_use_dma(host) && host->data)
- schedule_work(&host->datawork);
-
-}
-
-static irqreturn_t mxcmci_irq(int irq, void *devid)
-{
- struct mxcmci_host *host = devid;
- unsigned long flags;
- bool sdio_irq;
- u32 stat;
-
- stat = readl(host->base + MMC_REG_STATUS);
- writel(stat & ~(STATUS_SDIO_INT_ACTIVE | STATUS_DATA_TRANS_DONE |
- STATUS_WRITE_OP_DONE), host->base + MMC_REG_STATUS);
-
- dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat);
-
- spin_lock_irqsave(&host->lock, flags);
- sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio;
- spin_unlock_irqrestore(&host->lock, flags);
-
- if (mxcmci_use_dma(host) &&
- (stat & (STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE)))
- writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
- host->base + MMC_REG_STATUS);
-
- if (sdio_irq) {
- writel(STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS);
- mmc_signal_sdio_irq(host->mmc);
- }
-
- if (stat & STATUS_END_CMD_RESP)
- mxcmci_cmd_done(host, stat);
-
- if (mxcmci_use_dma(host) &&
- (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE)))
- mxcmci_data_done(host, stat);
-
- if (host->default_irq_mask &&
- (stat & (STATUS_CARD_INSERTION | STATUS_CARD_REMOVAL)))
- mmc_detect_change(host->mmc, msecs_to_jiffies(200));
-
- return IRQ_HANDLED;
-}
-
-static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req)
-{
- struct mxcmci_host *host = mmc_priv(mmc);
- unsigned int cmdat = host->cmdat;
- int error;
-
- WARN_ON(host->req != NULL);
-
- host->req = req;
- host->cmdat &= ~CMD_DAT_CONT_INIT;
-
- if (host->dma)
- host->do_dma = 1;
-
- if (req->data) {
- error = mxcmci_setup_data(host, req->data);
- if (error) {
- req->cmd->error = error;
- goto out;
- }
-
-
- cmdat |= CMD_DAT_CONT_DATA_ENABLE;
-
- if (req->data->flags & MMC_DATA_WRITE)
- cmdat |= CMD_DAT_CONT_WRITE;
- }
-
- error = mxcmci_start_cmd(host, req->cmd, cmdat);
-
-out:
- if (error)
- mxcmci_finish_request(host, req);
-}
-
-static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios)
-{
- unsigned int divider;
- int prescaler = 0;
- unsigned int clk_in = clk_get_rate(host->clk);
-
- while (prescaler <= 0x800) {
- for (divider = 1; divider <= 0xF; divider++) {
- int x;
-
- x = (clk_in / (divider + 1));
-
- if (prescaler)
- x /= (prescaler * 2);
-
- if (x <= clk_ios)
- break;
- }
- if (divider < 0x10)
- break;
-
- if (prescaler == 0)
- prescaler = 1;
- else
- prescaler <<= 1;
- }
-
- writew((prescaler << 4) | divider, host->base + MMC_REG_CLK_RATE);
-
- dev_dbg(mmc_dev(host->mmc), "scaler: %d divider: %d in: %d out: %d\n",
- prescaler, divider, clk_in, clk_ios);
-}
-
-static int mxcmci_setup_dma(struct mmc_host *mmc)
-{
- struct mxcmci_host *host = mmc_priv(mmc);
- struct dma_slave_config *config = &host->dma_slave_config;
-
- config->dst_addr = host->res->start + MMC_REG_BUFFER_ACCESS;
- config->src_addr = host->res->start + MMC_REG_BUFFER_ACCESS;
- config->dst_addr_width = 4;
- config->src_addr_width = 4;
- config->dst_maxburst = host->burstlen;
- config->src_maxburst = host->burstlen;
- config->device_fc = false;
-
- return dmaengine_slave_config(host->dma, config);
-}
-
-static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct mxcmci_host *host = mmc_priv(mmc);
- int burstlen, ret;
-
- /*
- * use burstlen of 64 (16 words) in 4 bit mode (--> reg value 0)
- * use burstlen of 16 (4 words) in 1 bit mode (--> reg value 16)
- */
- if (ios->bus_width == MMC_BUS_WIDTH_4)
- burstlen = 16;
- else
- burstlen = 4;
-
- if (mxcmci_use_dma(host) && burstlen != host->burstlen) {
- host->burstlen = burstlen;
- ret = mxcmci_setup_dma(mmc);
- if (ret) {
- dev_err(mmc_dev(host->mmc),
- "failed to config DMA channel. Falling back to PIO\n");
- dma_release_channel(host->dma);
- host->do_dma = 0;
- host->dma = NULL;
- }
- }
-
- if (ios->bus_width == MMC_BUS_WIDTH_4)
- host->cmdat |= CMD_DAT_CONT_BUS_WIDTH_4;
- else
- host->cmdat &= ~CMD_DAT_CONT_BUS_WIDTH_4;
-
- if (host->power_mode != ios->power_mode) {
- mxcmci_set_power(host, ios->power_mode, ios->vdd);
- host->power_mode = ios->power_mode;
-
- if (ios->power_mode == MMC_POWER_ON)
- host->cmdat |= CMD_DAT_CONT_INIT;
- }
-
- if (ios->clock) {
- mxcmci_set_clk_rate(host, ios->clock);
- writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK);
- } else {
- writew(STR_STP_CLK_STOP_CLK, host->base + MMC_REG_STR_STP_CLK);
- }
-
- host->clock = ios->clock;
-}
-
-static irqreturn_t mxcmci_detect_irq(int irq, void *data)
-{
- struct mmc_host *mmc = data;
-
- dev_dbg(mmc_dev(mmc), "%s\n", __func__);
-
- mmc_detect_change(mmc, msecs_to_jiffies(250));
- return IRQ_HANDLED;
-}
-
-static int mxcmci_get_ro(struct mmc_host *mmc)
-{
- struct mxcmci_host *host = mmc_priv(mmc);
-
- if (host->pdata && host->pdata->get_ro)
- return !!host->pdata->get_ro(mmc_dev(mmc));
- /*
- * Board doesn't support read only detection; let the mmc core
- * decide what to do.
- */
- return -ENOSYS;
-}
-
-static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
- struct mxcmci_host *host = mmc_priv(mmc);
- unsigned long flags;
- u32 int_cntr;
-
- spin_lock_irqsave(&host->lock, flags);
- host->use_sdio = enable;
- int_cntr = readl(host->base + MMC_REG_INT_CNTR);
-
- if (enable)
- int_cntr |= INT_SDIO_IRQ_EN;
- else
- int_cntr &= ~INT_SDIO_IRQ_EN;
-
- writel(int_cntr, host->base + MMC_REG_INT_CNTR);
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void mxcmci_init_card(struct mmc_host *host, struct mmc_card *card)
-{
- /*
- * MX3 SoCs have a silicon bug which corrupts CRC calculation of
- * multi-block transfers when connected SDIO peripheral doesn't
- * drive the BUSY line as required by the specs.
- * One way to prevent this is to only allow 1-bit transfers.
- */
-
- if (cpu_is_mx3() && card->type == MMC_TYPE_SDIO)
- host->caps &= ~MMC_CAP_4_BIT_DATA;
- else
- host->caps |= MMC_CAP_4_BIT_DATA;
-}
-
-static bool filter(struct dma_chan *chan, void *param)
-{
- struct mxcmci_host *host = param;
-
- if (!imx_dma_is_general_purpose(chan))
- return false;
-
- chan->private = &host->dma_data;
-
- return true;
-}
-
-static const struct mmc_host_ops mxcmci_ops = {
- .request = mxcmci_request,
- .set_ios = mxcmci_set_ios,
- .get_ro = mxcmci_get_ro,
- .enable_sdio_irq = mxcmci_enable_sdio_irq,
- .init_card = mxcmci_init_card,
-};
-
-static int mxcmci_probe(struct platform_device *pdev)
-{
- struct mmc_host *mmc;
- struct mxcmci_host *host = NULL;
- struct resource *iores, *r;
- int ret = 0, irq;
- dma_cap_mask_t mask;
-
- pr_info("i.MX SDHC driver\n");
-
- iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
- if (!iores || irq < 0)
- return -EINVAL;
-
- r = request_mem_region(iores->start, resource_size(iores), pdev->name);
- if (!r)
- return -EBUSY;
-
- mmc = mmc_alloc_host(sizeof(struct mxcmci_host), &pdev->dev);
- if (!mmc) {
- ret = -ENOMEM;
- goto out_release_mem;
- }
-
- mmc->ops = &mxcmci_ops;
- mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
-
- /* MMC core transfer sizes tunable parameters */
- 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;
- mmc->max_seg_size = mmc->max_req_size;
-
- host = mmc_priv(mmc);
- host->base = ioremap(r->start, resource_size(r));
- if (!host->base) {
- ret = -ENOMEM;
- goto out_free;
- }
-
- host->mmc = mmc;
- host->pdata = pdev->dev.platform_data;
- spin_lock_init(&host->lock);
-
- mxcmci_init_ocr(host);
-
- if (host->pdata && host->pdata->dat3_card_detect)
- host->default_irq_mask =
- INT_CARD_INSERTION_EN | INT_CARD_REMOVAL_EN;
- else
- host->default_irq_mask = 0;
-
- host->res = r;
- host->irq = irq;
-
- host->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(host->clk)) {
- ret = PTR_ERR(host->clk);
- goto out_iounmap;
- }
- clk_enable(host->clk);
-
- mxcmci_softreset(host);
-
- host->rev_no = readw(host->base + MMC_REG_REV_NO);
- if (host->rev_no != 0x400) {
- ret = -ENODEV;
- dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n",
- host->rev_no);
- goto out_clk_put;
- }
-
- mmc->f_min = clk_get_rate(host->clk) >> 16;
- mmc->f_max = clk_get_rate(host->clk) >> 1;
-
- /* recommended in data sheet */
- writew(0x2db4, host->base + MMC_REG_READ_TO);
-
- writel(host->default_irq_mask, host->base + MMC_REG_INT_CNTR);
-
- r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (r) {
- host->dmareq = r->start;
- host->dma_data.peripheral_type = IMX_DMATYPE_SDHC;
- host->dma_data.priority = DMA_PRIO_LOW;
- host->dma_data.dma_request = host->dmareq;
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- host->dma = dma_request_channel(mask, filter, host);
- if (host->dma)
- mmc->max_seg_size = dma_get_max_seg_size(
- host->dma->device->dev);
- }
-
- if (!host->dma)
- dev_info(mmc_dev(host->mmc), "dma not available. Using PIO\n");
-
- INIT_WORK(&host->datawork, mxcmci_datawork);
-
- ret = request_irq(host->irq, mxcmci_irq, 0, DRIVER_NAME, host);
- if (ret)
- goto out_free_dma;
-
- platform_set_drvdata(pdev, mmc);
-
- if (host->pdata && host->pdata->init) {
- ret = host->pdata->init(&pdev->dev, mxcmci_detect_irq,
- host->mmc);
- if (ret)
- goto out_free_irq;
- }
-
- mmc_add_host(mmc);
-
- return 0;
-
-out_free_irq:
- free_irq(host->irq, host);
-out_free_dma:
- if (host->dma)
- dma_release_channel(host->dma);
-out_clk_put:
- clk_disable(host->clk);
- clk_put(host->clk);
-out_iounmap:
- iounmap(host->base);
-out_free:
- mmc_free_host(mmc);
-out_release_mem:
- release_mem_region(iores->start, resource_size(iores));
- return ret;
-}
-
-static int mxcmci_remove(struct platform_device *pdev)
-{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
- struct mxcmci_host *host = mmc_priv(mmc);
-
- platform_set_drvdata(pdev, NULL);
-
- mmc_remove_host(mmc);
-
- if (host->vcc)
- regulator_put(host->vcc);
-
- if (host->pdata && host->pdata->exit)
- host->pdata->exit(&pdev->dev, mmc);
-
- free_irq(host->irq, host);
- iounmap(host->base);
-
- if (host->dma)
- dma_release_channel(host->dma);
-
- clk_disable(host->clk);
- clk_put(host->clk);
-
- release_mem_region(host->res->start, resource_size(host->res));
-
- mmc_free_host(mmc);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int mxcmci_suspend(struct device *dev)
-{
- struct mmc_host *mmc = dev_get_drvdata(dev);
- struct mxcmci_host *host = mmc_priv(mmc);
- int ret = 0;
-
- if (mmc)
- ret = mmc_suspend_host(mmc);
- clk_disable(host->clk);
-
- return ret;
-}
-
-static int mxcmci_resume(struct device *dev)
-{
- struct mmc_host *mmc = dev_get_drvdata(dev);
- struct mxcmci_host *host = mmc_priv(mmc);
- int ret = 0;
-
- clk_enable(host->clk);
- if (mmc)
- ret = mmc_resume_host(mmc);
-
- return ret;
-}
-
-static const struct dev_pm_ops mxcmci_pm_ops = {
- .suspend = mxcmci_suspend,
- .resume = mxcmci_resume,
-};
-#endif
-
-static struct platform_driver mxcmci_driver = {
- .probe = mxcmci_probe,
- .remove = mxcmci_remove,
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
-#ifdef CONFIG_PM
- .pm = &mxcmci_pm_ops,
-#endif
- }
-};
-
-module_platform_driver(mxcmci_driver);
-
-MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver");
-MODULE_AUTHOR("Sascha Hauer, Pengutronix");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-mmc");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/mxs-mmc.c b/ANDROID_3.4.5/drivers/mmc/host/mxs-mmc.c
deleted file mode 100644
index e3f5af96..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/mxs-mmc.c
+++ /dev/null
@@ -1,873 +0,0 @@
-/*
- * Portions copyright (C) 2003 Russell King, PXA MMCI Driver
- * Portions copyright (C) 2004-2005 Pierre Ossman, W83L51xD SD/MMC driver
- *
- * Copyright 2008 Embedded Alley Solutions, Inc.
- * Copyright 2009-2011 Freescale Semiconductor, Inc.
- *
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmaengine.h>
-#include <linux/highmem.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/completion.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/sdio.h>
-#include <linux/gpio.h>
-#include <linux/regulator/consumer.h>
-#include <linux/module.h>
-#include <linux/fsl/mxs-dma.h>
-
-#include <mach/mxs.h>
-#include <mach/common.h>
-#include <mach/mmc.h>
-
-#define DRIVER_NAME "mxs-mmc"
-
-/* card detect polling timeout */
-#define MXS_MMC_DETECT_TIMEOUT (HZ/2)
-
-#define SSP_VERSION_LATEST 4
-#define ssp_is_old() (host->version < SSP_VERSION_LATEST)
-
-/* SSP registers */
-#define HW_SSP_CTRL0 0x000
-#define BM_SSP_CTRL0_RUN (1 << 29)
-#define BM_SSP_CTRL0_SDIO_IRQ_CHECK (1 << 28)
-#define BM_SSP_CTRL0_IGNORE_CRC (1 << 26)
-#define BM_SSP_CTRL0_READ (1 << 25)
-#define BM_SSP_CTRL0_DATA_XFER (1 << 24)
-#define BP_SSP_CTRL0_BUS_WIDTH (22)
-#define BM_SSP_CTRL0_BUS_WIDTH (0x3 << 22)
-#define BM_SSP_CTRL0_WAIT_FOR_IRQ (1 << 21)
-#define BM_SSP_CTRL0_LONG_RESP (1 << 19)
-#define BM_SSP_CTRL0_GET_RESP (1 << 17)
-#define BM_SSP_CTRL0_ENABLE (1 << 16)
-#define BP_SSP_CTRL0_XFER_COUNT (0)
-#define BM_SSP_CTRL0_XFER_COUNT (0xffff)
-#define HW_SSP_CMD0 0x010
-#define BM_SSP_CMD0_DBL_DATA_RATE_EN (1 << 25)
-#define BM_SSP_CMD0_SLOW_CLKING_EN (1 << 22)
-#define BM_SSP_CMD0_CONT_CLKING_EN (1 << 21)
-#define BM_SSP_CMD0_APPEND_8CYC (1 << 20)
-#define BP_SSP_CMD0_BLOCK_SIZE (16)
-#define BM_SSP_CMD0_BLOCK_SIZE (0xf << 16)
-#define BP_SSP_CMD0_BLOCK_COUNT (8)
-#define BM_SSP_CMD0_BLOCK_COUNT (0xff << 8)
-#define BP_SSP_CMD0_CMD (0)
-#define BM_SSP_CMD0_CMD (0xff)
-#define HW_SSP_CMD1 0x020
-#define HW_SSP_XFER_SIZE 0x030
-#define HW_SSP_BLOCK_SIZE 0x040
-#define BP_SSP_BLOCK_SIZE_BLOCK_COUNT (4)
-#define BM_SSP_BLOCK_SIZE_BLOCK_COUNT (0xffffff << 4)
-#define BP_SSP_BLOCK_SIZE_BLOCK_SIZE (0)
-#define BM_SSP_BLOCK_SIZE_BLOCK_SIZE (0xf)
-#define HW_SSP_TIMING (ssp_is_old() ? 0x050 : 0x070)
-#define BP_SSP_TIMING_TIMEOUT (16)
-#define BM_SSP_TIMING_TIMEOUT (0xffff << 16)
-#define BP_SSP_TIMING_CLOCK_DIVIDE (8)
-#define BM_SSP_TIMING_CLOCK_DIVIDE (0xff << 8)
-#define BP_SSP_TIMING_CLOCK_RATE (0)
-#define BM_SSP_TIMING_CLOCK_RATE (0xff)
-#define HW_SSP_CTRL1 (ssp_is_old() ? 0x060 : 0x080)
-#define BM_SSP_CTRL1_SDIO_IRQ (1 << 31)
-#define BM_SSP_CTRL1_SDIO_IRQ_EN (1 << 30)
-#define BM_SSP_CTRL1_RESP_ERR_IRQ (1 << 29)
-#define BM_SSP_CTRL1_RESP_ERR_IRQ_EN (1 << 28)
-#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ (1 << 27)
-#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN (1 << 26)
-#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ (1 << 25)
-#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN (1 << 24)
-#define BM_SSP_CTRL1_DATA_CRC_IRQ (1 << 23)
-#define BM_SSP_CTRL1_DATA_CRC_IRQ_EN (1 << 22)
-#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ (1 << 21)
-#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ_EN (1 << 20)
-#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ (1 << 17)
-#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN (1 << 16)
-#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ (1 << 15)
-#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ_EN (1 << 14)
-#define BM_SSP_CTRL1_DMA_ENABLE (1 << 13)
-#define BM_SSP_CTRL1_POLARITY (1 << 9)
-#define BP_SSP_CTRL1_WORD_LENGTH (4)
-#define BM_SSP_CTRL1_WORD_LENGTH (0xf << 4)
-#define BP_SSP_CTRL1_SSP_MODE (0)
-#define BM_SSP_CTRL1_SSP_MODE (0xf)
-#define HW_SSP_SDRESP0 (ssp_is_old() ? 0x080 : 0x0a0)
-#define HW_SSP_SDRESP1 (ssp_is_old() ? 0x090 : 0x0b0)
-#define HW_SSP_SDRESP2 (ssp_is_old() ? 0x0a0 : 0x0c0)
-#define HW_SSP_SDRESP3 (ssp_is_old() ? 0x0b0 : 0x0d0)
-#define HW_SSP_STATUS (ssp_is_old() ? 0x0c0 : 0x100)
-#define BM_SSP_STATUS_CARD_DETECT (1 << 28)
-#define BM_SSP_STATUS_SDIO_IRQ (1 << 17)
-#define HW_SSP_VERSION (cpu_is_mx23() ? 0x110 : 0x130)
-#define BP_SSP_VERSION_MAJOR (24)
-
-#define BF_SSP(value, field) (((value) << BP_SSP_##field) & BM_SSP_##field)
-
-#define MXS_MMC_IRQ_BITS (BM_SSP_CTRL1_SDIO_IRQ | \
- BM_SSP_CTRL1_RESP_ERR_IRQ | \
- BM_SSP_CTRL1_RESP_TIMEOUT_IRQ | \
- BM_SSP_CTRL1_DATA_TIMEOUT_IRQ | \
- BM_SSP_CTRL1_DATA_CRC_IRQ | \
- BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ | \
- BM_SSP_CTRL1_RECV_TIMEOUT_IRQ | \
- BM_SSP_CTRL1_FIFO_OVERRUN_IRQ)
-
-#define SSP_PIO_NUM 3
-
-struct mxs_mmc_host {
- struct mmc_host *mmc;
- struct mmc_request *mrq;
- struct mmc_command *cmd;
- struct mmc_data *data;
-
- void __iomem *base;
- int irq;
- struct resource *res;
- struct resource *dma_res;
- struct clk *clk;
- unsigned int clk_rate;
-
- struct dma_chan *dmach;
- struct mxs_dma_data dma_data;
- unsigned int dma_dir;
- enum dma_transfer_direction slave_dirn;
- u32 ssp_pio_words[SSP_PIO_NUM];
-
- unsigned int version;
- unsigned char bus_width;
- spinlock_t lock;
- int sdio_irq_en;
-};
-
-static int mxs_mmc_get_ro(struct mmc_host *mmc)
-{
- struct mxs_mmc_host *host = mmc_priv(mmc);
- struct mxs_mmc_platform_data *pdata =
- mmc_dev(host->mmc)->platform_data;
-
- if (!pdata)
- return -EFAULT;
-
- if (!gpio_is_valid(pdata->wp_gpio))
- return -EINVAL;
-
- return gpio_get_value(pdata->wp_gpio);
-}
-
-static int mxs_mmc_get_cd(struct mmc_host *mmc)
-{
- struct mxs_mmc_host *host = mmc_priv(mmc);
-
- return !(readl(host->base + HW_SSP_STATUS) &
- BM_SSP_STATUS_CARD_DETECT);
-}
-
-static void mxs_mmc_reset(struct mxs_mmc_host *host)
-{
- u32 ctrl0, ctrl1;
-
- mxs_reset_block(host->base);
-
- ctrl0 = BM_SSP_CTRL0_IGNORE_CRC;
- ctrl1 = BF_SSP(0x3, CTRL1_SSP_MODE) |
- BF_SSP(0x7, CTRL1_WORD_LENGTH) |
- BM_SSP_CTRL1_DMA_ENABLE |
- BM_SSP_CTRL1_POLARITY |
- BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN |
- BM_SSP_CTRL1_DATA_CRC_IRQ_EN |
- BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN |
- BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN |
- BM_SSP_CTRL1_RESP_ERR_IRQ_EN;
-
- writel(BF_SSP(0xffff, TIMING_TIMEOUT) |
- BF_SSP(2, TIMING_CLOCK_DIVIDE) |
- BF_SSP(0, TIMING_CLOCK_RATE),
- host->base + HW_SSP_TIMING);
-
- if (host->sdio_irq_en) {
- ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK;
- ctrl1 |= BM_SSP_CTRL1_SDIO_IRQ_EN;
- }
-
- writel(ctrl0, host->base + HW_SSP_CTRL0);
- writel(ctrl1, host->base + HW_SSP_CTRL1);
-}
-
-static void mxs_mmc_start_cmd(struct mxs_mmc_host *host,
- struct mmc_command *cmd);
-
-static void mxs_mmc_request_done(struct mxs_mmc_host *host)
-{
- struct mmc_command *cmd = host->cmd;
- struct mmc_data *data = host->data;
- struct mmc_request *mrq = host->mrq;
-
- if (mmc_resp_type(cmd) & MMC_RSP_PRESENT) {
- if (mmc_resp_type(cmd) & MMC_RSP_136) {
- cmd->resp[3] = readl(host->base + HW_SSP_SDRESP0);
- cmd->resp[2] = readl(host->base + HW_SSP_SDRESP1);
- cmd->resp[1] = readl(host->base + HW_SSP_SDRESP2);
- cmd->resp[0] = readl(host->base + HW_SSP_SDRESP3);
- } else {
- cmd->resp[0] = readl(host->base + HW_SSP_SDRESP0);
- }
- }
-
- if (data) {
- dma_unmap_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, host->dma_dir);
- /*
- * If there was an error on any block, we mark all
- * data blocks as being in error.
- */
- if (!data->error)
- data->bytes_xfered = data->blocks * data->blksz;
- else
- data->bytes_xfered = 0;
-
- host->data = NULL;
- if (mrq->stop) {
- mxs_mmc_start_cmd(host, mrq->stop);
- return;
- }
- }
-
- host->mrq = NULL;
- mmc_request_done(host->mmc, mrq);
-}
-
-static void mxs_mmc_dma_irq_callback(void *param)
-{
- struct mxs_mmc_host *host = param;
-
- mxs_mmc_request_done(host);
-}
-
-static irqreturn_t mxs_mmc_irq_handler(int irq, void *dev_id)
-{
- struct mxs_mmc_host *host = dev_id;
- struct mmc_command *cmd = host->cmd;
- struct mmc_data *data = host->data;
- u32 stat;
-
- spin_lock(&host->lock);
-
- stat = readl(host->base + HW_SSP_CTRL1);
- writel(stat & MXS_MMC_IRQ_BITS,
- host->base + HW_SSP_CTRL1 + MXS_CLR_ADDR);
-
- if ((stat & BM_SSP_CTRL1_SDIO_IRQ) && (stat & BM_SSP_CTRL1_SDIO_IRQ_EN))
- mmc_signal_sdio_irq(host->mmc);
-
- spin_unlock(&host->lock);
-
- if (stat & BM_SSP_CTRL1_RESP_TIMEOUT_IRQ)
- cmd->error = -ETIMEDOUT;
- else if (stat & BM_SSP_CTRL1_RESP_ERR_IRQ)
- cmd->error = -EIO;
-
- if (data) {
- if (stat & (BM_SSP_CTRL1_DATA_TIMEOUT_IRQ |
- BM_SSP_CTRL1_RECV_TIMEOUT_IRQ))
- data->error = -ETIMEDOUT;
- else if (stat & BM_SSP_CTRL1_DATA_CRC_IRQ)
- data->error = -EILSEQ;
- else if (stat & (BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ |
- BM_SSP_CTRL1_FIFO_OVERRUN_IRQ))
- data->error = -EIO;
- }
-
- return IRQ_HANDLED;
-}
-
-static struct dma_async_tx_descriptor *mxs_mmc_prep_dma(
- struct mxs_mmc_host *host, unsigned long flags)
-{
- struct dma_async_tx_descriptor *desc;
- struct mmc_data *data = host->data;
- struct scatterlist * sgl;
- unsigned int sg_len;
-
- if (data) {
- /* data */
- dma_map_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, host->dma_dir);
- sgl = data->sg;
- sg_len = data->sg_len;
- } else {
- /* pio */
- sgl = (struct scatterlist *) host->ssp_pio_words;
- sg_len = SSP_PIO_NUM;
- }
-
- desc = dmaengine_prep_slave_sg(host->dmach,
- sgl, sg_len, host->slave_dirn, flags);
- if (desc) {
- desc->callback = mxs_mmc_dma_irq_callback;
- desc->callback_param = host;
- } else {
- if (data)
- dma_unmap_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, host->dma_dir);
- }
-
- return desc;
-}
-
-static void mxs_mmc_bc(struct mxs_mmc_host *host)
-{
- struct mmc_command *cmd = host->cmd;
- struct dma_async_tx_descriptor *desc;
- u32 ctrl0, cmd0, cmd1;
-
- ctrl0 = BM_SSP_CTRL0_ENABLE | BM_SSP_CTRL0_IGNORE_CRC;
- cmd0 = BF_SSP(cmd->opcode, CMD0_CMD) | BM_SSP_CMD0_APPEND_8CYC;
- cmd1 = cmd->arg;
-
- if (host->sdio_irq_en) {
- ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK;
- cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN;
- }
-
- host->ssp_pio_words[0] = ctrl0;
- host->ssp_pio_words[1] = cmd0;
- host->ssp_pio_words[2] = cmd1;
- host->dma_dir = DMA_NONE;
- host->slave_dirn = DMA_TRANS_NONE;
- desc = mxs_mmc_prep_dma(host, DMA_CTRL_ACK);
- if (!desc)
- goto out;
-
- dmaengine_submit(desc);
- dma_async_issue_pending(host->dmach);
- return;
-
-out:
- dev_warn(mmc_dev(host->mmc),
- "%s: failed to prep dma\n", __func__);
-}
-
-static void mxs_mmc_ac(struct mxs_mmc_host *host)
-{
- struct mmc_command *cmd = host->cmd;
- struct dma_async_tx_descriptor *desc;
- u32 ignore_crc, get_resp, long_resp;
- u32 ctrl0, cmd0, cmd1;
-
- ignore_crc = (mmc_resp_type(cmd) & MMC_RSP_CRC) ?
- 0 : BM_SSP_CTRL0_IGNORE_CRC;
- get_resp = (mmc_resp_type(cmd) & MMC_RSP_PRESENT) ?
- BM_SSP_CTRL0_GET_RESP : 0;
- long_resp = (mmc_resp_type(cmd) & MMC_RSP_136) ?
- BM_SSP_CTRL0_LONG_RESP : 0;
-
- ctrl0 = BM_SSP_CTRL0_ENABLE | ignore_crc | get_resp | long_resp;
- cmd0 = BF_SSP(cmd->opcode, CMD0_CMD);
- cmd1 = cmd->arg;
-
- if (host->sdio_irq_en) {
- ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK;
- cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN;
- }
-
- host->ssp_pio_words[0] = ctrl0;
- host->ssp_pio_words[1] = cmd0;
- host->ssp_pio_words[2] = cmd1;
- host->dma_dir = DMA_NONE;
- host->slave_dirn = DMA_TRANS_NONE;
- desc = mxs_mmc_prep_dma(host, DMA_CTRL_ACK);
- if (!desc)
- goto out;
-
- dmaengine_submit(desc);
- dma_async_issue_pending(host->dmach);
- return;
-
-out:
- dev_warn(mmc_dev(host->mmc),
- "%s: failed to prep dma\n", __func__);
-}
-
-static unsigned short mxs_ns_to_ssp_ticks(unsigned clock_rate, unsigned ns)
-{
- const unsigned int ssp_timeout_mul = 4096;
- /*
- * Calculate ticks in ms since ns are large numbers
- * and might overflow
- */
- const unsigned int clock_per_ms = clock_rate / 1000;
- const unsigned int ms = ns / 1000;
- const unsigned int ticks = ms * clock_per_ms;
- const unsigned int ssp_ticks = ticks / ssp_timeout_mul;
-
- WARN_ON(ssp_ticks == 0);
- return ssp_ticks;
-}
-
-static void mxs_mmc_adtc(struct mxs_mmc_host *host)
-{
- struct mmc_command *cmd = host->cmd;
- struct mmc_data *data = cmd->data;
- struct dma_async_tx_descriptor *desc;
- struct scatterlist *sgl = data->sg, *sg;
- unsigned int sg_len = data->sg_len;
- int i;
-
- unsigned short dma_data_dir, timeout;
- enum dma_transfer_direction slave_dirn;
- unsigned int data_size = 0, log2_blksz;
- unsigned int blocks = data->blocks;
-
- u32 ignore_crc, get_resp, long_resp, read;
- u32 ctrl0, cmd0, cmd1, val;
-
- ignore_crc = (mmc_resp_type(cmd) & MMC_RSP_CRC) ?
- 0 : BM_SSP_CTRL0_IGNORE_CRC;
- get_resp = (mmc_resp_type(cmd) & MMC_RSP_PRESENT) ?
- BM_SSP_CTRL0_GET_RESP : 0;
- long_resp = (mmc_resp_type(cmd) & MMC_RSP_136) ?
- BM_SSP_CTRL0_LONG_RESP : 0;
-
- if (data->flags & MMC_DATA_WRITE) {
- dma_data_dir = DMA_TO_DEVICE;
- slave_dirn = DMA_MEM_TO_DEV;
- read = 0;
- } else {
- dma_data_dir = DMA_FROM_DEVICE;
- slave_dirn = DMA_DEV_TO_MEM;
- read = BM_SSP_CTRL0_READ;
- }
-
- ctrl0 = BF_SSP(host->bus_width, CTRL0_BUS_WIDTH) |
- ignore_crc | get_resp | long_resp |
- BM_SSP_CTRL0_DATA_XFER | read |
- BM_SSP_CTRL0_WAIT_FOR_IRQ |
- BM_SSP_CTRL0_ENABLE;
-
- cmd0 = BF_SSP(cmd->opcode, CMD0_CMD);
-
- /* get logarithm to base 2 of block size for setting register */
- log2_blksz = ilog2(data->blksz);
-
- /*
- * take special care of the case that data size from data->sg
- * is not equal to blocks x blksz
- */
- for_each_sg(sgl, sg, sg_len, i)
- data_size += sg->length;
-
- if (data_size != data->blocks * data->blksz)
- blocks = 1;
-
- /* xfer count, block size and count need to be set differently */
- if (ssp_is_old()) {
- ctrl0 |= BF_SSP(data_size, CTRL0_XFER_COUNT);
- cmd0 |= BF_SSP(log2_blksz, CMD0_BLOCK_SIZE) |
- BF_SSP(blocks - 1, CMD0_BLOCK_COUNT);
- } else {
- writel(data_size, host->base + HW_SSP_XFER_SIZE);
- writel(BF_SSP(log2_blksz, BLOCK_SIZE_BLOCK_SIZE) |
- BF_SSP(blocks - 1, BLOCK_SIZE_BLOCK_COUNT),
- host->base + HW_SSP_BLOCK_SIZE);
- }
-
- if ((cmd->opcode == MMC_STOP_TRANSMISSION) ||
- (cmd->opcode == SD_IO_RW_EXTENDED))
- cmd0 |= BM_SSP_CMD0_APPEND_8CYC;
-
- cmd1 = cmd->arg;
-
- if (host->sdio_irq_en) {
- ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK;
- cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN;
- }
-
- /* set the timeout count */
- timeout = mxs_ns_to_ssp_ticks(host->clk_rate, data->timeout_ns);
- val = readl(host->base + HW_SSP_TIMING);
- val &= ~(BM_SSP_TIMING_TIMEOUT);
- val |= BF_SSP(timeout, TIMING_TIMEOUT);
- writel(val, host->base + HW_SSP_TIMING);
-
- /* pio */
- host->ssp_pio_words[0] = ctrl0;
- host->ssp_pio_words[1] = cmd0;
- host->ssp_pio_words[2] = cmd1;
- host->dma_dir = DMA_NONE;
- host->slave_dirn = DMA_TRANS_NONE;
- desc = mxs_mmc_prep_dma(host, 0);
- if (!desc)
- goto out;
-
- /* append data sg */
- WARN_ON(host->data != NULL);
- host->data = data;
- host->dma_dir = dma_data_dir;
- host->slave_dirn = slave_dirn;
- desc = mxs_mmc_prep_dma(host, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc)
- goto out;
-
- dmaengine_submit(desc);
- dma_async_issue_pending(host->dmach);
- return;
-out:
- dev_warn(mmc_dev(host->mmc),
- "%s: failed to prep dma\n", __func__);
-}
-
-static void mxs_mmc_start_cmd(struct mxs_mmc_host *host,
- struct mmc_command *cmd)
-{
- host->cmd = cmd;
-
- switch (mmc_cmd_type(cmd)) {
- case MMC_CMD_BC:
- mxs_mmc_bc(host);
- break;
- case MMC_CMD_BCR:
- mxs_mmc_ac(host);
- break;
- case MMC_CMD_AC:
- mxs_mmc_ac(host);
- break;
- case MMC_CMD_ADTC:
- mxs_mmc_adtc(host);
- break;
- default:
- dev_warn(mmc_dev(host->mmc),
- "%s: unknown MMC command\n", __func__);
- break;
- }
-}
-
-static void mxs_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct mxs_mmc_host *host = mmc_priv(mmc);
-
- WARN_ON(host->mrq != NULL);
- host->mrq = mrq;
- mxs_mmc_start_cmd(host, mrq->cmd);
-}
-
-static void mxs_mmc_set_clk_rate(struct mxs_mmc_host *host, unsigned int rate)
-{
- unsigned int ssp_clk, ssp_sck;
- u32 clock_divide, clock_rate;
- u32 val;
-
- ssp_clk = clk_get_rate(host->clk);
-
- for (clock_divide = 2; clock_divide <= 254; clock_divide += 2) {
- clock_rate = DIV_ROUND_UP(ssp_clk, rate * clock_divide);
- clock_rate = (clock_rate > 0) ? clock_rate - 1 : 0;
- if (clock_rate <= 255)
- break;
- }
-
- if (clock_divide > 254) {
- dev_err(mmc_dev(host->mmc),
- "%s: cannot set clock to %d\n", __func__, rate);
- return;
- }
-
- ssp_sck = ssp_clk / clock_divide / (1 + clock_rate);
-
- val = readl(host->base + HW_SSP_TIMING);
- val &= ~(BM_SSP_TIMING_CLOCK_DIVIDE | BM_SSP_TIMING_CLOCK_RATE);
- val |= BF_SSP(clock_divide, TIMING_CLOCK_DIVIDE);
- val |= BF_SSP(clock_rate, TIMING_CLOCK_RATE);
- writel(val, host->base + HW_SSP_TIMING);
-
- host->clk_rate = ssp_sck;
-
- dev_dbg(mmc_dev(host->mmc),
- "%s: clock_divide %d, clock_rate %d, ssp_clk %d, rate_actual %d, rate_requested %d\n",
- __func__, clock_divide, clock_rate, ssp_clk, ssp_sck, rate);
-}
-
-static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct mxs_mmc_host *host = mmc_priv(mmc);
-
- if (ios->bus_width == MMC_BUS_WIDTH_8)
- host->bus_width = 2;
- else if (ios->bus_width == MMC_BUS_WIDTH_4)
- host->bus_width = 1;
- else
- host->bus_width = 0;
-
- if (ios->clock)
- mxs_mmc_set_clk_rate(host, ios->clock);
-}
-
-static void mxs_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
- struct mxs_mmc_host *host = mmc_priv(mmc);
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
-
- host->sdio_irq_en = enable;
-
- if (enable) {
- writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK,
- host->base + HW_SSP_CTRL0 + MXS_SET_ADDR);
- writel(BM_SSP_CTRL1_SDIO_IRQ_EN,
- host->base + HW_SSP_CTRL1 + MXS_SET_ADDR);
-
- if (readl(host->base + HW_SSP_STATUS) & BM_SSP_STATUS_SDIO_IRQ)
- mmc_signal_sdio_irq(host->mmc);
-
- } else {
- writel(BM_SSP_CTRL0_SDIO_IRQ_CHECK,
- host->base + HW_SSP_CTRL0 + MXS_CLR_ADDR);
- writel(BM_SSP_CTRL1_SDIO_IRQ_EN,
- host->base + HW_SSP_CTRL1 + MXS_CLR_ADDR);
- }
-
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static const struct mmc_host_ops mxs_mmc_ops = {
- .request = mxs_mmc_request,
- .get_ro = mxs_mmc_get_ro,
- .get_cd = mxs_mmc_get_cd,
- .set_ios = mxs_mmc_set_ios,
- .enable_sdio_irq = mxs_mmc_enable_sdio_irq,
-};
-
-static bool mxs_mmc_dma_filter(struct dma_chan *chan, void *param)
-{
- struct mxs_mmc_host *host = param;
-
- if (!mxs_dma_is_apbh(chan))
- return false;
-
- if (chan->chan_id != host->dma_res->start)
- return false;
-
- chan->private = &host->dma_data;
-
- return true;
-}
-
-static int mxs_mmc_probe(struct platform_device *pdev)
-{
- struct mxs_mmc_host *host;
- struct mmc_host *mmc;
- struct resource *iores, *dmares, *r;
- struct mxs_mmc_platform_data *pdata;
- int ret = 0, irq_err, irq_dma;
- dma_cap_mask_t mask;
-
- iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- irq_err = platform_get_irq(pdev, 0);
- irq_dma = platform_get_irq(pdev, 1);
- if (!iores || !dmares || irq_err < 0 || irq_dma < 0)
- return -EINVAL;
-
- r = request_mem_region(iores->start, resource_size(iores), pdev->name);
- if (!r)
- return -EBUSY;
-
- mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev);
- if (!mmc) {
- ret = -ENOMEM;
- goto out_release_mem;
- }
-
- host = mmc_priv(mmc);
- host->base = ioremap(r->start, resource_size(r));
- if (!host->base) {
- ret = -ENOMEM;
- goto out_mmc_free;
- }
-
- /* only major verion does matter */
- host->version = readl(host->base + HW_SSP_VERSION) >>
- BP_SSP_VERSION_MAJOR;
-
- host->mmc = mmc;
- host->res = r;
- host->dma_res = dmares;
- host->irq = irq_err;
- host->sdio_irq_en = 0;
-
- host->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(host->clk)) {
- ret = PTR_ERR(host->clk);
- goto out_iounmap;
- }
- clk_prepare_enable(host->clk);
-
- mxs_mmc_reset(host);
-
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
- host->dma_data.chan_irq = irq_dma;
- host->dmach = dma_request_channel(mask, mxs_mmc_dma_filter, host);
- if (!host->dmach) {
- dev_err(mmc_dev(host->mmc),
- "%s: failed to request dma\n", __func__);
- goto out_clk_put;
- }
-
- /* set mmc core parameters */
- mmc->ops = &mxs_mmc_ops;
- mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
- MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL;
-
- pdata = mmc_dev(host->mmc)->platform_data;
- if (pdata) {
- if (pdata->flags & SLOTF_8_BIT_CAPABLE)
- mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
- if (pdata->flags & SLOTF_4_BIT_CAPABLE)
- mmc->caps |= MMC_CAP_4_BIT_DATA;
- }
-
- mmc->f_min = 400000;
- mmc->f_max = 288000000;
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-
- mmc->max_segs = 52;
- mmc->max_blk_size = 1 << 0xf;
- mmc->max_blk_count = (ssp_is_old()) ? 0xff : 0xffffff;
- mmc->max_req_size = (ssp_is_old()) ? 0xffff : 0xffffffff;
- mmc->max_seg_size = dma_get_max_seg_size(host->dmach->device->dev);
-
- platform_set_drvdata(pdev, mmc);
-
- ret = request_irq(host->irq, mxs_mmc_irq_handler, 0, DRIVER_NAME, host);
- if (ret)
- goto out_free_dma;
-
- spin_lock_init(&host->lock);
-
- ret = mmc_add_host(mmc);
- if (ret)
- goto out_free_irq;
-
- dev_info(mmc_dev(host->mmc), "initialized\n");
-
- return 0;
-
-out_free_irq:
- free_irq(host->irq, host);
-out_free_dma:
- if (host->dmach)
- dma_release_channel(host->dmach);
-out_clk_put:
- clk_disable_unprepare(host->clk);
- clk_put(host->clk);
-out_iounmap:
- iounmap(host->base);
-out_mmc_free:
- mmc_free_host(mmc);
-out_release_mem:
- release_mem_region(iores->start, resource_size(iores));
- return ret;
-}
-
-static int mxs_mmc_remove(struct platform_device *pdev)
-{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
- struct mxs_mmc_host *host = mmc_priv(mmc);
- struct resource *res = host->res;
-
- mmc_remove_host(mmc);
-
- free_irq(host->irq, host);
-
- platform_set_drvdata(pdev, NULL);
-
- if (host->dmach)
- dma_release_channel(host->dmach);
-
- clk_disable_unprepare(host->clk);
- clk_put(host->clk);
-
- iounmap(host->base);
-
- mmc_free_host(mmc);
-
- release_mem_region(res->start, resource_size(res));
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int mxs_mmc_suspend(struct device *dev)
-{
- struct mmc_host *mmc = dev_get_drvdata(dev);
- struct mxs_mmc_host *host = mmc_priv(mmc);
- int ret = 0;
-
- ret = mmc_suspend_host(mmc);
-
- clk_disable_unprepare(host->clk);
-
- return ret;
-}
-
-static int mxs_mmc_resume(struct device *dev)
-{
- struct mmc_host *mmc = dev_get_drvdata(dev);
- struct mxs_mmc_host *host = mmc_priv(mmc);
- int ret = 0;
-
- clk_prepare_enable(host->clk);
-
- ret = mmc_resume_host(mmc);
-
- return ret;
-}
-
-static const struct dev_pm_ops mxs_mmc_pm_ops = {
- .suspend = mxs_mmc_suspend,
- .resume = mxs_mmc_resume,
-};
-#endif
-
-static struct platform_driver mxs_mmc_driver = {
- .probe = mxs_mmc_probe,
- .remove = mxs_mmc_remove,
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
-#ifdef CONFIG_PM
- .pm = &mxs_mmc_pm_ops,
-#endif
- },
-};
-
-module_platform_driver(mxs_mmc_driver);
-
-MODULE_DESCRIPTION("FREESCALE MXS MMC peripheral");
-MODULE_AUTHOR("Freescale Semiconductor");
-MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/of_mmc_spi.c b/ANDROID_3.4.5/drivers/mmc/host/of_mmc_spi.c
deleted file mode 100644
index 1534b582..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/of_mmc_spi.c
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * OpenFirmware bindings for the MMC-over-SPI driver
- *
- * Copyright (c) MontaVista Software, Inc. 2008.
- *
- * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/irq.h>
-#include <linux/gpio.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/of_irq.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/mmc_spi.h>
-#include <linux/mmc/core.h>
-#include <linux/mmc/host.h>
-
-/* For archs that don't support NO_IRQ (such as mips), provide a dummy value */
-#ifndef NO_IRQ
-#define NO_IRQ 0
-#endif
-
-MODULE_LICENSE("GPL");
-
-enum {
- CD_GPIO = 0,
- WP_GPIO,
- NUM_GPIOS,
-};
-
-struct of_mmc_spi {
- int gpios[NUM_GPIOS];
- bool alow_gpios[NUM_GPIOS];
- int detect_irq;
- struct mmc_spi_platform_data pdata;
-};
-
-static struct of_mmc_spi *to_of_mmc_spi(struct device *dev)
-{
- return container_of(dev->platform_data, struct of_mmc_spi, pdata);
-}
-
-static int of_mmc_spi_read_gpio(struct device *dev, int gpio_num)
-{
- struct of_mmc_spi *oms = to_of_mmc_spi(dev);
- bool active_low = oms->alow_gpios[gpio_num];
- bool value = gpio_get_value(oms->gpios[gpio_num]);
-
- return active_low ^ value;
-}
-
-static int of_mmc_spi_get_cd(struct device *dev)
-{
- return of_mmc_spi_read_gpio(dev, CD_GPIO);
-}
-
-static int of_mmc_spi_get_ro(struct device *dev)
-{
- return of_mmc_spi_read_gpio(dev, WP_GPIO);
-}
-
-static int of_mmc_spi_init(struct device *dev,
- irqreturn_t (*irqhandler)(int, void *), void *mmc)
-{
- struct of_mmc_spi *oms = to_of_mmc_spi(dev);
-
- return request_threaded_irq(oms->detect_irq, NULL, irqhandler, 0,
- dev_name(dev), mmc);
-}
-
-static void of_mmc_spi_exit(struct device *dev, void *mmc)
-{
- struct of_mmc_spi *oms = to_of_mmc_spi(dev);
-
- free_irq(oms->detect_irq, mmc);
-}
-
-struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi)
-{
- struct device *dev = &spi->dev;
- struct device_node *np = dev->of_node;
- struct of_mmc_spi *oms;
- const u32 *voltage_ranges;
- int num_ranges;
- int i;
- int ret = -EINVAL;
-
- if (dev->platform_data || !np)
- return dev->platform_data;
-
- oms = kzalloc(sizeof(*oms), GFP_KERNEL);
- if (!oms)
- return NULL;
-
- voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges);
- num_ranges = num_ranges / sizeof(*voltage_ranges) / 2;
- if (!voltage_ranges || !num_ranges) {
- dev_err(dev, "OF: voltage-ranges unspecified\n");
- goto err_ocr;
- }
-
- for (i = 0; i < num_ranges; i++) {
- const int j = i * 2;
- u32 mask;
-
- mask = mmc_vddrange_to_ocrmask(be32_to_cpu(voltage_ranges[j]),
- be32_to_cpu(voltage_ranges[j + 1]));
- if (!mask) {
- ret = -EINVAL;
- dev_err(dev, "OF: voltage-range #%d is invalid\n", i);
- goto err_ocr;
- }
- oms->pdata.ocr_mask |= mask;
- }
-
- for (i = 0; i < ARRAY_SIZE(oms->gpios); i++) {
- enum of_gpio_flags gpio_flags;
-
- oms->gpios[i] = of_get_gpio_flags(np, i, &gpio_flags);
- if (!gpio_is_valid(oms->gpios[i]))
- continue;
-
- ret = gpio_request(oms->gpios[i], dev_name(dev));
- if (ret < 0) {
- oms->gpios[i] = -EINVAL;
- continue;
- }
-
- if (gpio_flags & OF_GPIO_ACTIVE_LOW)
- oms->alow_gpios[i] = true;
- }
-
- if (gpio_is_valid(oms->gpios[CD_GPIO]))
- oms->pdata.get_cd = of_mmc_spi_get_cd;
- if (gpio_is_valid(oms->gpios[WP_GPIO]))
- oms->pdata.get_ro = of_mmc_spi_get_ro;
-
- oms->detect_irq = irq_of_parse_and_map(np, 0);
- if (oms->detect_irq != NO_IRQ) {
- oms->pdata.init = of_mmc_spi_init;
- oms->pdata.exit = of_mmc_spi_exit;
- } else {
- oms->pdata.caps |= MMC_CAP_NEEDS_POLL;
- }
-
- dev->platform_data = &oms->pdata;
- return dev->platform_data;
-err_ocr:
- kfree(oms);
- return NULL;
-}
-EXPORT_SYMBOL(mmc_spi_get_pdata);
-
-void mmc_spi_put_pdata(struct spi_device *spi)
-{
- struct device *dev = &spi->dev;
- struct device_node *np = dev->of_node;
- struct of_mmc_spi *oms = to_of_mmc_spi(dev);
- int i;
-
- if (!dev->platform_data || !np)
- return;
-
- for (i = 0; i < ARRAY_SIZE(oms->gpios); i++) {
- if (gpio_is_valid(oms->gpios[i]))
- gpio_free(oms->gpios[i]);
- }
- kfree(oms);
- dev->platform_data = NULL;
-}
-EXPORT_SYMBOL(mmc_spi_put_pdata);
diff --git a/ANDROID_3.4.5/drivers/mmc/host/omap.c b/ANDROID_3.4.5/drivers/mmc/host/omap.c
deleted file mode 100644
index 887c0e59..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/omap.c
+++ /dev/null
@@ -1,1637 +0,0 @@
-/*
- * linux/drivers/mmc/host/omap.c
- *
- * Copyright (C) 2004 Nokia Corporation
- * Written by Tuukka Tikkanen and Juha Yrjölä<juha.yrjola@nokia.com>
- * Misc hacks here and there by Tony Lindgren <tony@atomide.com>
- * Other hacks (DMA, SD, etc) by David Brownell
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/timer.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/clk.h>
-#include <linux/scatterlist.h>
-#include <linux/i2c/tps65010.h>
-#include <linux/slab.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include <plat/board.h>
-#include <plat/mmc.h>
-#include <asm/gpio.h>
-#include <plat/dma.h>
-#include <plat/mux.h>
-#include <plat/fpga.h>
-
-#define OMAP_MMC_REG_CMD 0x00
-#define OMAP_MMC_REG_ARGL 0x01
-#define OMAP_MMC_REG_ARGH 0x02
-#define OMAP_MMC_REG_CON 0x03
-#define OMAP_MMC_REG_STAT 0x04
-#define OMAP_MMC_REG_IE 0x05
-#define OMAP_MMC_REG_CTO 0x06
-#define OMAP_MMC_REG_DTO 0x07
-#define OMAP_MMC_REG_DATA 0x08
-#define OMAP_MMC_REG_BLEN 0x09
-#define OMAP_MMC_REG_NBLK 0x0a
-#define OMAP_MMC_REG_BUF 0x0b
-#define OMAP_MMC_REG_SDIO 0x0d
-#define OMAP_MMC_REG_REV 0x0f
-#define OMAP_MMC_REG_RSP0 0x10
-#define OMAP_MMC_REG_RSP1 0x11
-#define OMAP_MMC_REG_RSP2 0x12
-#define OMAP_MMC_REG_RSP3 0x13
-#define OMAP_MMC_REG_RSP4 0x14
-#define OMAP_MMC_REG_RSP5 0x15
-#define OMAP_MMC_REG_RSP6 0x16
-#define OMAP_MMC_REG_RSP7 0x17
-#define OMAP_MMC_REG_IOSR 0x18
-#define OMAP_MMC_REG_SYSC 0x19
-#define OMAP_MMC_REG_SYSS 0x1a
-
-#define OMAP_MMC_STAT_CARD_ERR (1 << 14)
-#define OMAP_MMC_STAT_CARD_IRQ (1 << 13)
-#define OMAP_MMC_STAT_OCR_BUSY (1 << 12)
-#define OMAP_MMC_STAT_A_EMPTY (1 << 11)
-#define OMAP_MMC_STAT_A_FULL (1 << 10)
-#define OMAP_MMC_STAT_CMD_CRC (1 << 8)
-#define OMAP_MMC_STAT_CMD_TOUT (1 << 7)
-#define OMAP_MMC_STAT_DATA_CRC (1 << 6)
-#define OMAP_MMC_STAT_DATA_TOUT (1 << 5)
-#define OMAP_MMC_STAT_END_BUSY (1 << 4)
-#define OMAP_MMC_STAT_END_OF_DATA (1 << 3)
-#define OMAP_MMC_STAT_CARD_BUSY (1 << 2)
-#define OMAP_MMC_STAT_END_OF_CMD (1 << 0)
-
-#define OMAP_MMC_REG(host, reg) (OMAP_MMC_REG_##reg << (host)->reg_shift)
-#define OMAP_MMC_READ(host, reg) __raw_readw((host)->virt_base + OMAP_MMC_REG(host, reg))
-#define OMAP_MMC_WRITE(host, reg, val) __raw_writew((val), (host)->virt_base + OMAP_MMC_REG(host, reg))
-
-/*
- * Command types
- */
-#define OMAP_MMC_CMDTYPE_BC 0
-#define OMAP_MMC_CMDTYPE_BCR 1
-#define OMAP_MMC_CMDTYPE_AC 2
-#define OMAP_MMC_CMDTYPE_ADTC 3
-
-
-#define DRIVER_NAME "mmci-omap"
-
-/* Specifies how often in millisecs to poll for card status changes
- * when the cover switch is open */
-#define OMAP_MMC_COVER_POLL_DELAY 500
-
-struct mmc_omap_host;
-
-struct mmc_omap_slot {
- int id;
- unsigned int vdd;
- u16 saved_con;
- u16 bus_mode;
- unsigned int fclk_freq;
- unsigned powered:1;
-
- struct tasklet_struct cover_tasklet;
- struct timer_list cover_timer;
- unsigned cover_open;
-
- struct mmc_request *mrq;
- struct mmc_omap_host *host;
- struct mmc_host *mmc;
- struct omap_mmc_slot_data *pdata;
-};
-
-struct mmc_omap_host {
- int initialized;
- int suspended;
- struct mmc_request * mrq;
- struct mmc_command * cmd;
- struct mmc_data * data;
- struct mmc_host * mmc;
- struct device * dev;
- unsigned char id; /* 16xx chips have 2 MMC blocks */
- struct clk * iclk;
- struct clk * fclk;
- struct resource *mem_res;
- void __iomem *virt_base;
- unsigned int phys_base;
- int irq;
- unsigned char bus_mode;
- unsigned char hw_bus_mode;
- unsigned int reg_shift;
-
- struct work_struct cmd_abort_work;
- unsigned abort:1;
- struct timer_list cmd_abort_timer;
-
- struct work_struct slot_release_work;
- struct mmc_omap_slot *next_slot;
- struct work_struct send_stop_work;
- struct mmc_data *stop_data;
-
- unsigned int sg_len;
- int sg_idx;
- u16 * buffer;
- u32 buffer_bytes_left;
- u32 total_bytes_left;
-
- unsigned use_dma:1;
- unsigned brs_received:1, dma_done:1;
- unsigned dma_is_read:1;
- unsigned dma_in_use:1;
- int dma_ch;
- spinlock_t dma_lock;
- struct timer_list dma_timer;
- unsigned dma_len;
-
- struct mmc_omap_slot *slots[OMAP_MMC_MAX_SLOTS];
- struct mmc_omap_slot *current_slot;
- spinlock_t slot_lock;
- wait_queue_head_t slot_wq;
- int nr_slots;
-
- struct timer_list clk_timer;
- spinlock_t clk_lock; /* for changing enabled state */
- unsigned int fclk_enabled:1;
-
- struct omap_mmc_platform_data *pdata;
-};
-
-static struct workqueue_struct *mmc_omap_wq;
-
-static void mmc_omap_fclk_offdelay(struct mmc_omap_slot *slot)
-{
- unsigned long tick_ns;
-
- if (slot != NULL && slot->host->fclk_enabled && slot->fclk_freq > 0) {
- tick_ns = (1000000000 + slot->fclk_freq - 1) / slot->fclk_freq;
- ndelay(8 * tick_ns);
- }
-}
-
-static void mmc_omap_fclk_enable(struct mmc_omap_host *host, unsigned int enable)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&host->clk_lock, flags);
- if (host->fclk_enabled != enable) {
- host->fclk_enabled = enable;
- if (enable)
- clk_enable(host->fclk);
- else
- clk_disable(host->fclk);
- }
- spin_unlock_irqrestore(&host->clk_lock, flags);
-}
-
-static void mmc_omap_select_slot(struct mmc_omap_slot *slot, int claimed)
-{
- struct mmc_omap_host *host = slot->host;
- unsigned long flags;
-
- if (claimed)
- goto no_claim;
- spin_lock_irqsave(&host->slot_lock, flags);
- while (host->mmc != NULL) {
- spin_unlock_irqrestore(&host->slot_lock, flags);
- wait_event(host->slot_wq, host->mmc == NULL);
- spin_lock_irqsave(&host->slot_lock, flags);
- }
- host->mmc = slot->mmc;
- spin_unlock_irqrestore(&host->slot_lock, flags);
-no_claim:
- del_timer(&host->clk_timer);
- if (host->current_slot != slot || !claimed)
- mmc_omap_fclk_offdelay(host->current_slot);
-
- if (host->current_slot != slot) {
- OMAP_MMC_WRITE(host, CON, slot->saved_con & 0xFC00);
- if (host->pdata->switch_slot != NULL)
- host->pdata->switch_slot(mmc_dev(slot->mmc), slot->id);
- host->current_slot = slot;
- }
-
- if (claimed) {
- mmc_omap_fclk_enable(host, 1);
-
- /* Doing the dummy read here seems to work around some bug
- * at least in OMAP24xx silicon where the command would not
- * start after writing the CMD register. Sigh. */
- OMAP_MMC_READ(host, CON);
-
- OMAP_MMC_WRITE(host, CON, slot->saved_con);
- } else
- mmc_omap_fclk_enable(host, 0);
-}
-
-static void mmc_omap_start_request(struct mmc_omap_host *host,
- struct mmc_request *req);
-
-static void mmc_omap_slot_release_work(struct work_struct *work)
-{
- struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
- slot_release_work);
- struct mmc_omap_slot *next_slot = host->next_slot;
- struct mmc_request *rq;
-
- host->next_slot = NULL;
- mmc_omap_select_slot(next_slot, 1);
-
- rq = next_slot->mrq;
- next_slot->mrq = NULL;
- mmc_omap_start_request(host, rq);
-}
-
-static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled)
-{
- struct mmc_omap_host *host = slot->host;
- unsigned long flags;
- int i;
-
- BUG_ON(slot == NULL || host->mmc == NULL);
-
- if (clk_enabled)
- /* Keeps clock running for at least 8 cycles on valid freq */
- mod_timer(&host->clk_timer, jiffies + HZ/10);
- else {
- del_timer(&host->clk_timer);
- mmc_omap_fclk_offdelay(slot);
- mmc_omap_fclk_enable(host, 0);
- }
-
- spin_lock_irqsave(&host->slot_lock, flags);
- /* Check for any pending requests */
- for (i = 0; i < host->nr_slots; i++) {
- struct mmc_omap_slot *new_slot;
-
- if (host->slots[i] == NULL || host->slots[i]->mrq == NULL)
- continue;
-
- BUG_ON(host->next_slot != NULL);
- new_slot = host->slots[i];
- /* The current slot should not have a request in queue */
- BUG_ON(new_slot == host->current_slot);
-
- host->next_slot = new_slot;
- host->mmc = new_slot->mmc;
- spin_unlock_irqrestore(&host->slot_lock, flags);
- queue_work(mmc_omap_wq, &host->slot_release_work);
- return;
- }
-
- host->mmc = NULL;
- wake_up(&host->slot_wq);
- spin_unlock_irqrestore(&host->slot_lock, flags);
-}
-
-static inline
-int mmc_omap_cover_is_open(struct mmc_omap_slot *slot)
-{
- if (slot->pdata->get_cover_state)
- return slot->pdata->get_cover_state(mmc_dev(slot->mmc),
- slot->id);
- return 0;
-}
-
-static ssize_t
-mmc_omap_show_cover_switch(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
- struct mmc_omap_slot *slot = mmc_priv(mmc);
-
- return sprintf(buf, "%s\n", mmc_omap_cover_is_open(slot) ? "open" :
- "closed");
-}
-
-static DEVICE_ATTR(cover_switch, S_IRUGO, mmc_omap_show_cover_switch, NULL);
-
-static ssize_t
-mmc_omap_show_slot_name(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
- struct mmc_omap_slot *slot = mmc_priv(mmc);
-
- return sprintf(buf, "%s\n", slot->pdata->name);
-}
-
-static DEVICE_ATTR(slot_name, S_IRUGO, mmc_omap_show_slot_name, NULL);
-
-static void
-mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
-{
- u32 cmdreg;
- u32 resptype;
- u32 cmdtype;
-
- host->cmd = cmd;
-
- resptype = 0;
- cmdtype = 0;
-
- /* Our hardware needs to know exact type */
- switch (mmc_resp_type(cmd)) {
- case MMC_RSP_NONE:
- break;
- case MMC_RSP_R1:
- case MMC_RSP_R1B:
- /* resp 1, 1b, 6, 7 */
- resptype = 1;
- break;
- case MMC_RSP_R2:
- resptype = 2;
- break;
- case MMC_RSP_R3:
- resptype = 3;
- break;
- default:
- dev_err(mmc_dev(host->mmc), "Invalid response type: %04x\n", mmc_resp_type(cmd));
- break;
- }
-
- if (mmc_cmd_type(cmd) == MMC_CMD_ADTC) {
- cmdtype = OMAP_MMC_CMDTYPE_ADTC;
- } else if (mmc_cmd_type(cmd) == MMC_CMD_BC) {
- cmdtype = OMAP_MMC_CMDTYPE_BC;
- } else if (mmc_cmd_type(cmd) == MMC_CMD_BCR) {
- cmdtype = OMAP_MMC_CMDTYPE_BCR;
- } else {
- cmdtype = OMAP_MMC_CMDTYPE_AC;
- }
-
- cmdreg = cmd->opcode | (resptype << 8) | (cmdtype << 12);
-
- if (host->current_slot->bus_mode == MMC_BUSMODE_OPENDRAIN)
- cmdreg |= 1 << 6;
-
- if (cmd->flags & MMC_RSP_BUSY)
- cmdreg |= 1 << 11;
-
- if (host->data && !(host->data->flags & MMC_DATA_WRITE))
- cmdreg |= 1 << 15;
-
- mod_timer(&host->cmd_abort_timer, jiffies + HZ/2);
-
- OMAP_MMC_WRITE(host, CTO, 200);
- OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff);
- OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16);
- OMAP_MMC_WRITE(host, IE,
- OMAP_MMC_STAT_A_EMPTY | OMAP_MMC_STAT_A_FULL |
- OMAP_MMC_STAT_CMD_CRC | OMAP_MMC_STAT_CMD_TOUT |
- OMAP_MMC_STAT_DATA_CRC | OMAP_MMC_STAT_DATA_TOUT |
- OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR |
- OMAP_MMC_STAT_END_OF_DATA);
- OMAP_MMC_WRITE(host, CMD, cmdreg);
-}
-
-static void
-mmc_omap_release_dma(struct mmc_omap_host *host, struct mmc_data *data,
- int abort)
-{
- enum dma_data_direction dma_data_dir;
-
- BUG_ON(host->dma_ch < 0);
- if (data->error)
- omap_stop_dma(host->dma_ch);
- /* Release DMA channel lazily */
- mod_timer(&host->dma_timer, jiffies + HZ);
- if (data->flags & MMC_DATA_WRITE)
- dma_data_dir = DMA_TO_DEVICE;
- else
- dma_data_dir = DMA_FROM_DEVICE;
- dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->sg_len,
- dma_data_dir);
-}
-
-static void mmc_omap_send_stop_work(struct work_struct *work)
-{
- struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
- send_stop_work);
- struct mmc_omap_slot *slot = host->current_slot;
- struct mmc_data *data = host->stop_data;
- unsigned long tick_ns;
-
- tick_ns = (1000000000 + slot->fclk_freq - 1)/slot->fclk_freq;
- ndelay(8*tick_ns);
-
- mmc_omap_start_command(host, data->stop);
-}
-
-static void
-mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
-{
- if (host->dma_in_use)
- mmc_omap_release_dma(host, data, data->error);
-
- host->data = NULL;
- host->sg_len = 0;
-
- /* NOTE: MMC layer will sometimes poll-wait CMD13 next, issuing
- * dozens of requests until the card finishes writing data.
- * It'd be cheaper to just wait till an EOFB interrupt arrives...
- */
-
- if (!data->stop) {
- struct mmc_host *mmc;
-
- host->mrq = NULL;
- mmc = host->mmc;
- mmc_omap_release_slot(host->current_slot, 1);
- mmc_request_done(mmc, data->mrq);
- return;
- }
-
- host->stop_data = data;
- queue_work(mmc_omap_wq, &host->send_stop_work);
-}
-
-static void
-mmc_omap_send_abort(struct mmc_omap_host *host, int maxloops)
-{
- struct mmc_omap_slot *slot = host->current_slot;
- unsigned int restarts, passes, timeout;
- u16 stat = 0;
-
- /* Sending abort takes 80 clocks. Have some extra and round up */
- timeout = (120*1000000 + slot->fclk_freq - 1)/slot->fclk_freq;
- restarts = 0;
- while (restarts < maxloops) {
- OMAP_MMC_WRITE(host, STAT, 0xFFFF);
- OMAP_MMC_WRITE(host, CMD, (3 << 12) | (1 << 7));
-
- passes = 0;
- while (passes < timeout) {
- stat = OMAP_MMC_READ(host, STAT);
- if (stat & OMAP_MMC_STAT_END_OF_CMD)
- goto out;
- udelay(1);
- passes++;
- }
-
- restarts++;
- }
-out:
- OMAP_MMC_WRITE(host, STAT, stat);
-}
-
-static void
-mmc_omap_abort_xfer(struct mmc_omap_host *host, struct mmc_data *data)
-{
- if (host->dma_in_use)
- mmc_omap_release_dma(host, data, 1);
-
- host->data = NULL;
- host->sg_len = 0;
-
- mmc_omap_send_abort(host, 10000);
-}
-
-static void
-mmc_omap_end_of_data(struct mmc_omap_host *host, struct mmc_data *data)
-{
- unsigned long flags;
- int done;
-
- if (!host->dma_in_use) {
- mmc_omap_xfer_done(host, data);
- return;
- }
- done = 0;
- spin_lock_irqsave(&host->dma_lock, flags);
- if (host->dma_done)
- done = 1;
- else
- host->brs_received = 1;
- spin_unlock_irqrestore(&host->dma_lock, flags);
- if (done)
- mmc_omap_xfer_done(host, data);
-}
-
-static void
-mmc_omap_dma_timer(unsigned long data)
-{
- struct mmc_omap_host *host = (struct mmc_omap_host *) data;
-
- BUG_ON(host->dma_ch < 0);
- omap_free_dma(host->dma_ch);
- host->dma_ch = -1;
-}
-
-static void
-mmc_omap_dma_done(struct mmc_omap_host *host, struct mmc_data *data)
-{
- unsigned long flags;
- int done;
-
- done = 0;
- spin_lock_irqsave(&host->dma_lock, flags);
- if (host->brs_received)
- done = 1;
- else
- host->dma_done = 1;
- spin_unlock_irqrestore(&host->dma_lock, flags);
- if (done)
- mmc_omap_xfer_done(host, data);
-}
-
-static void
-mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
-{
- host->cmd = NULL;
-
- del_timer(&host->cmd_abort_timer);
-
- if (cmd->flags & MMC_RSP_PRESENT) {
- if (cmd->flags & MMC_RSP_136) {
- /* response type 2 */
- cmd->resp[3] =
- OMAP_MMC_READ(host, RSP0) |
- (OMAP_MMC_READ(host, RSP1) << 16);
- cmd->resp[2] =
- OMAP_MMC_READ(host, RSP2) |
- (OMAP_MMC_READ(host, RSP3) << 16);
- cmd->resp[1] =
- OMAP_MMC_READ(host, RSP4) |
- (OMAP_MMC_READ(host, RSP5) << 16);
- cmd->resp[0] =
- OMAP_MMC_READ(host, RSP6) |
- (OMAP_MMC_READ(host, RSP7) << 16);
- } else {
- /* response types 1, 1b, 3, 4, 5, 6 */
- cmd->resp[0] =
- OMAP_MMC_READ(host, RSP6) |
- (OMAP_MMC_READ(host, RSP7) << 16);
- }
- }
-
- if (host->data == NULL || cmd->error) {
- struct mmc_host *mmc;
-
- if (host->data != NULL)
- mmc_omap_abort_xfer(host, host->data);
- host->mrq = NULL;
- mmc = host->mmc;
- mmc_omap_release_slot(host->current_slot, 1);
- mmc_request_done(mmc, cmd->mrq);
- }
-}
-
-/*
- * Abort stuck command. Can occur when card is removed while it is being
- * read.
- */
-static void mmc_omap_abort_command(struct work_struct *work)
-{
- struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
- cmd_abort_work);
- BUG_ON(!host->cmd);
-
- dev_dbg(mmc_dev(host->mmc), "Aborting stuck command CMD%d\n",
- host->cmd->opcode);
-
- if (host->cmd->error == 0)
- host->cmd->error = -ETIMEDOUT;
-
- if (host->data == NULL) {
- struct mmc_command *cmd;
- struct mmc_host *mmc;
-
- cmd = host->cmd;
- host->cmd = NULL;
- mmc_omap_send_abort(host, 10000);
-
- host->mrq = NULL;
- mmc = host->mmc;
- mmc_omap_release_slot(host->current_slot, 1);
- mmc_request_done(mmc, cmd->mrq);
- } else
- mmc_omap_cmd_done(host, host->cmd);
-
- host->abort = 0;
- enable_irq(host->irq);
-}
-
-static void
-mmc_omap_cmd_timer(unsigned long data)
-{
- struct mmc_omap_host *host = (struct mmc_omap_host *) data;
- unsigned long flags;
-
- spin_lock_irqsave(&host->slot_lock, flags);
- if (host->cmd != NULL && !host->abort) {
- OMAP_MMC_WRITE(host, IE, 0);
- disable_irq(host->irq);
- host->abort = 1;
- queue_work(mmc_omap_wq, &host->cmd_abort_work);
- }
- spin_unlock_irqrestore(&host->slot_lock, flags);
-}
-
-/* PIO only */
-static void
-mmc_omap_sg_to_buf(struct mmc_omap_host *host)
-{
- struct scatterlist *sg;
-
- sg = host->data->sg + host->sg_idx;
- host->buffer_bytes_left = sg->length;
- host->buffer = sg_virt(sg);
- if (host->buffer_bytes_left > host->total_bytes_left)
- host->buffer_bytes_left = host->total_bytes_left;
-}
-
-static void
-mmc_omap_clk_timer(unsigned long data)
-{
- struct mmc_omap_host *host = (struct mmc_omap_host *) data;
-
- mmc_omap_fclk_enable(host, 0);
-}
-
-/* PIO only */
-static void
-mmc_omap_xfer_data(struct mmc_omap_host *host, int write)
-{
- int n;
-
- if (host->buffer_bytes_left == 0) {
- host->sg_idx++;
- BUG_ON(host->sg_idx == host->sg_len);
- mmc_omap_sg_to_buf(host);
- }
- n = 64;
- if (n > host->buffer_bytes_left)
- n = host->buffer_bytes_left;
- host->buffer_bytes_left -= n;
- host->total_bytes_left -= n;
- host->data->bytes_xfered += n;
-
- if (write) {
- __raw_writesw(host->virt_base + OMAP_MMC_REG(host, DATA), host->buffer, n);
- } else {
- __raw_readsw(host->virt_base + OMAP_MMC_REG(host, DATA), host->buffer, n);
- }
-}
-
-static inline void mmc_omap_report_irq(u16 status)
-{
- static const char *mmc_omap_status_bits[] = {
- "EOC", "CD", "CB", "BRS", "EOFB", "DTO", "DCRC", "CTO",
- "CCRC", "CRW", "AF", "AE", "OCRB", "CIRQ", "CERR"
- };
- int i, c = 0;
-
- for (i = 0; i < ARRAY_SIZE(mmc_omap_status_bits); i++)
- if (status & (1 << i)) {
- if (c)
- printk(" ");
- printk("%s", mmc_omap_status_bits[i]);
- c++;
- }
-}
-
-static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
-{
- struct mmc_omap_host * host = (struct mmc_omap_host *)dev_id;
- u16 status;
- int end_command;
- int end_transfer;
- int transfer_error, cmd_error;
-
- if (host->cmd == NULL && host->data == NULL) {
- status = OMAP_MMC_READ(host, STAT);
- dev_info(mmc_dev(host->slots[0]->mmc),
- "Spurious IRQ 0x%04x\n", status);
- if (status != 0) {
- OMAP_MMC_WRITE(host, STAT, status);
- OMAP_MMC_WRITE(host, IE, 0);
- }
- return IRQ_HANDLED;
- }
-
- end_command = 0;
- end_transfer = 0;
- transfer_error = 0;
- cmd_error = 0;
-
- while ((status = OMAP_MMC_READ(host, STAT)) != 0) {
- int cmd;
-
- OMAP_MMC_WRITE(host, STAT, status);
- if (host->cmd != NULL)
- cmd = host->cmd->opcode;
- else
- cmd = -1;
-#ifdef CONFIG_MMC_DEBUG
- dev_dbg(mmc_dev(host->mmc), "MMC IRQ %04x (CMD %d): ",
- status, cmd);
- mmc_omap_report_irq(status);
- printk("\n");
-#endif
- if (host->total_bytes_left) {
- if ((status & OMAP_MMC_STAT_A_FULL) ||
- (status & OMAP_MMC_STAT_END_OF_DATA))
- mmc_omap_xfer_data(host, 0);
- if (status & OMAP_MMC_STAT_A_EMPTY)
- mmc_omap_xfer_data(host, 1);
- }
-
- if (status & OMAP_MMC_STAT_END_OF_DATA)
- end_transfer = 1;
-
- if (status & OMAP_MMC_STAT_DATA_TOUT) {
- dev_dbg(mmc_dev(host->mmc), "data timeout (CMD%d)\n",
- cmd);
- if (host->data) {
- host->data->error = -ETIMEDOUT;
- transfer_error = 1;
- }
- }
-
- if (status & OMAP_MMC_STAT_DATA_CRC) {
- if (host->data) {
- host->data->error = -EILSEQ;
- dev_dbg(mmc_dev(host->mmc),
- "data CRC error, bytes left %d\n",
- host->total_bytes_left);
- transfer_error = 1;
- } else {
- dev_dbg(mmc_dev(host->mmc), "data CRC error\n");
- }
- }
-
- if (status & OMAP_MMC_STAT_CMD_TOUT) {
- /* Timeouts are routine with some commands */
- if (host->cmd) {
- struct mmc_omap_slot *slot =
- host->current_slot;
- if (slot == NULL ||
- !mmc_omap_cover_is_open(slot))
- dev_err(mmc_dev(host->mmc),
- "command timeout (CMD%d)\n",
- cmd);
- host->cmd->error = -ETIMEDOUT;
- end_command = 1;
- cmd_error = 1;
- }
- }
-
- if (status & OMAP_MMC_STAT_CMD_CRC) {
- if (host->cmd) {
- dev_err(mmc_dev(host->mmc),
- "command CRC error (CMD%d, arg 0x%08x)\n",
- cmd, host->cmd->arg);
- host->cmd->error = -EILSEQ;
- end_command = 1;
- cmd_error = 1;
- } else
- dev_err(mmc_dev(host->mmc),
- "command CRC error without cmd?\n");
- }
-
- if (status & OMAP_MMC_STAT_CARD_ERR) {
- dev_dbg(mmc_dev(host->mmc),
- "ignoring card status error (CMD%d)\n",
- cmd);
- end_command = 1;
- }
-
- /*
- * NOTE: On 1610 the END_OF_CMD may come too early when
- * starting a write
- */
- if ((status & OMAP_MMC_STAT_END_OF_CMD) &&
- (!(status & OMAP_MMC_STAT_A_EMPTY))) {
- end_command = 1;
- }
- }
-
- if (cmd_error && host->data) {
- del_timer(&host->cmd_abort_timer);
- host->abort = 1;
- OMAP_MMC_WRITE(host, IE, 0);
- disable_irq_nosync(host->irq);
- queue_work(mmc_omap_wq, &host->cmd_abort_work);
- return IRQ_HANDLED;
- }
-
- if (end_command && host->cmd)
- mmc_omap_cmd_done(host, host->cmd);
- if (host->data != NULL) {
- if (transfer_error)
- mmc_omap_xfer_done(host, host->data);
- else if (end_transfer)
- mmc_omap_end_of_data(host, host->data);
- }
-
- return IRQ_HANDLED;
-}
-
-void omap_mmc_notify_cover_event(struct device *dev, int num, int is_closed)
-{
- int cover_open;
- struct mmc_omap_host *host = dev_get_drvdata(dev);
- struct mmc_omap_slot *slot = host->slots[num];
-
- BUG_ON(num >= host->nr_slots);
-
- /* Other subsystems can call in here before we're initialised. */
- if (host->nr_slots == 0 || !host->slots[num])
- return;
-
- cover_open = mmc_omap_cover_is_open(slot);
- if (cover_open != slot->cover_open) {
- slot->cover_open = cover_open;
- sysfs_notify(&slot->mmc->class_dev.kobj, NULL, "cover_switch");
- }
-
- tasklet_hi_schedule(&slot->cover_tasklet);
-}
-
-static void mmc_omap_cover_timer(unsigned long arg)
-{
- struct mmc_omap_slot *slot = (struct mmc_omap_slot *) arg;
- tasklet_schedule(&slot->cover_tasklet);
-}
-
-static void mmc_omap_cover_handler(unsigned long param)
-{
- struct mmc_omap_slot *slot = (struct mmc_omap_slot *)param;
- int cover_open = mmc_omap_cover_is_open(slot);
-
- mmc_detect_change(slot->mmc, 0);
- if (!cover_open)
- return;
-
- /*
- * If no card is inserted, we postpone polling until
- * the cover has been closed.
- */
- if (slot->mmc->card == NULL || !mmc_card_present(slot->mmc->card))
- return;
-
- mod_timer(&slot->cover_timer,
- jiffies + msecs_to_jiffies(OMAP_MMC_COVER_POLL_DELAY));
-}
-
-/* Prepare to transfer the next segment of a scatterlist */
-static void
-mmc_omap_prepare_dma(struct mmc_omap_host *host, struct mmc_data *data)
-{
- int dma_ch = host->dma_ch;
- unsigned long data_addr;
- u16 buf, frame;
- u32 count;
- struct scatterlist *sg = &data->sg[host->sg_idx];
- int src_port = 0;
- int dst_port = 0;
- int sync_dev = 0;
-
- data_addr = host->phys_base + OMAP_MMC_REG(host, DATA);
- frame = data->blksz;
- count = sg_dma_len(sg);
-
- if ((data->blocks == 1) && (count > data->blksz))
- count = frame;
-
- host->dma_len = count;
-
- /* FIFO is 16x2 bytes on 15xx, and 32x2 bytes on 16xx and 24xx.
- * Use 16 or 32 word frames when the blocksize is at least that large.
- * Blocksize is usually 512 bytes; but not for some SD reads.
- */
- if (cpu_is_omap15xx() && frame > 32)
- frame = 32;
- else if (frame > 64)
- frame = 64;
- count /= frame;
- frame >>= 1;
-
- if (!(data->flags & MMC_DATA_WRITE)) {
- buf = 0x800f | ((frame - 1) << 8);
-
- if (cpu_class_is_omap1()) {
- src_port = OMAP_DMA_PORT_TIPB;
- dst_port = OMAP_DMA_PORT_EMIFF;
- }
- if (cpu_is_omap24xx())
- sync_dev = OMAP24XX_DMA_MMC1_RX;
-
- omap_set_dma_src_params(dma_ch, src_port,
- OMAP_DMA_AMODE_CONSTANT,
- data_addr, 0, 0);
- omap_set_dma_dest_params(dma_ch, dst_port,
- OMAP_DMA_AMODE_POST_INC,
- sg_dma_address(sg), 0, 0);
- omap_set_dma_dest_data_pack(dma_ch, 1);
- omap_set_dma_dest_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4);
- } else {
- buf = 0x0f80 | ((frame - 1) << 0);
-
- if (cpu_class_is_omap1()) {
- src_port = OMAP_DMA_PORT_EMIFF;
- dst_port = OMAP_DMA_PORT_TIPB;
- }
- if (cpu_is_omap24xx())
- sync_dev = OMAP24XX_DMA_MMC1_TX;
-
- omap_set_dma_dest_params(dma_ch, dst_port,
- OMAP_DMA_AMODE_CONSTANT,
- data_addr, 0, 0);
- omap_set_dma_src_params(dma_ch, src_port,
- OMAP_DMA_AMODE_POST_INC,
- sg_dma_address(sg), 0, 0);
- omap_set_dma_src_data_pack(dma_ch, 1);
- omap_set_dma_src_burst_mode(dma_ch, OMAP_DMA_DATA_BURST_4);
- }
-
- /* Max limit for DMA frame count is 0xffff */
- BUG_ON(count > 0xffff);
-
- OMAP_MMC_WRITE(host, BUF, buf);
- omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S16,
- frame, count, OMAP_DMA_SYNC_FRAME,
- sync_dev, 0);
-}
-
-/* A scatterlist segment completed */
-static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data)
-{
- struct mmc_omap_host *host = (struct mmc_omap_host *) data;
- struct mmc_data *mmcdat = host->data;
-
- if (unlikely(host->dma_ch < 0)) {
- dev_err(mmc_dev(host->mmc),
- "DMA callback while DMA not enabled\n");
- return;
- }
- /* FIXME: We really should do something to _handle_ the errors */
- if (ch_status & OMAP1_DMA_TOUT_IRQ) {
- dev_err(mmc_dev(host->mmc),"DMA timeout\n");
- return;
- }
- if (ch_status & OMAP_DMA_DROP_IRQ) {
- dev_err(mmc_dev(host->mmc), "DMA sync error\n");
- return;
- }
- if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) {
- return;
- }
- mmcdat->bytes_xfered += host->dma_len;
- host->sg_idx++;
- if (host->sg_idx < host->sg_len) {
- mmc_omap_prepare_dma(host, host->data);
- omap_start_dma(host->dma_ch);
- } else
- mmc_omap_dma_done(host, host->data);
-}
-
-static int mmc_omap_get_dma_channel(struct mmc_omap_host *host, struct mmc_data *data)
-{
- const char *dma_dev_name;
- int sync_dev, dma_ch, is_read, r;
-
- is_read = !(data->flags & MMC_DATA_WRITE);
- del_timer_sync(&host->dma_timer);
- if (host->dma_ch >= 0) {
- if (is_read == host->dma_is_read)
- return 0;
- omap_free_dma(host->dma_ch);
- host->dma_ch = -1;
- }
-
- if (is_read) {
- if (host->id == 0) {
- sync_dev = OMAP_DMA_MMC_RX;
- dma_dev_name = "MMC1 read";
- } else {
- sync_dev = OMAP_DMA_MMC2_RX;
- dma_dev_name = "MMC2 read";
- }
- } else {
- if (host->id == 0) {
- sync_dev = OMAP_DMA_MMC_TX;
- dma_dev_name = "MMC1 write";
- } else {
- sync_dev = OMAP_DMA_MMC2_TX;
- dma_dev_name = "MMC2 write";
- }
- }
- r = omap_request_dma(sync_dev, dma_dev_name, mmc_omap_dma_cb,
- host, &dma_ch);
- if (r != 0) {
- dev_dbg(mmc_dev(host->mmc), "omap_request_dma() failed with %d\n", r);
- return r;
- }
- host->dma_ch = dma_ch;
- host->dma_is_read = is_read;
-
- return 0;
-}
-
-static inline void set_cmd_timeout(struct mmc_omap_host *host, struct mmc_request *req)
-{
- u16 reg;
-
- reg = OMAP_MMC_READ(host, SDIO);
- reg &= ~(1 << 5);
- OMAP_MMC_WRITE(host, SDIO, reg);
- /* Set maximum timeout */
- OMAP_MMC_WRITE(host, CTO, 0xff);
-}
-
-static inline void set_data_timeout(struct mmc_omap_host *host, struct mmc_request *req)
-{
- unsigned int timeout, cycle_ns;
- u16 reg;
-
- cycle_ns = 1000000000 / host->current_slot->fclk_freq;
- timeout = req->data->timeout_ns / cycle_ns;
- timeout += req->data->timeout_clks;
-
- /* Check if we need to use timeout multiplier register */
- reg = OMAP_MMC_READ(host, SDIO);
- if (timeout > 0xffff) {
- reg |= (1 << 5);
- timeout /= 1024;
- } else
- reg &= ~(1 << 5);
- OMAP_MMC_WRITE(host, SDIO, reg);
- OMAP_MMC_WRITE(host, DTO, timeout);
-}
-
-static void
-mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
-{
- struct mmc_data *data = req->data;
- int i, use_dma, block_size;
- unsigned sg_len;
-
- host->data = data;
- if (data == NULL) {
- OMAP_MMC_WRITE(host, BLEN, 0);
- OMAP_MMC_WRITE(host, NBLK, 0);
- OMAP_MMC_WRITE(host, BUF, 0);
- host->dma_in_use = 0;
- set_cmd_timeout(host, req);
- return;
- }
-
- block_size = data->blksz;
-
- OMAP_MMC_WRITE(host, NBLK, data->blocks - 1);
- OMAP_MMC_WRITE(host, BLEN, block_size - 1);
- set_data_timeout(host, req);
-
- /* cope with calling layer confusion; it issues "single
- * block" writes using multi-block scatterlists.
- */
- sg_len = (data->blocks == 1) ? 1 : data->sg_len;
-
- /* Only do DMA for entire blocks */
- use_dma = host->use_dma;
- if (use_dma) {
- for (i = 0; i < sg_len; i++) {
- if ((data->sg[i].length % block_size) != 0) {
- use_dma = 0;
- break;
- }
- }
- }
-
- host->sg_idx = 0;
- if (use_dma) {
- if (mmc_omap_get_dma_channel(host, data) == 0) {
- enum dma_data_direction dma_data_dir;
-
- if (data->flags & MMC_DATA_WRITE)
- dma_data_dir = DMA_TO_DEVICE;
- else
- dma_data_dir = DMA_FROM_DEVICE;
-
- host->sg_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
- sg_len, dma_data_dir);
- host->total_bytes_left = 0;
- mmc_omap_prepare_dma(host, req->data);
- host->brs_received = 0;
- host->dma_done = 0;
- host->dma_in_use = 1;
- } else
- use_dma = 0;
- }
-
- /* Revert to PIO? */
- if (!use_dma) {
- OMAP_MMC_WRITE(host, BUF, 0x1f1f);
- host->total_bytes_left = data->blocks * block_size;
- host->sg_len = sg_len;
- mmc_omap_sg_to_buf(host);
- host->dma_in_use = 0;
- }
-}
-
-static void mmc_omap_start_request(struct mmc_omap_host *host,
- struct mmc_request *req)
-{
- BUG_ON(host->mrq != NULL);
-
- host->mrq = req;
-
- /* only touch fifo AFTER the controller readies it */
- mmc_omap_prepare_data(host, req);
- mmc_omap_start_command(host, req->cmd);
- if (host->dma_in_use)
- omap_start_dma(host->dma_ch);
-}
-
-static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req)
-{
- struct mmc_omap_slot *slot = mmc_priv(mmc);
- struct mmc_omap_host *host = slot->host;
- unsigned long flags;
-
- spin_lock_irqsave(&host->slot_lock, flags);
- if (host->mmc != NULL) {
- BUG_ON(slot->mrq != NULL);
- slot->mrq = req;
- spin_unlock_irqrestore(&host->slot_lock, flags);
- return;
- } else
- host->mmc = mmc;
- spin_unlock_irqrestore(&host->slot_lock, flags);
- mmc_omap_select_slot(slot, 1);
- mmc_omap_start_request(host, req);
-}
-
-static void mmc_omap_set_power(struct mmc_omap_slot *slot, int power_on,
- int vdd)
-{
- struct mmc_omap_host *host;
-
- host = slot->host;
-
- if (slot->pdata->set_power != NULL)
- slot->pdata->set_power(mmc_dev(slot->mmc), slot->id, power_on,
- vdd);
-
- if (cpu_is_omap24xx()) {
- u16 w;
-
- if (power_on) {
- w = OMAP_MMC_READ(host, CON);
- OMAP_MMC_WRITE(host, CON, w | (1 << 11));
- } else {
- w = OMAP_MMC_READ(host, CON);
- OMAP_MMC_WRITE(host, CON, w & ~(1 << 11));
- }
- }
-}
-
-static int mmc_omap_calc_divisor(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct mmc_omap_slot *slot = mmc_priv(mmc);
- struct mmc_omap_host *host = slot->host;
- int func_clk_rate = clk_get_rate(host->fclk);
- int dsor;
-
- if (ios->clock == 0)
- return 0;
-
- dsor = func_clk_rate / ios->clock;
- if (dsor < 1)
- dsor = 1;
-
- if (func_clk_rate / dsor > ios->clock)
- dsor++;
-
- if (dsor > 250)
- dsor = 250;
-
- slot->fclk_freq = func_clk_rate / dsor;
-
- if (ios->bus_width == MMC_BUS_WIDTH_4)
- dsor |= 1 << 15;
-
- return dsor;
-}
-
-static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct mmc_omap_slot *slot = mmc_priv(mmc);
- struct mmc_omap_host *host = slot->host;
- int i, dsor;
- int clk_enabled;
-
- mmc_omap_select_slot(slot, 0);
-
- dsor = mmc_omap_calc_divisor(mmc, ios);
-
- if (ios->vdd != slot->vdd)
- slot->vdd = ios->vdd;
-
- clk_enabled = 0;
- switch (ios->power_mode) {
- case MMC_POWER_OFF:
- mmc_omap_set_power(slot, 0, ios->vdd);
- break;
- case MMC_POWER_UP:
- /* Cannot touch dsor yet, just power up MMC */
- mmc_omap_set_power(slot, 1, ios->vdd);
- goto exit;
- case MMC_POWER_ON:
- mmc_omap_fclk_enable(host, 1);
- clk_enabled = 1;
- dsor |= 1 << 11;
- break;
- }
-
- if (slot->bus_mode != ios->bus_mode) {
- if (slot->pdata->set_bus_mode != NULL)
- slot->pdata->set_bus_mode(mmc_dev(mmc), slot->id,
- ios->bus_mode);
- slot->bus_mode = ios->bus_mode;
- }
-
- /* On insanely high arm_per frequencies something sometimes
- * goes somehow out of sync, and the POW bit is not being set,
- * which results in the while loop below getting stuck.
- * Writing to the CON register twice seems to do the trick. */
- for (i = 0; i < 2; i++)
- OMAP_MMC_WRITE(host, CON, dsor);
- slot->saved_con = dsor;
- if (ios->power_mode == MMC_POWER_ON) {
- /* worst case at 400kHz, 80 cycles makes 200 microsecs */
- int usecs = 250;
-
- /* Send clock cycles, poll completion */
- OMAP_MMC_WRITE(host, IE, 0);
- OMAP_MMC_WRITE(host, STAT, 0xffff);
- OMAP_MMC_WRITE(host, CMD, 1 << 7);
- while (usecs > 0 && (OMAP_MMC_READ(host, STAT) & 1) == 0) {
- udelay(1);
- usecs--;
- }
- OMAP_MMC_WRITE(host, STAT, 1);
- }
-
-exit:
- mmc_omap_release_slot(slot, clk_enabled);
-}
-
-static const struct mmc_host_ops mmc_omap_ops = {
- .request = mmc_omap_request,
- .set_ios = mmc_omap_set_ios,
-};
-
-static int __init mmc_omap_new_slot(struct mmc_omap_host *host, int id)
-{
- struct mmc_omap_slot *slot = NULL;
- struct mmc_host *mmc;
- int r;
-
- mmc = mmc_alloc_host(sizeof(struct mmc_omap_slot), host->dev);
- if (mmc == NULL)
- return -ENOMEM;
-
- slot = mmc_priv(mmc);
- slot->host = host;
- slot->mmc = mmc;
- slot->id = id;
- slot->pdata = &host->pdata->slots[id];
-
- host->slots[id] = slot;
-
- mmc->caps = 0;
- if (host->pdata->slots[id].wires >= 4)
- mmc->caps |= MMC_CAP_4_BIT_DATA;
-
- mmc->ops = &mmc_omap_ops;
- mmc->f_min = 400000;
-
- if (cpu_class_is_omap2())
- mmc->f_max = 48000000;
- else
- mmc->f_max = 24000000;
- if (host->pdata->max_freq)
- mmc->f_max = min(host->pdata->max_freq, mmc->f_max);
- mmc->ocr_avail = slot->pdata->ocr_mask;
-
- /* Use scatterlist DMA to reduce per-transfer costs.
- * NOTE max_seg_size assumption that small blocks aren't
- * normally used (except e.g. for reading SD registers).
- */
- 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;
- mmc->max_seg_size = mmc->max_req_size;
-
- r = mmc_add_host(mmc);
- if (r < 0)
- goto err_remove_host;
-
- if (slot->pdata->name != NULL) {
- r = device_create_file(&mmc->class_dev,
- &dev_attr_slot_name);
- if (r < 0)
- goto err_remove_host;
- }
-
- if (slot->pdata->get_cover_state != NULL) {
- r = device_create_file(&mmc->class_dev,
- &dev_attr_cover_switch);
- if (r < 0)
- goto err_remove_slot_name;
-
- setup_timer(&slot->cover_timer, mmc_omap_cover_timer,
- (unsigned long)slot);
- tasklet_init(&slot->cover_tasklet, mmc_omap_cover_handler,
- (unsigned long)slot);
- tasklet_schedule(&slot->cover_tasklet);
- }
-
- return 0;
-
-err_remove_slot_name:
- if (slot->pdata->name != NULL)
- device_remove_file(&mmc->class_dev, &dev_attr_slot_name);
-err_remove_host:
- mmc_remove_host(mmc);
- mmc_free_host(mmc);
- return r;
-}
-
-static void mmc_omap_remove_slot(struct mmc_omap_slot *slot)
-{
- struct mmc_host *mmc = slot->mmc;
-
- if (slot->pdata->name != NULL)
- device_remove_file(&mmc->class_dev, &dev_attr_slot_name);
- if (slot->pdata->get_cover_state != NULL)
- device_remove_file(&mmc->class_dev, &dev_attr_cover_switch);
-
- tasklet_kill(&slot->cover_tasklet);
- del_timer_sync(&slot->cover_timer);
- flush_workqueue(mmc_omap_wq);
-
- mmc_remove_host(mmc);
- mmc_free_host(mmc);
-}
-
-static int __init mmc_omap_probe(struct platform_device *pdev)
-{
- struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;
- struct mmc_omap_host *host = NULL;
- struct resource *res;
- int i, ret = 0;
- int irq;
-
- if (pdata == NULL) {
- dev_err(&pdev->dev, "platform data missing\n");
- return -ENXIO;
- }
- if (pdata->nr_slots == 0) {
- dev_err(&pdev->dev, "no slots\n");
- return -ENXIO;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
- if (res == NULL || irq < 0)
- return -ENXIO;
-
- res = request_mem_region(res->start, resource_size(res),
- pdev->name);
- if (res == NULL)
- return -EBUSY;
-
- host = kzalloc(sizeof(struct mmc_omap_host), GFP_KERNEL);
- if (host == NULL) {
- ret = -ENOMEM;
- goto err_free_mem_region;
- }
-
- INIT_WORK(&host->slot_release_work, mmc_omap_slot_release_work);
- INIT_WORK(&host->send_stop_work, mmc_omap_send_stop_work);
-
- INIT_WORK(&host->cmd_abort_work, mmc_omap_abort_command);
- setup_timer(&host->cmd_abort_timer, mmc_omap_cmd_timer,
- (unsigned long) host);
-
- spin_lock_init(&host->clk_lock);
- setup_timer(&host->clk_timer, mmc_omap_clk_timer, (unsigned long) host);
-
- spin_lock_init(&host->dma_lock);
- setup_timer(&host->dma_timer, mmc_omap_dma_timer, (unsigned long) host);
- spin_lock_init(&host->slot_lock);
- init_waitqueue_head(&host->slot_wq);
-
- host->pdata = pdata;
- host->dev = &pdev->dev;
- platform_set_drvdata(pdev, host);
-
- host->id = pdev->id;
- host->mem_res = res;
- host->irq = irq;
-
- host->use_dma = 1;
- host->dev->dma_mask = &pdata->dma_mask;
- host->dma_ch = -1;
-
- host->irq = irq;
- host->phys_base = host->mem_res->start;
- host->virt_base = ioremap(res->start, resource_size(res));
- if (!host->virt_base)
- goto err_ioremap;
-
- host->iclk = clk_get(&pdev->dev, "ick");
- if (IS_ERR(host->iclk)) {
- ret = PTR_ERR(host->iclk);
- goto err_free_mmc_host;
- }
- clk_enable(host->iclk);
-
- host->fclk = clk_get(&pdev->dev, "fck");
- if (IS_ERR(host->fclk)) {
- ret = PTR_ERR(host->fclk);
- goto err_free_iclk;
- }
-
- ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host);
- if (ret)
- goto err_free_fclk;
-
- if (pdata->init != NULL) {
- ret = pdata->init(&pdev->dev);
- if (ret < 0)
- goto err_free_irq;
- }
-
- host->nr_slots = pdata->nr_slots;
- for (i = 0; i < pdata->nr_slots; i++) {
- ret = mmc_omap_new_slot(host, i);
- if (ret < 0) {
- while (--i >= 0)
- mmc_omap_remove_slot(host->slots[i]);
-
- goto err_plat_cleanup;
- }
- }
-
- host->reg_shift = (cpu_is_omap7xx() ? 1 : 2);
-
- return 0;
-
-err_plat_cleanup:
- if (pdata->cleanup)
- pdata->cleanup(&pdev->dev);
-err_free_irq:
- free_irq(host->irq, host);
-err_free_fclk:
- clk_put(host->fclk);
-err_free_iclk:
- clk_disable(host->iclk);
- clk_put(host->iclk);
-err_free_mmc_host:
- iounmap(host->virt_base);
-err_ioremap:
- kfree(host);
-err_free_mem_region:
- release_mem_region(res->start, resource_size(res));
- return ret;
-}
-
-static int mmc_omap_remove(struct platform_device *pdev)
-{
- struct mmc_omap_host *host = platform_get_drvdata(pdev);
- int i;
-
- platform_set_drvdata(pdev, NULL);
-
- BUG_ON(host == NULL);
-
- for (i = 0; i < host->nr_slots; i++)
- mmc_omap_remove_slot(host->slots[i]);
-
- if (host->pdata->cleanup)
- host->pdata->cleanup(&pdev->dev);
-
- mmc_omap_fclk_enable(host, 0);
- free_irq(host->irq, host);
- clk_put(host->fclk);
- clk_disable(host->iclk);
- clk_put(host->iclk);
-
- iounmap(host->virt_base);
- release_mem_region(pdev->resource[0].start,
- pdev->resource[0].end - pdev->resource[0].start + 1);
-
- kfree(host);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int mmc_omap_suspend(struct platform_device *pdev, pm_message_t mesg)
-{
- int i, ret = 0;
- struct mmc_omap_host *host = platform_get_drvdata(pdev);
-
- if (host == NULL || host->suspended)
- return 0;
-
- for (i = 0; i < host->nr_slots; i++) {
- struct mmc_omap_slot *slot;
-
- slot = host->slots[i];
- ret = mmc_suspend_host(slot->mmc);
- if (ret < 0) {
- while (--i >= 0) {
- slot = host->slots[i];
- mmc_resume_host(slot->mmc);
- }
- return ret;
- }
- }
- host->suspended = 1;
- return 0;
-}
-
-static int mmc_omap_resume(struct platform_device *pdev)
-{
- int i, ret = 0;
- struct mmc_omap_host *host = platform_get_drvdata(pdev);
-
- if (host == NULL || !host->suspended)
- return 0;
-
- for (i = 0; i < host->nr_slots; i++) {
- struct mmc_omap_slot *slot;
- slot = host->slots[i];
- ret = mmc_resume_host(slot->mmc);
- if (ret < 0)
- return ret;
-
- host->suspended = 0;
- }
- return 0;
-}
-#else
-#define mmc_omap_suspend NULL
-#define mmc_omap_resume NULL
-#endif
-
-static struct platform_driver mmc_omap_driver = {
- .remove = mmc_omap_remove,
- .suspend = mmc_omap_suspend,
- .resume = mmc_omap_resume,
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- },
-};
-
-static int __init mmc_omap_init(void)
-{
- int ret;
-
- mmc_omap_wq = alloc_workqueue("mmc_omap", 0, 0);
- if (!mmc_omap_wq)
- return -ENOMEM;
-
- ret = platform_driver_probe(&mmc_omap_driver, mmc_omap_probe);
- if (ret)
- destroy_workqueue(mmc_omap_wq);
- return ret;
-}
-
-static void __exit mmc_omap_exit(void)
-{
- platform_driver_unregister(&mmc_omap_driver);
- destroy_workqueue(mmc_omap_wq);
-}
-
-module_init(mmc_omap_init);
-module_exit(mmc_omap_exit);
-
-MODULE_DESCRIPTION("OMAP Multimedia Card driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRIVER_NAME);
-MODULE_AUTHOR("Juha Yrjölä");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/omap_hsmmc.c b/ANDROID_3.4.5/drivers/mmc/host/omap_hsmmc.c
deleted file mode 100644
index 71a0c4ea..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/omap_hsmmc.c
+++ /dev/null
@@ -1,2209 +0,0 @@
-/*
- * drivers/mmc/host/omap_hsmmc.c
- *
- * Driver for OMAP2430/3430 MMC controller.
- *
- * Copyright (C) 2007 Texas Instruments.
- *
- * Authors:
- * Syed Mohammed Khasim <x0khasim@ti.com>
- * Madhusudhan <madhu.cr@ti.com>
- * Mohit Jalori <mjalori@ti.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-#include <linux/timer.h>
-#include <linux/clk.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/of_device.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/core.h>
-#include <linux/mmc/mmc.h>
-#include <linux/io.h>
-#include <linux/semaphore.h>
-#include <linux/gpio.h>
-#include <linux/regulator/consumer.h>
-#include <linux/pm_runtime.h>
-#include <plat/dma.h>
-#include <mach/hardware.h>
-#include <plat/board.h>
-#include <plat/mmc.h>
-#include <plat/cpu.h>
-
-/* OMAP HSMMC Host Controller Registers */
-#define OMAP_HSMMC_SYSCONFIG 0x0010
-#define OMAP_HSMMC_SYSSTATUS 0x0014
-#define OMAP_HSMMC_CON 0x002C
-#define OMAP_HSMMC_BLK 0x0104
-#define OMAP_HSMMC_ARG 0x0108
-#define OMAP_HSMMC_CMD 0x010C
-#define OMAP_HSMMC_RSP10 0x0110
-#define OMAP_HSMMC_RSP32 0x0114
-#define OMAP_HSMMC_RSP54 0x0118
-#define OMAP_HSMMC_RSP76 0x011C
-#define OMAP_HSMMC_DATA 0x0120
-#define OMAP_HSMMC_HCTL 0x0128
-#define OMAP_HSMMC_SYSCTL 0x012C
-#define OMAP_HSMMC_STAT 0x0130
-#define OMAP_HSMMC_IE 0x0134
-#define OMAP_HSMMC_ISE 0x0138
-#define OMAP_HSMMC_CAPA 0x0140
-
-#define VS18 (1 << 26)
-#define VS30 (1 << 25)
-#define SDVS18 (0x5 << 9)
-#define SDVS30 (0x6 << 9)
-#define SDVS33 (0x7 << 9)
-#define SDVS_MASK 0x00000E00
-#define SDVSCLR 0xFFFFF1FF
-#define SDVSDET 0x00000400
-#define AUTOIDLE 0x1
-#define SDBP (1 << 8)
-#define DTO 0xe
-#define ICE 0x1
-#define ICS 0x2
-#define CEN (1 << 2)
-#define CLKD_MASK 0x0000FFC0
-#define CLKD_SHIFT 6
-#define DTO_MASK 0x000F0000
-#define DTO_SHIFT 16
-#define INT_EN_MASK 0x307F0033
-#define BWR_ENABLE (1 << 4)
-#define BRR_ENABLE (1 << 5)
-#define DTO_ENABLE (1 << 20)
-#define INIT_STREAM (1 << 1)
-#define DP_SELECT (1 << 21)
-#define DDIR (1 << 4)
-#define DMA_EN 0x1
-#define MSBS (1 << 5)
-#define BCE (1 << 1)
-#define FOUR_BIT (1 << 1)
-#define DW8 (1 << 5)
-#define CC 0x1
-#define TC 0x02
-#define OD 0x1
-#define ERR (1 << 15)
-#define CMD_TIMEOUT (1 << 16)
-#define DATA_TIMEOUT (1 << 20)
-#define CMD_CRC (1 << 17)
-#define DATA_CRC (1 << 21)
-#define CARD_ERR (1 << 28)
-#define STAT_CLEAR 0xFFFFFFFF
-#define INIT_STREAM_CMD 0x00000000
-#define DUAL_VOLT_OCR_BIT 7
-#define SRC (1 << 25)
-#define SRD (1 << 26)
-#define SOFTRESET (1 << 1)
-#define RESETDONE (1 << 0)
-
-#define MMC_AUTOSUSPEND_DELAY 100
-#define MMC_TIMEOUT_MS 20
-#define OMAP_MMC_MIN_CLOCK 400000
-#define OMAP_MMC_MAX_CLOCK 52000000
-#define DRIVER_NAME "omap_hsmmc"
-
-/*
- * One controller can have multiple slots, like on some omap boards using
- * omap.c controller driver. Luckily this is not currently done on any known
- * omap_hsmmc.c device.
- */
-#define mmc_slot(host) (host->pdata->slots[host->slot_id])
-
-/*
- * MMC Host controller read/write API's
- */
-#define OMAP_HSMMC_READ(base, reg) \
- __raw_readl((base) + OMAP_HSMMC_##reg)
-
-#define OMAP_HSMMC_WRITE(base, reg, val) \
- __raw_writel((val), (base) + OMAP_HSMMC_##reg)
-
-struct omap_hsmmc_next {
- unsigned int dma_len;
- s32 cookie;
-};
-
-struct omap_hsmmc_host {
- struct device *dev;
- struct mmc_host *mmc;
- struct mmc_request *mrq;
- struct mmc_command *cmd;
- struct mmc_data *data;
- struct clk *fclk;
- struct clk *dbclk;
- /*
- * vcc == configured supply
- * vcc_aux == optional
- * - MMC1, supply for DAT4..DAT7
- * - MMC2/MMC2, external level shifter voltage supply, for
- * chip (SDIO, eMMC, etc) or transceiver (MMC2 only)
- */
- struct regulator *vcc;
- struct regulator *vcc_aux;
- void __iomem *base;
- resource_size_t mapbase;
- spinlock_t irq_lock; /* Prevent races with irq handler */
- unsigned int dma_len;
- unsigned int dma_sg_idx;
- unsigned char bus_mode;
- unsigned char power_mode;
- u32 *buffer;
- u32 bytesleft;
- int suspended;
- int irq;
- int use_dma, dma_ch;
- int dma_line_tx, dma_line_rx;
- int slot_id;
- int got_dbclk;
- int response_busy;
- int context_loss;
- int vdd;
- int protect_card;
- int reqs_blocked;
- int use_reg;
- int req_in_progress;
- struct omap_hsmmc_next next_data;
-
- struct omap_mmc_platform_data *pdata;
-};
-
-static int omap_hsmmc_card_detect(struct device *dev, int slot)
-{
- struct omap_mmc_platform_data *mmc = dev->platform_data;
-
- /* NOTE: assumes card detect signal is active-low */
- return !gpio_get_value_cansleep(mmc->slots[0].switch_pin);
-}
-
-static int omap_hsmmc_get_wp(struct device *dev, int slot)
-{
- struct omap_mmc_platform_data *mmc = dev->platform_data;
-
- /* NOTE: assumes write protect signal is active-high */
- return gpio_get_value_cansleep(mmc->slots[0].gpio_wp);
-}
-
-static int omap_hsmmc_get_cover_state(struct device *dev, int slot)
-{
- struct omap_mmc_platform_data *mmc = dev->platform_data;
-
- /* NOTE: assumes card detect signal is active-low */
- return !gpio_get_value_cansleep(mmc->slots[0].switch_pin);
-}
-
-#ifdef CONFIG_PM
-
-static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot)
-{
- struct omap_mmc_platform_data *mmc = dev->platform_data;
-
- disable_irq(mmc->slots[0].card_detect_irq);
- return 0;
-}
-
-static int omap_hsmmc_resume_cdirq(struct device *dev, int slot)
-{
- struct omap_mmc_platform_data *mmc = dev->platform_data;
-
- enable_irq(mmc->slots[0].card_detect_irq);
- return 0;
-}
-
-#else
-
-#define omap_hsmmc_suspend_cdirq NULL
-#define omap_hsmmc_resume_cdirq NULL
-
-#endif
-
-#ifdef CONFIG_REGULATOR
-
-static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
- int vdd)
-{
- struct omap_hsmmc_host *host =
- platform_get_drvdata(to_platform_device(dev));
- int ret = 0;
-
- /*
- * If we don't see a Vcc regulator, assume it's a fixed
- * voltage always-on regulator.
- */
- if (!host->vcc)
- return 0;
- /*
- * With DT, never turn OFF the regulator. This is because
- * the pbias cell programming support is still missing when
- * booting with Device tree
- */
- if (dev->of_node && !vdd)
- return 0;
-
- if (mmc_slot(host).before_set_reg)
- mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
-
- /*
- * Assume Vcc regulator is used only to power the card ... OMAP
- * VDDS is used to power the pins, optionally with a transceiver to
- * support cards using voltages other than VDDS (1.8V nominal). When a
- * transceiver is used, DAT3..7 are muxed as transceiver control pins.
- *
- * In some cases this regulator won't support enable/disable;
- * e.g. it's a fixed rail for a WLAN chip.
- *
- * In other cases vcc_aux switches interface power. Example, for
- * eMMC cards it represents VccQ. Sometimes transceivers or SDIO
- * chips/cards need an interface voltage rail too.
- */
- if (power_on) {
- 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->mmc,
- host->vcc, 0);
- }
- } else {
- /* Shut down the rail */
- if (host->vcc_aux)
- ret = regulator_disable(host->vcc_aux);
- 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)
- mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
-
- return ret;
-}
-
-static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
-{
- struct regulator *reg;
- int ocr_value = 0;
-
- mmc_slot(host).set_power = omap_hsmmc_set_power;
-
- reg = regulator_get(host->dev, "vmmc");
- if (IS_ERR(reg)) {
- dev_dbg(host->dev, "vmmc regulator missing\n");
- } else {
- host->vcc = reg;
- ocr_value = mmc_regulator_get_ocrmask(reg);
- if (!mmc_slot(host).ocr_mask) {
- mmc_slot(host).ocr_mask = ocr_value;
- } else {
- if (!(mmc_slot(host).ocr_mask & ocr_value)) {
- dev_err(host->dev, "ocrmask %x is not supported\n",
- mmc_slot(host).ocr_mask);
- mmc_slot(host).ocr_mask = 0;
- return -EINVAL;
- }
- }
-
- /* Allow an aux regulator */
- reg = regulator_get(host->dev, "vmmc_aux");
- host->vcc_aux = IS_ERR(reg) ? NULL : reg;
-
- /* For eMMC do not power off when not in sleep state */
- if (mmc_slot(host).no_regulator_off_init)
- return 0;
- /*
- * UGLY HACK: workaround regulator framework bugs.
- * When the bootloader leaves a supply active, it's
- * initialized with zero usecount ... and we can't
- * disable it without first enabling it. Until the
- * framework is fixed, we need a workaround like this
- * (which is safe for MMC, but not in general).
- */
- if (regulator_is_enabled(host->vcc) > 0 ||
- (host->vcc_aux && regulator_is_enabled(host->vcc_aux))) {
- int vdd = ffs(mmc_slot(host).ocr_mask) - 1;
-
- mmc_slot(host).set_power(host->dev, host->slot_id,
- 1, vdd);
- mmc_slot(host).set_power(host->dev, host->slot_id,
- 0, 0);
- }
- }
-
- return 0;
-}
-
-static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
-{
- regulator_put(host->vcc);
- regulator_put(host->vcc_aux);
- mmc_slot(host).set_power = NULL;
-}
-
-static inline int omap_hsmmc_have_reg(void)
-{
- return 1;
-}
-
-#else
-
-static inline int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
-{
- return -EINVAL;
-}
-
-static inline void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
-{
-}
-
-static inline int omap_hsmmc_have_reg(void)
-{
- return 0;
-}
-
-#endif
-
-static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata)
-{
- int ret;
-
- if (gpio_is_valid(pdata->slots[0].switch_pin)) {
- if (pdata->slots[0].cover)
- pdata->slots[0].get_cover_state =
- omap_hsmmc_get_cover_state;
- else
- pdata->slots[0].card_detect = omap_hsmmc_card_detect;
- pdata->slots[0].card_detect_irq =
- gpio_to_irq(pdata->slots[0].switch_pin);
- ret = gpio_request(pdata->slots[0].switch_pin, "mmc_cd");
- if (ret)
- return ret;
- ret = gpio_direction_input(pdata->slots[0].switch_pin);
- if (ret)
- goto err_free_sp;
- } else
- pdata->slots[0].switch_pin = -EINVAL;
-
- if (gpio_is_valid(pdata->slots[0].gpio_wp)) {
- pdata->slots[0].get_ro = omap_hsmmc_get_wp;
- ret = gpio_request(pdata->slots[0].gpio_wp, "mmc_wp");
- if (ret)
- goto err_free_cd;
- ret = gpio_direction_input(pdata->slots[0].gpio_wp);
- if (ret)
- goto err_free_wp;
- } else
- pdata->slots[0].gpio_wp = -EINVAL;
-
- return 0;
-
-err_free_wp:
- gpio_free(pdata->slots[0].gpio_wp);
-err_free_cd:
- if (gpio_is_valid(pdata->slots[0].switch_pin))
-err_free_sp:
- gpio_free(pdata->slots[0].switch_pin);
- return ret;
-}
-
-static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata)
-{
- if (gpio_is_valid(pdata->slots[0].gpio_wp))
- gpio_free(pdata->slots[0].gpio_wp);
- if (gpio_is_valid(pdata->slots[0].switch_pin))
- gpio_free(pdata->slots[0].switch_pin);
-}
-
-/*
- * Start clock to the card
- */
-static void omap_hsmmc_start_clock(struct omap_hsmmc_host *host)
-{
- OMAP_HSMMC_WRITE(host->base, SYSCTL,
- OMAP_HSMMC_READ(host->base, SYSCTL) | CEN);
-}
-
-/*
- * Stop clock to the card
- */
-static void omap_hsmmc_stop_clock(struct omap_hsmmc_host *host)
-{
- OMAP_HSMMC_WRITE(host->base, SYSCTL,
- OMAP_HSMMC_READ(host->base, SYSCTL) & ~CEN);
- if ((OMAP_HSMMC_READ(host->base, SYSCTL) & CEN) != 0x0)
- dev_dbg(mmc_dev(host->mmc), "MMC Clock is not stoped\n");
-}
-
-static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
- struct mmc_command *cmd)
-{
- unsigned int irq_mask;
-
- if (host->use_dma)
- irq_mask = INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE);
- else
- irq_mask = INT_EN_MASK;
-
- /* Disable timeout for erases */
- if (cmd->opcode == MMC_ERASE)
- irq_mask &= ~DTO_ENABLE;
-
- OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
- OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
- OMAP_HSMMC_WRITE(host->base, IE, irq_mask);
-}
-
-static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host)
-{
- OMAP_HSMMC_WRITE(host->base, ISE, 0);
- OMAP_HSMMC_WRITE(host->base, IE, 0);
- OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
-}
-
-/* Calculate divisor for the given clock frequency */
-static u16 calc_divisor(struct omap_hsmmc_host *host, struct mmc_ios *ios)
-{
- u16 dsor = 0;
-
- if (ios->clock) {
- dsor = DIV_ROUND_UP(clk_get_rate(host->fclk), ios->clock);
- if (dsor > 250)
- dsor = 250;
- }
-
- return dsor;
-}
-
-static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
-{
- struct mmc_ios *ios = &host->mmc->ios;
- unsigned long regval;
- unsigned long timeout;
-
- dev_dbg(mmc_dev(host->mmc), "Set clock to %uHz\n", ios->clock);
-
- omap_hsmmc_stop_clock(host);
-
- regval = OMAP_HSMMC_READ(host->base, SYSCTL);
- regval = regval & ~(CLKD_MASK | DTO_MASK);
- regval = regval | (calc_divisor(host, ios) << 6) | (DTO << 16);
- OMAP_HSMMC_WRITE(host->base, SYSCTL, regval);
- OMAP_HSMMC_WRITE(host->base, SYSCTL,
- OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
-
- /* Wait till the ICS bit is set */
- timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
- while ((OMAP_HSMMC_READ(host->base, SYSCTL) & ICS) != ICS
- && time_before(jiffies, timeout))
- cpu_relax();
-
- omap_hsmmc_start_clock(host);
-}
-
-static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host)
-{
- struct mmc_ios *ios = &host->mmc->ios;
- u32 con;
-
- con = OMAP_HSMMC_READ(host->base, CON);
- switch (ios->bus_width) {
- case MMC_BUS_WIDTH_8:
- OMAP_HSMMC_WRITE(host->base, CON, con | DW8);
- break;
- case MMC_BUS_WIDTH_4:
- OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
- OMAP_HSMMC_WRITE(host->base, HCTL,
- OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT);
- break;
- case MMC_BUS_WIDTH_1:
- OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
- OMAP_HSMMC_WRITE(host->base, HCTL,
- OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT);
- break;
- }
-}
-
-static void omap_hsmmc_set_bus_mode(struct omap_hsmmc_host *host)
-{
- struct mmc_ios *ios = &host->mmc->ios;
- u32 con;
-
- con = OMAP_HSMMC_READ(host->base, CON);
- if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
- OMAP_HSMMC_WRITE(host->base, CON, con | OD);
- else
- OMAP_HSMMC_WRITE(host->base, CON, con & ~OD);
-}
-
-#ifdef CONFIG_PM
-
-/*
- * Restore the MMC host context, if it was lost as result of a
- * power state change.
- */
-static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
-{
- struct mmc_ios *ios = &host->mmc->ios;
- struct omap_mmc_platform_data *pdata = host->pdata;
- int context_loss = 0;
- u32 hctl, capa;
- unsigned long timeout;
-
- if (pdata->get_context_loss_count) {
- context_loss = pdata->get_context_loss_count(host->dev);
- if (context_loss < 0)
- return 1;
- }
-
- dev_dbg(mmc_dev(host->mmc), "context was %slost\n",
- context_loss == host->context_loss ? "not " : "");
- if (host->context_loss == context_loss)
- return 1;
-
- /* Wait for hardware reset */
- timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
- while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE
- && time_before(jiffies, timeout))
- ;
-
- /* Do software reset */
- OMAP_HSMMC_WRITE(host->base, SYSCONFIG, SOFTRESET);
- timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
- while ((OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) != RESETDONE
- && time_before(jiffies, timeout))
- ;
-
- OMAP_HSMMC_WRITE(host->base, SYSCONFIG,
- OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE);
-
- if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
- if (host->power_mode != MMC_POWER_OFF &&
- (1 << ios->vdd) <= MMC_VDD_23_24)
- hctl = SDVS18;
- else
- hctl = SDVS30;
- capa = VS30 | VS18;
- } else {
- hctl = SDVS18;
- capa = VS18;
- }
-
- OMAP_HSMMC_WRITE(host->base, HCTL,
- OMAP_HSMMC_READ(host->base, HCTL) | hctl);
-
- OMAP_HSMMC_WRITE(host->base, CAPA,
- OMAP_HSMMC_READ(host->base, CAPA) | capa);
-
- OMAP_HSMMC_WRITE(host->base, HCTL,
- OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
-
- timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
- while ((OMAP_HSMMC_READ(host->base, HCTL) & SDBP) != SDBP
- && time_before(jiffies, timeout))
- ;
-
- omap_hsmmc_disable_irq(host);
-
- /* Do not initialize card-specific things if the power is off */
- if (host->power_mode == MMC_POWER_OFF)
- goto out;
-
- omap_hsmmc_set_bus_width(host);
-
- omap_hsmmc_set_clock(host);
-
- omap_hsmmc_set_bus_mode(host);
-
-out:
- host->context_loss = context_loss;
-
- dev_dbg(mmc_dev(host->mmc), "context is restored\n");
- return 0;
-}
-
-/*
- * Save the MMC host context (store the number of power state changes so far).
- */
-static void omap_hsmmc_context_save(struct omap_hsmmc_host *host)
-{
- struct omap_mmc_platform_data *pdata = host->pdata;
- int context_loss;
-
- if (pdata->get_context_loss_count) {
- context_loss = pdata->get_context_loss_count(host->dev);
- if (context_loss < 0)
- return;
- host->context_loss = context_loss;
- }
-}
-
-#else
-
-static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
-{
- return 0;
-}
-
-static void omap_hsmmc_context_save(struct omap_hsmmc_host *host)
-{
-}
-
-#endif
-
-/*
- * Send init stream sequence to card
- * before sending IDLE command
- */
-static void send_init_stream(struct omap_hsmmc_host *host)
-{
- int reg = 0;
- unsigned long timeout;
-
- if (host->protect_card)
- return;
-
- disable_irq(host->irq);
-
- OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
- OMAP_HSMMC_WRITE(host->base, CON,
- OMAP_HSMMC_READ(host->base, CON) | INIT_STREAM);
- OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);
-
- timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
- while ((reg != CC) && time_before(jiffies, timeout))
- reg = OMAP_HSMMC_READ(host->base, STAT) & CC;
-
- OMAP_HSMMC_WRITE(host->base, CON,
- OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM);
-
- OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
- OMAP_HSMMC_READ(host->base, STAT);
-
- enable_irq(host->irq);
-}
-
-static inline
-int omap_hsmmc_cover_is_closed(struct omap_hsmmc_host *host)
-{
- int r = 1;
-
- if (mmc_slot(host).get_cover_state)
- r = mmc_slot(host).get_cover_state(host->dev, host->slot_id);
- return r;
-}
-
-static ssize_t
-omap_hsmmc_show_cover_switch(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
- struct omap_hsmmc_host *host = mmc_priv(mmc);
-
- return sprintf(buf, "%s\n",
- omap_hsmmc_cover_is_closed(host) ? "closed" : "open");
-}
-
-static DEVICE_ATTR(cover_switch, S_IRUGO, omap_hsmmc_show_cover_switch, NULL);
-
-static ssize_t
-omap_hsmmc_show_slot_name(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
- struct omap_hsmmc_host *host = mmc_priv(mmc);
-
- return sprintf(buf, "%s\n", mmc_slot(host).name);
-}
-
-static DEVICE_ATTR(slot_name, S_IRUGO, omap_hsmmc_show_slot_name, NULL);
-
-/*
- * Configure the response type and send the cmd.
- */
-static void
-omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
- struct mmc_data *data)
-{
- int cmdreg = 0, resptype = 0, cmdtype = 0;
-
- dev_dbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n",
- mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
- host->cmd = cmd;
-
- omap_hsmmc_enable_irq(host, cmd);
-
- host->response_busy = 0;
- if (cmd->flags & MMC_RSP_PRESENT) {
- if (cmd->flags & MMC_RSP_136)
- resptype = 1;
- else if (cmd->flags & MMC_RSP_BUSY) {
- resptype = 3;
- host->response_busy = 1;
- } else
- resptype = 2;
- }
-
- /*
- * Unlike OMAP1 controller, the cmdtype does not seem to be based on
- * ac, bc, adtc, bcr. Only commands ending an open ended transfer need
- * a val of 0x3, rest 0x0.
- */
- if (cmd == host->mrq->stop)
- cmdtype = 0x3;
-
- cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22);
-
- if (data) {
- cmdreg |= DP_SELECT | MSBS | BCE;
- if (data->flags & MMC_DATA_READ)
- cmdreg |= DDIR;
- else
- cmdreg &= ~(DDIR);
- }
-
- if (host->use_dma)
- cmdreg |= DMA_EN;
-
- host->req_in_progress = 1;
-
- OMAP_HSMMC_WRITE(host->base, ARG, cmd->arg);
- OMAP_HSMMC_WRITE(host->base, CMD, cmdreg);
-}
-
-static int
-omap_hsmmc_get_dma_dir(struct omap_hsmmc_host *host, struct mmc_data *data)
-{
- if (data->flags & MMC_DATA_WRITE)
- return DMA_TO_DEVICE;
- else
- return DMA_FROM_DEVICE;
-}
-
-static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_request *mrq)
-{
- int dma_ch;
-
- spin_lock(&host->irq_lock);
- host->req_in_progress = 0;
- dma_ch = host->dma_ch;
- spin_unlock(&host->irq_lock);
-
- omap_hsmmc_disable_irq(host);
- /* Do not complete the request if DMA is still in progress */
- if (mrq->data && host->use_dma && dma_ch != -1)
- return;
- host->mrq = NULL;
- mmc_request_done(host->mmc, mrq);
-}
-
-/*
- * Notify the transfer complete to MMC core
- */
-static void
-omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
-{
- if (!data) {
- struct mmc_request *mrq = host->mrq;
-
- /* TC before CC from CMD6 - don't know why, but it happens */
- if (host->cmd && host->cmd->opcode == 6 &&
- host->response_busy) {
- host->response_busy = 0;
- return;
- }
-
- omap_hsmmc_request_done(host, mrq);
- return;
- }
-
- host->data = NULL;
-
- if (!data->error)
- data->bytes_xfered += data->blocks * (data->blksz);
- else
- data->bytes_xfered = 0;
-
- if (!data->stop) {
- omap_hsmmc_request_done(host, data->mrq);
- return;
- }
- omap_hsmmc_start_command(host, data->stop, NULL);
-}
-
-/*
- * Notify the core about command completion
- */
-static void
-omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
-{
- host->cmd = NULL;
-
- if (cmd->flags & MMC_RSP_PRESENT) {
- if (cmd->flags & MMC_RSP_136) {
- /* response type 2 */
- cmd->resp[3] = OMAP_HSMMC_READ(host->base, RSP10);
- cmd->resp[2] = OMAP_HSMMC_READ(host->base, RSP32);
- cmd->resp[1] = OMAP_HSMMC_READ(host->base, RSP54);
- cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP76);
- } else {
- /* response types 1, 1b, 3, 4, 5, 6 */
- cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);
- }
- }
- if ((host->data == NULL && !host->response_busy) || cmd->error)
- omap_hsmmc_request_done(host, cmd->mrq);
-}
-
-/*
- * DMA clean up for command errors
- */
-static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno)
-{
- int dma_ch;
-
- host->data->error = errno;
-
- spin_lock(&host->irq_lock);
- dma_ch = host->dma_ch;
- host->dma_ch = -1;
- spin_unlock(&host->irq_lock);
-
- if (host->use_dma && dma_ch != -1) {
- dma_unmap_sg(mmc_dev(host->mmc), host->data->sg,
- host->data->sg_len,
- omap_hsmmc_get_dma_dir(host, host->data));
- omap_free_dma(dma_ch);
- host->data->host_cookie = 0;
- }
- host->data = NULL;
-}
-
-/*
- * Readable error output
- */
-#ifdef CONFIG_MMC_DEBUG
-static void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host, u32 status)
-{
- /* --- means reserved bit without definition at documentation */
- static const char *omap_hsmmc_status_bits[] = {
- "CC" , "TC" , "BGE", "---", "BWR" , "BRR" , "---" , "---" ,
- "CIRQ", "OBI" , "---", "---", "---" , "---" , "---" , "ERRI",
- "CTO" , "CCRC", "CEB", "CIE", "DTO" , "DCRC", "DEB" , "---" ,
- "ACE" , "---" , "---", "---", "CERR", "BADA", "---" , "---"
- };
- char res[256];
- char *buf = res;
- int len, i;
-
- len = sprintf(buf, "MMC IRQ 0x%x :", status);
- buf += len;
-
- for (i = 0; i < ARRAY_SIZE(omap_hsmmc_status_bits); i++)
- if (status & (1 << i)) {
- len = sprintf(buf, " %s", omap_hsmmc_status_bits[i]);
- buf += len;
- }
-
- dev_dbg(mmc_dev(host->mmc), "%s\n", res);
-}
-#else
-static inline void omap_hsmmc_dbg_report_irq(struct omap_hsmmc_host *host,
- u32 status)
-{
-}
-#endif /* CONFIG_MMC_DEBUG */
-
-/*
- * MMC controller internal state machines reset
- *
- * Used to reset command or data internal state machines, using respectively
- * SRC or SRD bit of SYSCTL register
- * Can be called from interrupt context
- */
-static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
- unsigned long bit)
-{
- unsigned long i = 0;
- unsigned long limit = (loops_per_jiffy *
- msecs_to_jiffies(MMC_TIMEOUT_MS));
-
- OMAP_HSMMC_WRITE(host->base, SYSCTL,
- OMAP_HSMMC_READ(host->base, SYSCTL) | bit);
-
- /*
- * OMAP4 ES2 and greater has an updated reset logic.
- * Monitor a 0->1 transition first
- */
- if (mmc_slot(host).features & HSMMC_HAS_UPDATED_RESET) {
- while ((!(OMAP_HSMMC_READ(host->base, SYSCTL) & bit))
- && (i++ < limit))
- cpu_relax();
- }
- i = 0;
-
- while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) &&
- (i++ < limit))
- cpu_relax();
-
- if (OMAP_HSMMC_READ(host->base, SYSCTL) & bit)
- dev_err(mmc_dev(host->mmc),
- "Timeout waiting on controller reset in %s\n",
- __func__);
-}
-
-static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
-{
- struct mmc_data *data;
- int end_cmd = 0, end_trans = 0;
-
- if (!host->req_in_progress) {
- do {
- OMAP_HSMMC_WRITE(host->base, STAT, status);
- /* Flush posted write */
- status = OMAP_HSMMC_READ(host->base, STAT);
- } while (status & INT_EN_MASK);
- return;
- }
-
- data = host->data;
- dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
-
- if (status & ERR) {
- omap_hsmmc_dbg_report_irq(host, status);
- if ((status & CMD_TIMEOUT) ||
- (status & CMD_CRC)) {
- if (host->cmd) {
- if (status & CMD_TIMEOUT) {
- omap_hsmmc_reset_controller_fsm(host,
- SRC);
- host->cmd->error = -ETIMEDOUT;
- } else {
- host->cmd->error = -EILSEQ;
- }
- end_cmd = 1;
- }
- if (host->data || host->response_busy) {
- if (host->data)
- omap_hsmmc_dma_cleanup(host,
- -ETIMEDOUT);
- host->response_busy = 0;
- omap_hsmmc_reset_controller_fsm(host, SRD);
- }
- }
- if ((status & DATA_TIMEOUT) ||
- (status & DATA_CRC)) {
- if (host->data || host->response_busy) {
- int err = (status & DATA_TIMEOUT) ?
- -ETIMEDOUT : -EILSEQ;
-
- if (host->data)
- omap_hsmmc_dma_cleanup(host, err);
- else
- host->mrq->cmd->error = err;
- host->response_busy = 0;
- omap_hsmmc_reset_controller_fsm(host, SRD);
- end_trans = 1;
- }
- }
- if (status & CARD_ERR) {
- dev_dbg(mmc_dev(host->mmc),
- "Ignoring card err CMD%d\n", host->cmd->opcode);
- if (host->cmd)
- end_cmd = 1;
- if (host->data)
- end_trans = 1;
- }
- }
-
- OMAP_HSMMC_WRITE(host->base, STAT, status);
-
- if (end_cmd || ((status & CC) && host->cmd))
- omap_hsmmc_cmd_done(host, host->cmd);
- if ((end_trans || (status & TC)) && host->mrq)
- omap_hsmmc_xfer_done(host, data);
-}
-
-/*
- * MMC controller IRQ handler
- */
-static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
-{
- struct omap_hsmmc_host *host = dev_id;
- int status;
-
- status = OMAP_HSMMC_READ(host->base, STAT);
- do {
- omap_hsmmc_do_irq(host, status);
- /* Flush posted write */
- status = OMAP_HSMMC_READ(host->base, STAT);
- } while (status & INT_EN_MASK);
-
- return IRQ_HANDLED;
-}
-
-static void set_sd_bus_power(struct omap_hsmmc_host *host)
-{
- unsigned long i;
-
- OMAP_HSMMC_WRITE(host->base, HCTL,
- OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
- for (i = 0; i < loops_per_jiffy; i++) {
- if (OMAP_HSMMC_READ(host->base, HCTL) & SDBP)
- break;
- cpu_relax();
- }
-}
-
-/*
- * Switch MMC interface voltage ... only relevant for MMC1.
- *
- * MMC2 and MMC3 use fixed 1.8V levels, and maybe a transceiver.
- * The MMC2 transceiver controls are used instead of DAT4..DAT7.
- * Some chips, like eMMC ones, use internal transceivers.
- */
-static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
-{
- u32 reg_val = 0;
- int ret;
-
- /* Disable the clocks */
- pm_runtime_put_sync(host->dev);
- if (host->got_dbclk)
- clk_disable(host->dbclk);
-
- /* Turn the power off */
- ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
-
- /* Turn the power ON with given VDD 1.8 or 3.0v */
- if (!ret)
- ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1,
- vdd);
- pm_runtime_get_sync(host->dev);
- if (host->got_dbclk)
- clk_enable(host->dbclk);
-
- if (ret != 0)
- goto err;
-
- OMAP_HSMMC_WRITE(host->base, HCTL,
- OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR);
- reg_val = OMAP_HSMMC_READ(host->base, HCTL);
-
- /*
- * If a MMC dual voltage card is detected, the set_ios fn calls
- * this fn with VDD bit set for 1.8V. Upon card removal from the
- * slot, omap_hsmmc_set_ios sets the VDD back to 3V on MMC_POWER_OFF.
- *
- * Cope with a bit of slop in the range ... per data sheets:
- * - "1.8V" for vdds_mmc1/vdds_mmc1a can be up to 2.45V max,
- * but recommended values are 1.71V to 1.89V
- * - "3.0V" for vdds_mmc1/vdds_mmc1a can be up to 3.5V max,
- * but recommended values are 2.7V to 3.3V
- *
- * Board setup code shouldn't permit anything very out-of-range.
- * TWL4030-family VMMC1 and VSIM regulators are fine (avoiding the
- * middle range) but VSIM can't power DAT4..DAT7 at more than 3V.
- */
- if ((1 << vdd) <= MMC_VDD_23_24)
- reg_val |= SDVS18;
- else
- reg_val |= SDVS30;
-
- OMAP_HSMMC_WRITE(host->base, HCTL, reg_val);
- set_sd_bus_power(host);
-
- return 0;
-err:
- dev_dbg(mmc_dev(host->mmc), "Unable to switch operating voltage\n");
- return ret;
-}
-
-/* Protect the card while the cover is open */
-static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
-{
- if (!mmc_slot(host).get_cover_state)
- return;
-
- host->reqs_blocked = 0;
- if (mmc_slot(host).get_cover_state(host->dev, host->slot_id)) {
- if (host->protect_card) {
- dev_info(host->dev, "%s: cover is closed, "
- "card is now accessible\n",
- mmc_hostname(host->mmc));
- host->protect_card = 0;
- }
- } else {
- if (!host->protect_card) {
- dev_info(host->dev, "%s: cover is open, "
- "card is now inaccessible\n",
- mmc_hostname(host->mmc));
- host->protect_card = 1;
- }
- }
-}
-
-/*
- * irq handler to notify the core about card insertion/removal
- */
-static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id)
-{
- struct omap_hsmmc_host *host = dev_id;
- struct omap_mmc_slot_data *slot = &mmc_slot(host);
- int carddetect;
-
- if (host->suspended)
- return IRQ_HANDLED;
-
- sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
-
- if (slot->card_detect)
- carddetect = slot->card_detect(host->dev, host->slot_id);
- else {
- omap_hsmmc_protect_card(host);
- carddetect = -ENOSYS;
- }
-
- if (carddetect)
- mmc_detect_change(host->mmc, (HZ * 200) / 1000);
- else
- mmc_detect_change(host->mmc, (HZ * 50) / 1000);
- return IRQ_HANDLED;
-}
-
-static int omap_hsmmc_get_dma_sync_dev(struct omap_hsmmc_host *host,
- struct mmc_data *data)
-{
- int sync_dev;
-
- if (data->flags & MMC_DATA_WRITE)
- sync_dev = host->dma_line_tx;
- else
- sync_dev = host->dma_line_rx;
- return sync_dev;
-}
-
-static void omap_hsmmc_config_dma_params(struct omap_hsmmc_host *host,
- struct mmc_data *data,
- struct scatterlist *sgl)
-{
- int blksz, nblk, dma_ch;
-
- dma_ch = host->dma_ch;
- if (data->flags & MMC_DATA_WRITE) {
- omap_set_dma_dest_params(dma_ch, 0, OMAP_DMA_AMODE_CONSTANT,
- (host->mapbase + OMAP_HSMMC_DATA), 0, 0);
- omap_set_dma_src_params(dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
- sg_dma_address(sgl), 0, 0);
- } else {
- omap_set_dma_src_params(dma_ch, 0, OMAP_DMA_AMODE_CONSTANT,
- (host->mapbase + OMAP_HSMMC_DATA), 0, 0);
- omap_set_dma_dest_params(dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
- sg_dma_address(sgl), 0, 0);
- }
-
- blksz = host->data->blksz;
- nblk = sg_dma_len(sgl) / blksz;
-
- omap_set_dma_transfer_params(dma_ch, OMAP_DMA_DATA_TYPE_S32,
- blksz / 4, nblk, OMAP_DMA_SYNC_FRAME,
- omap_hsmmc_get_dma_sync_dev(host, data),
- !(data->flags & MMC_DATA_WRITE));
-
- omap_start_dma(dma_ch);
-}
-
-/*
- * DMA call back function
- */
-static void omap_hsmmc_dma_cb(int lch, u16 ch_status, void *cb_data)
-{
- struct omap_hsmmc_host *host = cb_data;
- struct mmc_data *data;
- int dma_ch, req_in_progress;
-
- if (!(ch_status & OMAP_DMA_BLOCK_IRQ)) {
- dev_warn(mmc_dev(host->mmc), "unexpected dma status %x\n",
- ch_status);
- return;
- }
-
- spin_lock(&host->irq_lock);
- if (host->dma_ch < 0) {
- spin_unlock(&host->irq_lock);
- return;
- }
-
- data = host->mrq->data;
- host->dma_sg_idx++;
- if (host->dma_sg_idx < host->dma_len) {
- /* Fire up the next transfer. */
- omap_hsmmc_config_dma_params(host, data,
- data->sg + host->dma_sg_idx);
- spin_unlock(&host->irq_lock);
- return;
- }
-
- if (!data->host_cookie)
- dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- omap_hsmmc_get_dma_dir(host, data));
-
- req_in_progress = host->req_in_progress;
- dma_ch = host->dma_ch;
- host->dma_ch = -1;
- spin_unlock(&host->irq_lock);
-
- omap_free_dma(dma_ch);
-
- /* If DMA has finished after TC, complete the request */
- if (!req_in_progress) {
- struct mmc_request *mrq = host->mrq;
-
- host->mrq = NULL;
- mmc_request_done(host->mmc, mrq);
- }
-}
-
-static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,
- struct mmc_data *data,
- struct omap_hsmmc_next *next)
-{
- int dma_len;
-
- if (!next && data->host_cookie &&
- data->host_cookie != host->next_data.cookie) {
- dev_warn(host->dev, "[%s] invalid cookie: data->host_cookie %d"
- " host->next_data.cookie %d\n",
- __func__, data->host_cookie, host->next_data.cookie);
- data->host_cookie = 0;
- }
-
- /* Check if next job is already prepared */
- if (next ||
- (!next && data->host_cookie != host->next_data.cookie)) {
- dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len,
- omap_hsmmc_get_dma_dir(host, data));
-
- } else {
- dma_len = host->next_data.dma_len;
- host->next_data.dma_len = 0;
- }
-
-
- if (dma_len == 0)
- return -EINVAL;
-
- if (next) {
- next->dma_len = dma_len;
- data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie;
- } else
- host->dma_len = dma_len;
-
- return 0;
-}
-
-/*
- * Routine to configure and start DMA for the MMC card
- */
-static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
- struct mmc_request *req)
-{
- int dma_ch = 0, ret = 0, i;
- struct mmc_data *data = req->data;
-
- /* Sanity check: all the SG entries must be aligned by block size. */
- for (i = 0; i < data->sg_len; i++) {
- struct scatterlist *sgl;
-
- sgl = data->sg + i;
- if (sgl->length % data->blksz)
- return -EINVAL;
- }
- if ((data->blksz % 4) != 0)
- /* REVISIT: The MMC buffer increments only when MSB is written.
- * Return error for blksz which is non multiple of four.
- */
- return -EINVAL;
-
- BUG_ON(host->dma_ch != -1);
-
- ret = omap_request_dma(omap_hsmmc_get_dma_sync_dev(host, data),
- "MMC/SD", omap_hsmmc_dma_cb, host, &dma_ch);
- if (ret != 0) {
- dev_err(mmc_dev(host->mmc),
- "%s: omap_request_dma() failed with %d\n",
- mmc_hostname(host->mmc), ret);
- return ret;
- }
- ret = omap_hsmmc_pre_dma_transfer(host, data, NULL);
- if (ret)
- return ret;
-
- host->dma_ch = dma_ch;
- host->dma_sg_idx = 0;
-
- omap_hsmmc_config_dma_params(host, data, data->sg);
-
- return 0;
-}
-
-static void set_data_timeout(struct omap_hsmmc_host *host,
- unsigned int timeout_ns,
- unsigned int timeout_clks)
-{
- unsigned int timeout, cycle_ns;
- uint32_t reg, clkd, dto = 0;
-
- reg = OMAP_HSMMC_READ(host->base, SYSCTL);
- clkd = (reg & CLKD_MASK) >> CLKD_SHIFT;
- if (clkd == 0)
- clkd = 1;
-
- cycle_ns = 1000000000 / (clk_get_rate(host->fclk) / clkd);
- timeout = timeout_ns / cycle_ns;
- timeout += timeout_clks;
- if (timeout) {
- while ((timeout & 0x80000000) == 0) {
- dto += 1;
- timeout <<= 1;
- }
- dto = 31 - dto;
- timeout <<= 1;
- if (timeout && dto)
- dto += 1;
- if (dto >= 13)
- dto -= 13;
- else
- dto = 0;
- if (dto > 14)
- dto = 14;
- }
-
- reg &= ~DTO_MASK;
- reg |= dto << DTO_SHIFT;
- OMAP_HSMMC_WRITE(host->base, SYSCTL, reg);
-}
-
-/*
- * Configure block length for MMC/SD cards and initiate the transfer.
- */
-static int
-omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
-{
- int ret;
- host->data = req->data;
-
- if (req->data == NULL) {
- OMAP_HSMMC_WRITE(host->base, BLK, 0);
- /*
- * Set an arbitrary 100ms data timeout for commands with
- * busy signal.
- */
- if (req->cmd->flags & MMC_RSP_BUSY)
- set_data_timeout(host, 100000000U, 0);
- return 0;
- }
-
- OMAP_HSMMC_WRITE(host->base, BLK, (req->data->blksz)
- | (req->data->blocks << 16));
- set_data_timeout(host, req->data->timeout_ns, req->data->timeout_clks);
-
- if (host->use_dma) {
- ret = omap_hsmmc_start_dma_transfer(host, req);
- if (ret != 0) {
- dev_dbg(mmc_dev(host->mmc), "MMC start dma failure\n");
- return ret;
- }
- }
- return 0;
-}
-
-static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
- int err)
-{
- struct omap_hsmmc_host *host = mmc_priv(mmc);
- struct mmc_data *data = mrq->data;
-
- if (host->use_dma) {
- if (data->host_cookie)
- dma_unmap_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len,
- omap_hsmmc_get_dma_dir(host, data));
- data->host_cookie = 0;
- }
-}
-
-static void omap_hsmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
- bool is_first_req)
-{
- struct omap_hsmmc_host *host = mmc_priv(mmc);
-
- if (mrq->data->host_cookie) {
- mrq->data->host_cookie = 0;
- return ;
- }
-
- if (host->use_dma)
- if (omap_hsmmc_pre_dma_transfer(host, mrq->data,
- &host->next_data))
- mrq->data->host_cookie = 0;
-}
-
-/*
- * Request function. for read/write operation
- */
-static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
-{
- struct omap_hsmmc_host *host = mmc_priv(mmc);
- int err;
-
- BUG_ON(host->req_in_progress);
- BUG_ON(host->dma_ch != -1);
- if (host->protect_card) {
- if (host->reqs_blocked < 3) {
- /*
- * Ensure the controller is left in a consistent
- * state by resetting the command and data state
- * machines.
- */
- omap_hsmmc_reset_controller_fsm(host, SRD);
- omap_hsmmc_reset_controller_fsm(host, SRC);
- host->reqs_blocked += 1;
- }
- req->cmd->error = -EBADF;
- if (req->data)
- req->data->error = -EBADF;
- req->cmd->retries = 0;
- mmc_request_done(mmc, req);
- return;
- } else if (host->reqs_blocked)
- host->reqs_blocked = 0;
- WARN_ON(host->mrq != NULL);
- host->mrq = req;
- err = omap_hsmmc_prepare_data(host, req);
- if (err) {
- req->cmd->error = err;
- if (req->data)
- req->data->error = err;
- host->mrq = NULL;
- mmc_request_done(mmc, req);
- return;
- }
-
- omap_hsmmc_start_command(host, req->cmd, req->data);
-}
-
-/* Routine to configure clock values. Exposed API to core */
-static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct omap_hsmmc_host *host = mmc_priv(mmc);
- int do_send_init_stream = 0;
-
- pm_runtime_get_sync(host->dev);
-
- if (ios->power_mode != host->power_mode) {
- switch (ios->power_mode) {
- case MMC_POWER_OFF:
- mmc_slot(host).set_power(host->dev, host->slot_id,
- 0, 0);
- host->vdd = 0;
- break;
- case MMC_POWER_UP:
- mmc_slot(host).set_power(host->dev, host->slot_id,
- 1, ios->vdd);
- host->vdd = ios->vdd;
- break;
- case MMC_POWER_ON:
- do_send_init_stream = 1;
- break;
- }
- host->power_mode = ios->power_mode;
- }
-
- /* FIXME: set registers based only on changes to ios */
-
- omap_hsmmc_set_bus_width(host);
-
- if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
- /* Only MMC1 can interface at 3V without some flavor
- * of external transceiver; but they all handle 1.8V.
- */
- if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
- (ios->vdd == DUAL_VOLT_OCR_BIT) &&
- /*
- * With pbias cell programming missing, this
- * can't be allowed when booting with device
- * tree.
- */
- !host->dev->of_node) {
- /*
- * The mmc_select_voltage fn of the core does
- * not seem to set the power_mode to
- * MMC_POWER_UP upon recalculating the voltage.
- * vdd 1.8v.
- */
- if (omap_hsmmc_switch_opcond(host, ios->vdd) != 0)
- dev_dbg(mmc_dev(host->mmc),
- "Switch operation failed\n");
- }
- }
-
- omap_hsmmc_set_clock(host);
-
- if (do_send_init_stream)
- send_init_stream(host);
-
- omap_hsmmc_set_bus_mode(host);
-
- pm_runtime_put_autosuspend(host->dev);
-}
-
-static int omap_hsmmc_get_cd(struct mmc_host *mmc)
-{
- struct omap_hsmmc_host *host = mmc_priv(mmc);
-
- if (!mmc_slot(host).card_detect)
- return -ENOSYS;
- return mmc_slot(host).card_detect(host->dev, host->slot_id);
-}
-
-static int omap_hsmmc_get_ro(struct mmc_host *mmc)
-{
- struct omap_hsmmc_host *host = mmc_priv(mmc);
-
- if (!mmc_slot(host).get_ro)
- return -ENOSYS;
- return mmc_slot(host).get_ro(host->dev, 0);
-}
-
-static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
-{
- struct omap_hsmmc_host *host = mmc_priv(mmc);
-
- if (mmc_slot(host).init_card)
- mmc_slot(host).init_card(card);
-}
-
-static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
-{
- u32 hctl, capa, value;
-
- /* Only MMC1 supports 3.0V */
- if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
- hctl = SDVS30;
- capa = VS30 | VS18;
- } else {
- hctl = SDVS18;
- capa = VS18;
- }
-
- value = OMAP_HSMMC_READ(host->base, HCTL) & ~SDVS_MASK;
- OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl);
-
- value = OMAP_HSMMC_READ(host->base, CAPA);
- OMAP_HSMMC_WRITE(host->base, CAPA, value | capa);
-
- /* Set the controller to AUTO IDLE mode */
- value = OMAP_HSMMC_READ(host->base, SYSCONFIG);
- OMAP_HSMMC_WRITE(host->base, SYSCONFIG, value | AUTOIDLE);
-
- /* Set SD bus power bit */
- set_sd_bus_power(host);
-}
-
-static int omap_hsmmc_enable_fclk(struct mmc_host *mmc)
-{
- struct omap_hsmmc_host *host = mmc_priv(mmc);
-
- pm_runtime_get_sync(host->dev);
-
- return 0;
-}
-
-static int omap_hsmmc_disable_fclk(struct mmc_host *mmc)
-{
- struct omap_hsmmc_host *host = mmc_priv(mmc);
-
- pm_runtime_mark_last_busy(host->dev);
- pm_runtime_put_autosuspend(host->dev);
-
- return 0;
-}
-
-static const struct mmc_host_ops omap_hsmmc_ops = {
- .enable = omap_hsmmc_enable_fclk,
- .disable = omap_hsmmc_disable_fclk,
- .post_req = omap_hsmmc_post_req,
- .pre_req = omap_hsmmc_pre_req,
- .request = omap_hsmmc_request,
- .set_ios = omap_hsmmc_set_ios,
- .get_cd = omap_hsmmc_get_cd,
- .get_ro = omap_hsmmc_get_ro,
- .init_card = omap_hsmmc_init_card,
- /* NYET -- enable_sdio_irq */
-};
-
-#ifdef CONFIG_DEBUG_FS
-
-static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
-{
- struct mmc_host *mmc = s->private;
- struct omap_hsmmc_host *host = mmc_priv(mmc);
- int context_loss = 0;
-
- if (host->pdata->get_context_loss_count)
- context_loss = host->pdata->get_context_loss_count(host->dev);
-
- seq_printf(s, "mmc%d:\n ctx_loss:\t%d:%d\n\nregs:\n",
- mmc->index, host->context_loss, context_loss);
-
- if (host->suspended) {
- seq_printf(s, "host suspended, can't read registers\n");
- return 0;
- }
-
- pm_runtime_get_sync(host->dev);
-
- seq_printf(s, "SYSCONFIG:\t0x%08x\n",
- OMAP_HSMMC_READ(host->base, SYSCONFIG));
- seq_printf(s, "CON:\t\t0x%08x\n",
- OMAP_HSMMC_READ(host->base, CON));
- seq_printf(s, "HCTL:\t\t0x%08x\n",
- OMAP_HSMMC_READ(host->base, HCTL));
- seq_printf(s, "SYSCTL:\t\t0x%08x\n",
- OMAP_HSMMC_READ(host->base, SYSCTL));
- seq_printf(s, "IE:\t\t0x%08x\n",
- OMAP_HSMMC_READ(host->base, IE));
- seq_printf(s, "ISE:\t\t0x%08x\n",
- OMAP_HSMMC_READ(host->base, ISE));
- seq_printf(s, "CAPA:\t\t0x%08x\n",
- OMAP_HSMMC_READ(host->base, CAPA));
-
- pm_runtime_mark_last_busy(host->dev);
- pm_runtime_put_autosuspend(host->dev);
-
- return 0;
-}
-
-static int omap_hsmmc_regs_open(struct inode *inode, struct file *file)
-{
- return single_open(file, omap_hsmmc_regs_show, inode->i_private);
-}
-
-static const struct file_operations mmc_regs_fops = {
- .open = omap_hsmmc_regs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static void omap_hsmmc_debugfs(struct mmc_host *mmc)
-{
- if (mmc->debugfs_root)
- debugfs_create_file("regs", S_IRUSR, mmc->debugfs_root,
- mmc, &mmc_regs_fops);
-}
-
-#else
-
-static void omap_hsmmc_debugfs(struct mmc_host *mmc)
-{
-}
-
-#endif
-
-#ifdef CONFIG_OF
-static u16 omap4_reg_offset = 0x100;
-
-static const struct of_device_id omap_mmc_of_match[] = {
- {
- .compatible = "ti,omap2-hsmmc",
- },
- {
- .compatible = "ti,omap3-hsmmc",
- },
- {
- .compatible = "ti,omap4-hsmmc",
- .data = &omap4_reg_offset,
- },
- {},
-};
-MODULE_DEVICE_TABLE(of, omap_mmc_of_match);
-
-static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
-{
- struct omap_mmc_platform_data *pdata;
- struct device_node *np = dev->of_node;
- u32 bus_width;
-
- pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- return NULL; /* out of memory */
-
- if (of_find_property(np, "ti,dual-volt", NULL))
- pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
-
- /* This driver only supports 1 slot */
- pdata->nr_slots = 1;
- pdata->slots[0].switch_pin = of_get_named_gpio(np, "cd-gpios", 0);
- pdata->slots[0].gpio_wp = of_get_named_gpio(np, "wp-gpios", 0);
-
- if (of_find_property(np, "ti,non-removable", NULL)) {
- pdata->slots[0].nonremovable = true;
- pdata->slots[0].no_regulator_off_init = true;
- }
- of_property_read_u32(np, "ti,bus-width", &bus_width);
- if (bus_width == 4)
- pdata->slots[0].caps |= MMC_CAP_4_BIT_DATA;
- else if (bus_width == 8)
- pdata->slots[0].caps |= MMC_CAP_8_BIT_DATA;
-
- if (of_find_property(np, "ti,needs-special-reset", NULL))
- pdata->slots[0].features |= HSMMC_HAS_UPDATED_RESET;
-
- return pdata;
-}
-#else
-static inline struct omap_mmc_platform_data
- *of_get_hsmmc_pdata(struct device *dev)
-{
- return NULL;
-}
-#endif
-
-static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
-{
- struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;
- struct mmc_host *mmc;
- struct omap_hsmmc_host *host = NULL;
- struct resource *res;
- int ret, irq;
- const struct of_device_id *match;
-
- match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
- if (match) {
- pdata = of_get_hsmmc_pdata(&pdev->dev);
- if (match->data) {
- u16 *offsetp = match->data;
- pdata->reg_offset = *offsetp;
- }
- }
-
- if (pdata == NULL) {
- dev_err(&pdev->dev, "Platform Data is missing\n");
- return -ENXIO;
- }
-
- if (pdata->nr_slots == 0) {
- dev_err(&pdev->dev, "No Slots\n");
- return -ENXIO;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
- if (res == NULL || irq < 0)
- return -ENXIO;
-
- res = request_mem_region(res->start, resource_size(res), pdev->name);
- if (res == NULL)
- return -EBUSY;
-
- ret = omap_hsmmc_gpio_init(pdata);
- if (ret)
- goto err;
-
- mmc = mmc_alloc_host(sizeof(struct omap_hsmmc_host), &pdev->dev);
- if (!mmc) {
- ret = -ENOMEM;
- goto err_alloc;
- }
-
- host = mmc_priv(mmc);
- host->mmc = mmc;
- host->pdata = pdata;
- host->dev = &pdev->dev;
- host->use_dma = 1;
- host->dev->dma_mask = &pdata->dma_mask;
- host->dma_ch = -1;
- host->irq = irq;
- host->slot_id = 0;
- host->mapbase = res->start + pdata->reg_offset;
- host->base = ioremap(host->mapbase, SZ_4K);
- host->power_mode = MMC_POWER_OFF;
- host->next_data.cookie = 1;
-
- platform_set_drvdata(pdev, host);
-
- mmc->ops = &omap_hsmmc_ops;
-
- /*
- * If regulator_disable can only put vcc_aux to sleep then there is
- * no off state.
- */
- if (mmc_slot(host).vcc_aux_disable_is_sleep)
- mmc_slot(host).no_off = 1;
-
- mmc->f_min = OMAP_MMC_MIN_CLOCK;
-
- if (pdata->max_freq > 0)
- mmc->f_max = pdata->max_freq;
- else
- mmc->f_max = OMAP_MMC_MAX_CLOCK;
-
- spin_lock_init(&host->irq_lock);
-
- host->fclk = clk_get(&pdev->dev, "fck");
- if (IS_ERR(host->fclk)) {
- ret = PTR_ERR(host->fclk);
- host->fclk = NULL;
- goto err1;
- }
-
- if (host->pdata->controller_flags & OMAP_HSMMC_BROKEN_MULTIBLOCK_READ) {
- dev_info(&pdev->dev, "multiblock reads disabled due to 35xx erratum 2.1.1.128; MMC read performance may suffer\n");
- mmc->caps2 |= MMC_CAP2_NO_MULTI_READ;
- }
-
- pm_runtime_enable(host->dev);
- pm_runtime_get_sync(host->dev);
- pm_runtime_set_autosuspend_delay(host->dev, MMC_AUTOSUSPEND_DELAY);
- pm_runtime_use_autosuspend(host->dev);
-
- omap_hsmmc_context_save(host);
-
- if (cpu_is_omap2430()) {
- host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
- /*
- * MMC can still work without debounce clock.
- */
- if (IS_ERR(host->dbclk))
- dev_warn(mmc_dev(host->mmc),
- "Failed to get debounce clock\n");
- else
- host->got_dbclk = 1;
-
- if (host->got_dbclk)
- if (clk_enable(host->dbclk) != 0)
- dev_dbg(mmc_dev(host->mmc), "Enabling debounce"
- " clk failed\n");
- }
-
- /* Since we do only SG emulation, we can have as many segs
- * as we want. */
- 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 */
- mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
- mmc->max_seg_size = mmc->max_req_size;
-
- mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
- MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
-
- mmc->caps |= mmc_slot(host).caps;
- if (mmc->caps & MMC_CAP_8_BIT_DATA)
- mmc->caps |= MMC_CAP_4_BIT_DATA;
-
- if (mmc_slot(host).nonremovable)
- mmc->caps |= MMC_CAP_NONREMOVABLE;
-
- mmc->pm_caps = mmc_slot(host).pm_caps;
-
- omap_hsmmc_conf_bus_power(host);
-
- res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
- if (!res) {
- dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n");
- goto err_irq;
- }
- host->dma_line_tx = res->start;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx");
- if (!res) {
- dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n");
- goto err_irq;
- }
- host->dma_line_rx = res->start;
-
- /* Request IRQ for MMC operations */
- ret = request_irq(host->irq, omap_hsmmc_irq, 0,
- mmc_hostname(mmc), host);
- if (ret) {
- dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
- goto err_irq;
- }
-
- if (pdata->init != NULL) {
- if (pdata->init(&pdev->dev) != 0) {
- dev_dbg(mmc_dev(host->mmc),
- "Unable to configure MMC IRQs\n");
- goto err_irq_cd_init;
- }
- }
-
- if (omap_hsmmc_have_reg() && !mmc_slot(host).set_power) {
- ret = omap_hsmmc_reg_get(host);
- if (ret)
- goto err_reg;
- host->use_reg = 1;
- }
-
- mmc->ocr_avail = mmc_slot(host).ocr_mask;
-
- /* Request IRQ for card detect */
- if ((mmc_slot(host).card_detect_irq)) {
- ret = request_threaded_irq(mmc_slot(host).card_detect_irq,
- NULL,
- omap_hsmmc_detect,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- mmc_hostname(mmc), host);
- if (ret) {
- dev_dbg(mmc_dev(host->mmc),
- "Unable to grab MMC CD IRQ\n");
- goto err_irq_cd;
- }
- pdata->suspend = omap_hsmmc_suspend_cdirq;
- pdata->resume = omap_hsmmc_resume_cdirq;
- }
-
- omap_hsmmc_disable_irq(host);
-
- omap_hsmmc_protect_card(host);
-
- mmc_add_host(mmc);
-
- if (mmc_slot(host).name != NULL) {
- ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name);
- if (ret < 0)
- goto err_slot_name;
- }
- if (mmc_slot(host).card_detect_irq && mmc_slot(host).get_cover_state) {
- ret = device_create_file(&mmc->class_dev,
- &dev_attr_cover_switch);
- if (ret < 0)
- goto err_slot_name;
- }
-
- omap_hsmmc_debugfs(mmc);
- pm_runtime_mark_last_busy(host->dev);
- pm_runtime_put_autosuspend(host->dev);
-
- return 0;
-
-err_slot_name:
- mmc_remove_host(mmc);
- free_irq(mmc_slot(host).card_detect_irq, host);
-err_irq_cd:
- if (host->use_reg)
- omap_hsmmc_reg_put(host);
-err_reg:
- if (host->pdata->cleanup)
- host->pdata->cleanup(&pdev->dev);
-err_irq_cd_init:
- free_irq(host->irq, host);
-err_irq:
- pm_runtime_put_sync(host->dev);
- pm_runtime_disable(host->dev);
- clk_put(host->fclk);
- if (host->got_dbclk) {
- clk_disable(host->dbclk);
- clk_put(host->dbclk);
- }
-err1:
- iounmap(host->base);
- platform_set_drvdata(pdev, NULL);
- mmc_free_host(mmc);
-err_alloc:
- omap_hsmmc_gpio_free(pdata);
-err:
- release_mem_region(res->start, resource_size(res));
- return ret;
-}
-
-static int __devexit omap_hsmmc_remove(struct platform_device *pdev)
-{
- struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
- struct resource *res;
-
- pm_runtime_get_sync(host->dev);
- mmc_remove_host(host->mmc);
- if (host->use_reg)
- omap_hsmmc_reg_put(host);
- if (host->pdata->cleanup)
- host->pdata->cleanup(&pdev->dev);
- free_irq(host->irq, host);
- if (mmc_slot(host).card_detect_irq)
- free_irq(mmc_slot(host).card_detect_irq, host);
-
- pm_runtime_put_sync(host->dev);
- pm_runtime_disable(host->dev);
- clk_put(host->fclk);
- if (host->got_dbclk) {
- clk_disable(host->dbclk);
- clk_put(host->dbclk);
- }
-
- mmc_free_host(host->mmc);
- iounmap(host->base);
- omap_hsmmc_gpio_free(pdev->dev.platform_data);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res)
- release_mem_region(res->start, resource_size(res));
- platform_set_drvdata(pdev, NULL);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int omap_hsmmc_suspend(struct device *dev)
-{
- int ret = 0;
- struct omap_hsmmc_host *host = dev_get_drvdata(dev);
-
- if (!host)
- return 0;
-
- if (host && host->suspended)
- return 0;
-
- pm_runtime_get_sync(host->dev);
- host->suspended = 1;
- if (host->pdata->suspend) {
- ret = host->pdata->suspend(dev, host->slot_id);
- if (ret) {
- dev_dbg(dev, "Unable to handle MMC board"
- " level suspend\n");
- host->suspended = 0;
- return ret;
- }
- }
- ret = mmc_suspend_host(host->mmc);
-
- if (ret) {
- host->suspended = 0;
- if (host->pdata->resume) {
- ret = host->pdata->resume(dev, host->slot_id);
- if (ret)
- dev_dbg(dev, "Unmask interrupt failed\n");
- }
- goto err;
- }
-
- if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) {
- omap_hsmmc_disable_irq(host);
- OMAP_HSMMC_WRITE(host->base, HCTL,
- OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
- }
-
- if (host->got_dbclk)
- clk_disable(host->dbclk);
-err:
- pm_runtime_put_sync(host->dev);
- return ret;
-}
-
-/* Routine to resume the MMC device */
-static int omap_hsmmc_resume(struct device *dev)
-{
- int ret = 0;
- struct omap_hsmmc_host *host = dev_get_drvdata(dev);
-
- if (!host)
- return 0;
-
- if (host && !host->suspended)
- return 0;
-
- pm_runtime_get_sync(host->dev);
-
- if (host->got_dbclk)
- clk_enable(host->dbclk);
-
- if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER))
- omap_hsmmc_conf_bus_power(host);
-
- if (host->pdata->resume) {
- ret = host->pdata->resume(dev, host->slot_id);
- if (ret)
- dev_dbg(dev, "Unmask interrupt failed\n");
- }
-
- omap_hsmmc_protect_card(host);
-
- /* Notify the core to resume the host */
- ret = mmc_resume_host(host->mmc);
- if (ret == 0)
- host->suspended = 0;
-
- pm_runtime_mark_last_busy(host->dev);
- pm_runtime_put_autosuspend(host->dev);
-
- return ret;
-
-}
-
-#else
-#define omap_hsmmc_suspend NULL
-#define omap_hsmmc_resume NULL
-#endif
-
-static int omap_hsmmc_runtime_suspend(struct device *dev)
-{
- struct omap_hsmmc_host *host;
-
- host = platform_get_drvdata(to_platform_device(dev));
- omap_hsmmc_context_save(host);
- dev_dbg(dev, "disabled\n");
-
- return 0;
-}
-
-static int omap_hsmmc_runtime_resume(struct device *dev)
-{
- struct omap_hsmmc_host *host;
-
- host = platform_get_drvdata(to_platform_device(dev));
- omap_hsmmc_context_restore(host);
- dev_dbg(dev, "enabled\n");
-
- return 0;
-}
-
-static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
- .suspend = omap_hsmmc_suspend,
- .resume = omap_hsmmc_resume,
- .runtime_suspend = omap_hsmmc_runtime_suspend,
- .runtime_resume = omap_hsmmc_runtime_resume,
-};
-
-static struct platform_driver omap_hsmmc_driver = {
- .probe = omap_hsmmc_probe,
- .remove = __devexit_p(omap_hsmmc_remove),
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- .pm = &omap_hsmmc_dev_pm_ops,
- .of_match_table = of_match_ptr(omap_mmc_of_match),
- },
-};
-
-module_platform_driver(omap_hsmmc_driver);
-MODULE_DESCRIPTION("OMAP High Speed Multimedia Card driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRIVER_NAME);
-MODULE_AUTHOR("Texas Instruments Inc");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/pxamci.c b/ANDROID_3.4.5/drivers/mmc/host/pxamci.c
deleted file mode 100644
index cb2dc0e7..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/pxamci.c
+++ /dev/null
@@ -1,879 +0,0 @@
-/*
- * linux/drivers/mmc/host/pxa.c - PXA MMCI driver
- *
- * Copyright (C) 2003 Russell King, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This hardware is really sick:
- * - No way to clear interrupts.
- * - Have to turn off the clock whenever we touch the device.
- * - Doesn't tell you how many data blocks were transferred.
- * Yuck!
- *
- * 1 and 3 byte data transfers not supported
- * max block length up to 1023
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/mmc/host.h>
-#include <linux/io.h>
-#include <linux/regulator/consumer.h>
-#include <linux/gpio.h>
-#include <linux/gfp.h>
-
-#include <asm/sizes.h>
-
-#include <mach/hardware.h>
-#include <mach/dma.h>
-#include <mach/mmc.h>
-
-#include "pxamci.h"
-
-#define DRIVER_NAME "pxa2xx-mci"
-
-#define NR_SG 1
-#define CLKRT_OFF (~0)
-
-#define mmc_has_26MHz() (cpu_is_pxa300() || cpu_is_pxa310() \
- || cpu_is_pxa935())
-
-struct pxamci_host {
- struct mmc_host *mmc;
- spinlock_t lock;
- struct resource *res;
- void __iomem *base;
- struct clk *clk;
- unsigned long clkrate;
- int irq;
- int dma;
- unsigned int clkrt;
- unsigned int cmdat;
- unsigned int imask;
- unsigned int power_mode;
- struct pxamci_platform_data *pdata;
-
- struct mmc_request *mrq;
- struct mmc_command *cmd;
- struct mmc_data *data;
-
- dma_addr_t sg_dma;
- struct pxa_dma_desc *sg_cpu;
- unsigned int dma_len;
-
- unsigned int dma_dir;
- unsigned int dma_drcmrrx;
- unsigned int dma_drcmrtx;
-
- struct regulator *vcc;
-};
-
-static inline void pxamci_init_ocr(struct pxamci_host *host)
-{
-#ifdef CONFIG_REGULATOR
- host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc");
-
- if (IS_ERR(host->vcc))
- host->vcc = NULL;
- else {
- host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc);
- if (host->pdata && host->pdata->ocr_mask)
- dev_warn(mmc_dev(host->mmc),
- "ocr_mask/setpower will not be used\n");
- }
-#endif
- if (host->vcc == NULL) {
- /* fall-back to platform data */
- host->mmc->ocr_avail = host->pdata ?
- host->pdata->ocr_mask :
- MMC_VDD_32_33 | MMC_VDD_33_34;
- }
-}
-
-static inline int pxamci_set_power(struct pxamci_host *host,
- unsigned char power_mode,
- unsigned int vdd)
-{
- int on;
-
- 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);
- gpio_set_value(host->pdata->gpio_power,
- !!on ^ host->pdata->gpio_power_invert);
- }
- 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)
-{
- if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
- unsigned long timeout = 10000;
- unsigned int v;
-
- writel(STOP_CLOCK, host->base + MMC_STRPCL);
-
- do {
- v = readl(host->base + MMC_STAT);
- if (!(v & STAT_CLK_EN))
- break;
- udelay(1);
- } while (timeout--);
-
- if (v & STAT_CLK_EN)
- dev_err(mmc_dev(host->mmc), "unable to stop clock\n");
- }
-}
-
-static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- host->imask &= ~mask;
- writel(host->imask, host->base + MMC_I_MASK);
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- host->imask |= mask;
- writel(host->imask, host->base + MMC_I_MASK);
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
-{
- unsigned int nob = data->blocks;
- unsigned long long clks;
- unsigned int timeout;
- bool dalgn = 0;
- u32 dcmd;
- int i;
-
- host->data = data;
-
- if (data->flags & MMC_DATA_STREAM)
- nob = 0xffff;
-
- writel(nob, host->base + MMC_NOB);
- writel(data->blksz, host->base + MMC_BLKLEN);
-
- clks = (unsigned long long)data->timeout_ns * host->clkrate;
- do_div(clks, 1000000000UL);
- timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
- writel((timeout + 255) / 256, host->base + MMC_RDTO);
-
- if (data->flags & MMC_DATA_READ) {
- host->dma_dir = DMA_FROM_DEVICE;
- dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC;
- DRCMR(host->dma_drcmrtx) = 0;
- DRCMR(host->dma_drcmrrx) = host->dma | DRCMR_MAPVLD;
- } else {
- host->dma_dir = DMA_TO_DEVICE;
- dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;
- DRCMR(host->dma_drcmrrx) = 0;
- DRCMR(host->dma_drcmrtx) = host->dma | DRCMR_MAPVLD;
- }
-
- dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
-
- host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- host->dma_dir);
-
- for (i = 0; i < host->dma_len; i++) {
- unsigned int length = sg_dma_len(&data->sg[i]);
- host->sg_cpu[i].dcmd = dcmd | length;
- if (length & 31 && !(data->flags & MMC_DATA_READ))
- host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN;
- /* Not aligned to 8-byte boundary? */
- if (sg_dma_address(&data->sg[i]) & 0x7)
- dalgn = 1;
- if (data->flags & MMC_DATA_READ) {
- host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
- host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
- } else {
- host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
- host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
- }
- host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
- sizeof(struct pxa_dma_desc);
- }
- host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
- wmb();
-
- /*
- * The PXA27x DMA controller encounters overhead when working with
- * unaligned (to 8-byte boundaries) data, so switch on byte alignment
- * mode only if we have unaligned data.
- */
- if (dalgn)
- DALGN |= (1 << host->dma);
- else
- DALGN &= ~(1 << host->dma);
- DDADR(host->dma) = host->sg_dma;
-
- /*
- * workaround for erratum #91:
- * only start DMA now if we are doing a read,
- * otherwise we wait until CMD/RESP has finished
- * before starting DMA.
- */
- if (!cpu_is_pxa27x() || data->flags & MMC_DATA_READ)
- DCSR(host->dma) = DCSR_RUN;
-}
-
-static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
-{
- WARN_ON(host->cmd != NULL);
- host->cmd = cmd;
-
- if (cmd->flags & MMC_RSP_BUSY)
- cmdat |= CMDAT_BUSY;
-
-#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
- switch (RSP_TYPE(mmc_resp_type(cmd))) {
- case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6, r7 */
- cmdat |= CMDAT_RESP_SHORT;
- break;
- case RSP_TYPE(MMC_RSP_R3):
- cmdat |= CMDAT_RESP_R3;
- break;
- case RSP_TYPE(MMC_RSP_R2):
- cmdat |= CMDAT_RESP_R2;
- break;
- default:
- break;
- }
-
- writel(cmd->opcode, host->base + MMC_CMD);
- writel(cmd->arg >> 16, host->base + MMC_ARGH);
- writel(cmd->arg & 0xffff, host->base + MMC_ARGL);
- writel(cmdat, host->base + MMC_CMDAT);
- writel(host->clkrt, host->base + MMC_CLKRT);
-
- writel(START_CLOCK, host->base + MMC_STRPCL);
-
- pxamci_enable_irq(host, END_CMD_RES);
-}
-
-static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *mrq)
-{
- host->mrq = NULL;
- host->cmd = NULL;
- host->data = NULL;
- mmc_request_done(host->mmc, mrq);
-}
-
-static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
-{
- struct mmc_command *cmd = host->cmd;
- int i;
- u32 v;
-
- if (!cmd)
- return 0;
-
- host->cmd = NULL;
-
- /*
- * Did I mention this is Sick. We always need to
- * discard the upper 8 bits of the first 16-bit word.
- */
- v = readl(host->base + MMC_RES) & 0xffff;
- for (i = 0; i < 4; i++) {
- u32 w1 = readl(host->base + MMC_RES) & 0xffff;
- u32 w2 = readl(host->base + MMC_RES) & 0xffff;
- cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
- v = w2;
- }
-
- if (stat & STAT_TIME_OUT_RESPONSE) {
- cmd->error = -ETIMEDOUT;
- } else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
- /*
- * workaround for erratum #42:
- * Intel PXA27x Family Processor Specification Update Rev 001
- * A bogus CRC error can appear if the msb of a 136 bit
- * response is a one.
- */
- if (cpu_is_pxa27x() &&
- (cmd->flags & MMC_RSP_136 && cmd->resp[0] & 0x80000000))
- pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode);
- else
- cmd->error = -EILSEQ;
- }
-
- pxamci_disable_irq(host, END_CMD_RES);
- if (host->data && !cmd->error) {
- pxamci_enable_irq(host, DATA_TRAN_DONE);
- /*
- * workaround for erratum #91, if doing write
- * enable DMA late
- */
- if (cpu_is_pxa27x() && host->data->flags & MMC_DATA_WRITE)
- DCSR(host->dma) = DCSR_RUN;
- } else {
- pxamci_finish_request(host, host->mrq);
- }
-
- return 1;
-}
-
-static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
-{
- struct mmc_data *data = host->data;
-
- if (!data)
- return 0;
-
- DCSR(host->dma) = 0;
- dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- host->dma_dir);
-
- if (stat & STAT_READ_TIME_OUT)
- data->error = -ETIMEDOUT;
- else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR))
- data->error = -EILSEQ;
-
- /*
- * There appears to be a hardware design bug here. There seems to
- * be no way to find out how much data was transferred to the card.
- * This means that if there was an error on any block, we mark all
- * data blocks as being in error.
- */
- if (!data->error)
- data->bytes_xfered = data->blocks * data->blksz;
- else
- data->bytes_xfered = 0;
-
- pxamci_disable_irq(host, DATA_TRAN_DONE);
-
- host->data = NULL;
- if (host->mrq->stop) {
- pxamci_stop_clock(host);
- pxamci_start_cmd(host, host->mrq->stop, host->cmdat);
- } else {
- pxamci_finish_request(host, host->mrq);
- }
-
- return 1;
-}
-
-static irqreturn_t pxamci_irq(int irq, void *devid)
-{
- struct pxamci_host *host = devid;
- unsigned int ireg;
- int handled = 0;
-
- ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK);
-
- if (ireg) {
- unsigned stat = readl(host->base + MMC_STAT);
-
- pr_debug("PXAMCI: irq %08x stat %08x\n", ireg, stat);
-
- if (ireg & END_CMD_RES)
- handled |= pxamci_cmd_done(host, stat);
- if (ireg & DATA_TRAN_DONE)
- handled |= pxamci_data_done(host, stat);
- if (ireg & SDIO_INT) {
- mmc_signal_sdio_irq(host->mmc);
- handled = 1;
- }
- }
-
- return IRQ_RETVAL(handled);
-}
-
-static void pxamci_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct pxamci_host *host = mmc_priv(mmc);
- unsigned int cmdat;
-
- WARN_ON(host->mrq != NULL);
-
- host->mrq = mrq;
-
- pxamci_stop_clock(host);
-
- cmdat = host->cmdat;
- host->cmdat &= ~CMDAT_INIT;
-
- if (mrq->data) {
- pxamci_setup_data(host, mrq->data);
-
- cmdat &= ~CMDAT_BUSY;
- cmdat |= CMDAT_DATAEN | CMDAT_DMAEN;
- if (mrq->data->flags & MMC_DATA_WRITE)
- cmdat |= CMDAT_WRITE;
-
- if (mrq->data->flags & MMC_DATA_STREAM)
- cmdat |= CMDAT_STREAM;
- }
-
- pxamci_start_cmd(host, mrq->cmd, cmdat);
-}
-
-static int pxamci_get_ro(struct mmc_host *mmc)
-{
- struct pxamci_host *host = mmc_priv(mmc);
-
- if (host->pdata && gpio_is_valid(host->pdata->gpio_card_ro)) {
- if (host->pdata->gpio_card_ro_invert)
- return !gpio_get_value(host->pdata->gpio_card_ro);
- else
- return gpio_get_value(host->pdata->gpio_card_ro);
- }
- if (host->pdata && host->pdata->get_ro)
- return !!host->pdata->get_ro(mmc_dev(mmc));
- /*
- * Board doesn't support read only detection; let the mmc core
- * decide what to do.
- */
- return -ENOSYS;
-}
-
-static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct pxamci_host *host = mmc_priv(mmc);
-
- if (ios->clock) {
- unsigned long rate = host->clkrate;
- unsigned int clk = rate / ios->clock;
-
- if (host->clkrt == CLKRT_OFF)
- clk_enable(host->clk);
-
- if (ios->clock == 26000000) {
- /* to support 26MHz */
- host->clkrt = 7;
- } else {
- /* to handle (19.5MHz, 26MHz) */
- if (!clk)
- clk = 1;
-
- /*
- * clk might result in a lower divisor than we
- * desire. check for that condition and adjust
- * as appropriate.
- */
- if (rate / clk > ios->clock)
- clk <<= 1;
- host->clkrt = fls(clk) - 1;
- }
-
- /*
- * we write clkrt on the next command
- */
- } else {
- pxamci_stop_clock(host);
- if (host->clkrt != CLKRT_OFF) {
- host->clkrt = CLKRT_OFF;
- clk_disable(host->clk);
- }
- }
-
- if (host->power_mode != ios->power_mode) {
- int ret;
-
- host->power_mode = ios->power_mode;
-
- 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;
- }
-
- if (ios->bus_width == MMC_BUS_WIDTH_4)
- host->cmdat |= CMDAT_SD_4DAT;
- else
- host->cmdat &= ~CMDAT_SD_4DAT;
-
- 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)
-{
- struct pxamci_host *pxa_host = mmc_priv(host);
-
- if (enable)
- pxamci_enable_irq(pxa_host, SDIO_INT);
- else
- pxamci_disable_irq(pxa_host, SDIO_INT);
-}
-
-static const struct mmc_host_ops pxamci_ops = {
- .request = pxamci_request,
- .get_ro = pxamci_get_ro,
- .set_ios = pxamci_set_ios,
- .enable_sdio_irq = pxamci_enable_sdio_irq,
-};
-
-static void pxamci_dma_irq(int dma, void *devid)
-{
- struct pxamci_host *host = devid;
- int dcsr = DCSR(dma);
- DCSR(dma) = dcsr & ~DCSR_STOPIRQEN;
-
- if (dcsr & DCSR_ENDINTR) {
- writel(BUF_PART_FULL, host->base + MMC_PRTBUF);
- } else {
- pr_err("%s: DMA error on channel %d (DCSR=%#x)\n",
- mmc_hostname(host->mmc), dma, dcsr);
- host->data->error = -EIO;
- pxamci_data_done(host, 0);
- }
-}
-
-static irqreturn_t pxamci_detect_irq(int irq, void *devid)
-{
- struct pxamci_host *host = mmc_priv(devid);
-
- mmc_detect_change(devid, msecs_to_jiffies(host->pdata->detect_delay_ms));
- return IRQ_HANDLED;
-}
-
-static int pxamci_probe(struct platform_device *pdev)
-{
- struct mmc_host *mmc;
- struct pxamci_host *host = NULL;
- struct resource *r, *dmarx, *dmatx;
- int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
-
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
- if (!r || irq < 0)
- return -ENXIO;
-
- r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
- if (!r)
- return -EBUSY;
-
- mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev);
- if (!mmc) {
- ret = -ENOMEM;
- goto out;
- }
-
- mmc->ops = &pxamci_ops;
-
- /*
- * We can do SG-DMA, but we don't because we never know how much
- * data we successfully wrote to the card.
- */
- mmc->max_segs = NR_SG;
-
- /*
- * Our hardware DMA can handle a maximum of one page per SG entry.
- */
- mmc->max_seg_size = PAGE_SIZE;
-
- /*
- * Block length register is only 10 bits before PXA27x.
- */
- mmc->max_blk_size = cpu_is_pxa25x() ? 1023 : 2048;
-
- /*
- * Block count register is 16 bits.
- */
- mmc->max_blk_count = 65535;
-
- host = mmc_priv(mmc);
- host->mmc = mmc;
- host->dma = -1;
- host->pdata = pdev->dev.platform_data;
- host->clkrt = CLKRT_OFF;
-
- host->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(host->clk)) {
- ret = PTR_ERR(host->clk);
- host->clk = NULL;
- goto out;
- }
-
- host->clkrate = clk_get_rate(host->clk);
-
- /*
- * Calculate minimum clock rate, rounding up.
- */
- mmc->f_min = (host->clkrate + 63) / 64;
- mmc->f_max = (mmc_has_26MHz()) ? 26000000 : host->clkrate;
-
- pxamci_init_ocr(host);
-
- mmc->caps = 0;
- host->cmdat = 0;
- if (!cpu_is_pxa25x()) {
- mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
- host->cmdat |= CMDAT_SDIO_INT_EN;
- if (mmc_has_26MHz())
- mmc->caps |= MMC_CAP_MMC_HIGHSPEED |
- MMC_CAP_SD_HIGHSPEED;
- }
-
- host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
- if (!host->sg_cpu) {
- ret = -ENOMEM;
- goto out;
- }
-
- spin_lock_init(&host->lock);
- host->res = r;
- host->irq = irq;
- host->imask = MMC_I_MASK_ALL;
-
- host->base = ioremap(r->start, SZ_4K);
- if (!host->base) {
- ret = -ENOMEM;
- goto out;
- }
-
- /*
- * Ensure that the host controller is shut down, and setup
- * with our defaults.
- */
- pxamci_stop_clock(host);
- writel(0, host->base + MMC_SPI);
- writel(64, host->base + MMC_RESTO);
- writel(host->imask, host->base + MMC_I_MASK);
-
- host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW,
- pxamci_dma_irq, host);
- if (host->dma < 0) {
- ret = -EBUSY;
- goto out;
- }
-
- ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host);
- if (ret)
- goto out;
-
- platform_set_drvdata(pdev, mmc);
-
- dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!dmarx) {
- ret = -ENXIO;
- goto out;
- }
- host->dma_drcmrrx = dmarx->start;
-
- dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (!dmatx) {
- ret = -ENXIO;
- goto out;
- }
- host->dma_drcmrtx = dmatx->start;
-
- if (host->pdata) {
- gpio_cd = host->pdata->gpio_card_detect;
- gpio_ro = host->pdata->gpio_card_ro;
- gpio_power = host->pdata->gpio_power;
- }
- if (gpio_is_valid(gpio_power)) {
- ret = gpio_request(gpio_power, "mmc card power");
- if (ret) {
- dev_err(&pdev->dev, "Failed requesting gpio_power %d\n", gpio_power);
- goto out;
- }
- gpio_direction_output(gpio_power,
- host->pdata->gpio_power_invert);
- }
- if (gpio_is_valid(gpio_ro)) {
- ret = gpio_request(gpio_ro, "mmc card read only");
- if (ret) {
- dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n", gpio_ro);
- goto err_gpio_ro;
- }
- gpio_direction_input(gpio_ro);
- }
- if (gpio_is_valid(gpio_cd)) {
- ret = gpio_request(gpio_cd, "mmc card detect");
- if (ret) {
- dev_err(&pdev->dev, "Failed requesting gpio_cd %d\n", gpio_cd);
- goto err_gpio_cd;
- }
- gpio_direction_input(gpio_cd);
-
- ret = request_irq(gpio_to_irq(gpio_cd), pxamci_detect_irq,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "mmc card detect", mmc);
- if (ret) {
- dev_err(&pdev->dev, "failed to request card detect IRQ\n");
- goto err_request_irq;
- }
- }
-
- if (host->pdata && host->pdata->init)
- host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc);
-
- if (gpio_is_valid(gpio_power) && host->pdata->setpower)
- dev_warn(&pdev->dev, "gpio_power and setpower() both defined\n");
- if (gpio_is_valid(gpio_ro) && host->pdata->get_ro)
- dev_warn(&pdev->dev, "gpio_ro and get_ro() both defined\n");
-
- mmc_add_host(mmc);
-
- return 0;
-
-err_request_irq:
- gpio_free(gpio_cd);
-err_gpio_cd:
- gpio_free(gpio_ro);
-err_gpio_ro:
- gpio_free(gpio_power);
- out:
- if (host) {
- if (host->dma >= 0)
- pxa_free_dma(host->dma);
- if (host->base)
- iounmap(host->base);
- if (host->sg_cpu)
- dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
- if (host->clk)
- clk_put(host->clk);
- }
- if (mmc)
- mmc_free_host(mmc);
- release_resource(r);
- return ret;
-}
-
-static int pxamci_remove(struct platform_device *pdev)
-{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
- int gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
-
- platform_set_drvdata(pdev, NULL);
-
- if (mmc) {
- struct pxamci_host *host = mmc_priv(mmc);
-
- mmc_remove_host(mmc);
-
- if (host->pdata) {
- gpio_cd = host->pdata->gpio_card_detect;
- gpio_ro = host->pdata->gpio_card_ro;
- gpio_power = host->pdata->gpio_power;
- }
- if (gpio_is_valid(gpio_cd)) {
- free_irq(gpio_to_irq(gpio_cd), mmc);
- gpio_free(gpio_cd);
- }
- if (gpio_is_valid(gpio_ro))
- gpio_free(gpio_ro);
- if (gpio_is_valid(gpio_power))
- gpio_free(gpio_power);
- if (host->vcc)
- regulator_put(host->vcc);
-
- if (host->pdata && host->pdata->exit)
- host->pdata->exit(&pdev->dev, mmc);
-
- pxamci_stop_clock(host);
- writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
- END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
- host->base + MMC_I_MASK);
-
- DRCMR(host->dma_drcmrrx) = 0;
- DRCMR(host->dma_drcmrtx) = 0;
-
- free_irq(host->irq, host);
- pxa_free_dma(host->dma);
- iounmap(host->base);
- dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
-
- clk_put(host->clk);
-
- release_resource(host->res);
-
- mmc_free_host(mmc);
- }
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int pxamci_suspend(struct device *dev)
-{
- struct mmc_host *mmc = dev_get_drvdata(dev);
- int ret = 0;
-
- if (mmc)
- ret = mmc_suspend_host(mmc);
-
- return ret;
-}
-
-static int pxamci_resume(struct device *dev)
-{
- struct mmc_host *mmc = dev_get_drvdata(dev);
- int ret = 0;
-
- if (mmc)
- ret = mmc_resume_host(mmc);
-
- return ret;
-}
-
-static const struct dev_pm_ops pxamci_pm_ops = {
- .suspend = pxamci_suspend,
- .resume = pxamci_resume,
-};
-#endif
-
-static struct platform_driver pxamci_driver = {
- .probe = pxamci_probe,
- .remove = pxamci_remove,
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
-#ifdef CONFIG_PM
- .pm = &pxamci_pm_ops,
-#endif
- },
-};
-
-module_platform_driver(pxamci_driver);
-
-MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:pxa2xx-mci");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/pxamci.h b/ANDROID_3.4.5/drivers/mmc/host/pxamci.h
deleted file mode 100644
index f6c2e2fc..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/pxamci.h
+++ /dev/null
@@ -1,90 +0,0 @@
-#define MMC_STRPCL 0x0000
-#define STOP_CLOCK (1 << 0)
-#define START_CLOCK (2 << 0)
-
-#define MMC_STAT 0x0004
-#define STAT_END_CMD_RES (1 << 13)
-#define STAT_PRG_DONE (1 << 12)
-#define STAT_DATA_TRAN_DONE (1 << 11)
-#define STAT_CLK_EN (1 << 8)
-#define STAT_RECV_FIFO_FULL (1 << 7)
-#define STAT_XMIT_FIFO_EMPTY (1 << 6)
-#define STAT_RES_CRC_ERR (1 << 5)
-#define STAT_SPI_READ_ERROR_TOKEN (1 << 4)
-#define STAT_CRC_READ_ERROR (1 << 3)
-#define STAT_CRC_WRITE_ERROR (1 << 2)
-#define STAT_TIME_OUT_RESPONSE (1 << 1)
-#define STAT_READ_TIME_OUT (1 << 0)
-
-#define MMC_CLKRT 0x0008 /* 3 bit */
-
-#define MMC_SPI 0x000c
-#define SPI_CS_ADDRESS (1 << 3)
-#define SPI_CS_EN (1 << 2)
-#define CRC_ON (1 << 1)
-#define SPI_EN (1 << 0)
-
-#define MMC_CMDAT 0x0010
-#define CMDAT_SDIO_INT_EN (1 << 11)
-#define CMDAT_SD_4DAT (1 << 8)
-#define CMDAT_DMAEN (1 << 7)
-#define CMDAT_INIT (1 << 6)
-#define CMDAT_BUSY (1 << 5)
-#define CMDAT_STREAM (1 << 4) /* 1 = stream */
-#define CMDAT_WRITE (1 << 3) /* 1 = write */
-#define CMDAT_DATAEN (1 << 2)
-#define CMDAT_RESP_NONE (0 << 0)
-#define CMDAT_RESP_SHORT (1 << 0)
-#define CMDAT_RESP_R2 (2 << 0)
-#define CMDAT_RESP_R3 (3 << 0)
-
-#define MMC_RESTO 0x0014 /* 7 bit */
-
-#define MMC_RDTO 0x0018 /* 16 bit */
-
-#define MMC_BLKLEN 0x001c /* 10 bit */
-
-#define MMC_NOB 0x0020 /* 16 bit */
-
-#define MMC_PRTBUF 0x0024
-#define BUF_PART_FULL (1 << 0)
-
-#define MMC_I_MASK 0x0028
-
-/*PXA27x MMC interrupts*/
-#define SDIO_SUSPEND_ACK (1 << 12)
-#define SDIO_INT (1 << 11)
-#define RD_STALLED (1 << 10)
-#define RES_ERR (1 << 9)
-#define DAT_ERR (1 << 8)
-#define TINT (1 << 7)
-
-/*PXA2xx MMC interrupts*/
-#define TXFIFO_WR_REQ (1 << 6)
-#define RXFIFO_RD_REQ (1 << 5)
-#define CLK_IS_OFF (1 << 4)
-#define STOP_CMD (1 << 3)
-#define END_CMD_RES (1 << 2)
-#define PRG_DONE (1 << 1)
-#define DATA_TRAN_DONE (1 << 0)
-
-#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
-#define MMC_I_MASK_ALL 0x00001fff
-#else
-#define MMC_I_MASK_ALL 0x0000007f
-#endif
-
-#define MMC_I_REG 0x002c
-/* same as MMC_I_MASK */
-
-#define MMC_CMD 0x0030
-
-#define MMC_ARGH 0x0034 /* 16 bit */
-
-#define MMC_ARGL 0x0038 /* 16 bit */
-
-#define MMC_RES 0x003c /* 16 bit */
-
-#define MMC_RXFIFO 0x0040 /* 8 bit */
-
-#define MMC_TXFIFO 0x0044 /* 8 bit */
diff --git a/ANDROID_3.4.5/drivers/mmc/host/s3cmci.c b/ANDROID_3.4.5/drivers/mmc/host/s3cmci.c
deleted file mode 100644
index c3622a69..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/s3cmci.c
+++ /dev/null
@@ -1,1921 +0,0 @@
-/*
- * linux/drivers/mmc/s3cmci.h - Samsung S3C MCI driver
- *
- * Copyright (C) 2004-2006 maintech GmbH, Thomas Kleffel <tk@maintech.de>
- *
- * Current driver maintained by Ben Dooks and Simtec Electronics
- * Copyright (C) 2008 Simtec Electronics <ben-linux@fluff.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk.h>
-#include <linux/mmc/host.h>
-#include <linux/platform_device.h>
-#include <linux/cpufreq.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/gpio.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-
-#include <mach/dma.h>
-
-#include <mach/regs-sdi.h>
-#include <mach/regs-gpio.h>
-
-#include <plat/mci.h>
-
-#include "s3cmci.h"
-
-#define DRIVER_NAME "s3c-mci"
-
-enum dbg_channels {
- dbg_err = (1 << 0),
- dbg_debug = (1 << 1),
- dbg_info = (1 << 2),
- dbg_irq = (1 << 3),
- dbg_sg = (1 << 4),
- dbg_dma = (1 << 5),
- dbg_pio = (1 << 6),
- dbg_fail = (1 << 7),
- dbg_conf = (1 << 8),
-};
-
-static const int dbgmap_err = dbg_fail;
-static const int dbgmap_info = dbg_info | dbg_conf;
-static const int dbgmap_debug = dbg_err | dbg_debug;
-
-#define dbg(host, channels, args...) \
- do { \
- if (dbgmap_err & channels) \
- dev_err(&host->pdev->dev, args); \
- else if (dbgmap_info & channels) \
- dev_info(&host->pdev->dev, args); \
- else if (dbgmap_debug & channels) \
- dev_dbg(&host->pdev->dev, args); \
- } while (0)
-
-static struct s3c2410_dma_client s3cmci_dma_client = {
- .name = "s3c-mci",
-};
-
-static void finalize_request(struct s3cmci_host *host);
-static void s3cmci_send_request(struct mmc_host *mmc);
-static void s3cmci_reset(struct s3cmci_host *host);
-
-#ifdef CONFIG_MMC_DEBUG
-
-static void dbg_dumpregs(struct s3cmci_host *host, char *prefix)
-{
- u32 con, pre, cmdarg, cmdcon, cmdsta, r0, r1, r2, r3, timer, bsize;
- u32 datcon, datcnt, datsta, fsta, imask;
-
- con = readl(host->base + S3C2410_SDICON);
- pre = readl(host->base + S3C2410_SDIPRE);
- cmdarg = readl(host->base + S3C2410_SDICMDARG);
- cmdcon = readl(host->base + S3C2410_SDICMDCON);
- cmdsta = readl(host->base + S3C2410_SDICMDSTAT);
- r0 = readl(host->base + S3C2410_SDIRSP0);
- r1 = readl(host->base + S3C2410_SDIRSP1);
- r2 = readl(host->base + S3C2410_SDIRSP2);
- r3 = readl(host->base + S3C2410_SDIRSP3);
- timer = readl(host->base + S3C2410_SDITIMER);
- bsize = readl(host->base + S3C2410_SDIBSIZE);
- datcon = readl(host->base + S3C2410_SDIDCON);
- datcnt = readl(host->base + S3C2410_SDIDCNT);
- datsta = readl(host->base + S3C2410_SDIDSTA);
- fsta = readl(host->base + S3C2410_SDIFSTA);
- imask = readl(host->base + host->sdiimsk);
-
- dbg(host, dbg_debug, "%s CON:[%08x] PRE:[%08x] TMR:[%08x]\n",
- prefix, con, pre, timer);
-
- dbg(host, dbg_debug, "%s CCON:[%08x] CARG:[%08x] CSTA:[%08x]\n",
- prefix, cmdcon, cmdarg, cmdsta);
-
- dbg(host, dbg_debug, "%s DCON:[%08x] FSTA:[%08x]"
- " DSTA:[%08x] DCNT:[%08x]\n",
- prefix, datcon, fsta, datsta, datcnt);
-
- dbg(host, dbg_debug, "%s R0:[%08x] R1:[%08x]"
- " R2:[%08x] R3:[%08x]\n",
- prefix, r0, r1, r2, r3);
-}
-
-static void prepare_dbgmsg(struct s3cmci_host *host, struct mmc_command *cmd,
- int stop)
-{
- snprintf(host->dbgmsg_cmd, 300,
- "#%u%s op:%i arg:0x%08x flags:0x08%x retries:%u",
- host->ccnt, (stop ? " (STOP)" : ""),
- cmd->opcode, cmd->arg, cmd->flags, cmd->retries);
-
- if (cmd->data) {
- snprintf(host->dbgmsg_dat, 300,
- "#%u bsize:%u blocks:%u bytes:%u",
- host->dcnt, cmd->data->blksz,
- cmd->data->blocks,
- cmd->data->blocks * cmd->data->blksz);
- } else {
- host->dbgmsg_dat[0] = '\0';
- }
-}
-
-static void dbg_dumpcmd(struct s3cmci_host *host, struct mmc_command *cmd,
- int fail)
-{
- unsigned int dbglvl = fail ? dbg_fail : dbg_debug;
-
- if (!cmd)
- return;
-
- if (cmd->error == 0) {
- dbg(host, dbglvl, "CMD[OK] %s R0:0x%08x\n",
- host->dbgmsg_cmd, cmd->resp[0]);
- } else {
- dbg(host, dbglvl, "CMD[ERR %i] %s Status:%s\n",
- cmd->error, host->dbgmsg_cmd, host->status);
- }
-
- if (!cmd->data)
- return;
-
- if (cmd->data->error == 0) {
- dbg(host, dbglvl, "DAT[OK] %s\n", host->dbgmsg_dat);
- } else {
- dbg(host, dbglvl, "DAT[ERR %i] %s DCNT:0x%08x\n",
- cmd->data->error, host->dbgmsg_dat,
- readl(host->base + S3C2410_SDIDCNT));
- }
-}
-#else
-static void dbg_dumpcmd(struct s3cmci_host *host,
- struct mmc_command *cmd, int fail) { }
-
-static void prepare_dbgmsg(struct s3cmci_host *host, struct mmc_command *cmd,
- int stop) { }
-
-static void dbg_dumpregs(struct s3cmci_host *host, char *prefix) { }
-
-#endif /* CONFIG_MMC_DEBUG */
-
-/**
- * s3cmci_host_usedma - return whether the host is using dma or pio
- * @host: The host state
- *
- * Return true if the host is using DMA to transfer data, else false
- * to use PIO mode. Will return static data depending on the driver
- * configuration.
- */
-static inline bool s3cmci_host_usedma(struct s3cmci_host *host)
-{
-#ifdef CONFIG_MMC_S3C_PIO
- return false;
-#elif defined(CONFIG_MMC_S3C_DMA)
- return true;
-#else
- return host->dodma;
-#endif
-}
-
-/**
- * s3cmci_host_canpio - return true if host has pio code available
- *
- * Return true if the driver has been compiled with the PIO support code
- * available.
- */
-static inline bool s3cmci_host_canpio(void)
-{
-#ifdef CONFIG_MMC_S3C_PIO
- return true;
-#else
- return false;
-#endif
-}
-
-static inline u32 enable_imask(struct s3cmci_host *host, u32 imask)
-{
- u32 newmask;
-
- newmask = readl(host->base + host->sdiimsk);
- newmask |= imask;
-
- writel(newmask, host->base + host->sdiimsk);
-
- return newmask;
-}
-
-static inline u32 disable_imask(struct s3cmci_host *host, u32 imask)
-{
- u32 newmask;
-
- newmask = readl(host->base + host->sdiimsk);
- newmask &= ~imask;
-
- writel(newmask, host->base + host->sdiimsk);
-
- return newmask;
-}
-
-static inline void clear_imask(struct s3cmci_host *host)
-{
- u32 mask = readl(host->base + host->sdiimsk);
-
- /* preserve the SDIO IRQ mask state */
- mask &= S3C2410_SDIIMSK_SDIOIRQ;
- writel(mask, host->base + host->sdiimsk);
-}
-
-/**
- * s3cmci_check_sdio_irq - test whether the SDIO IRQ is being signalled
- * @host: The host to check.
- *
- * Test to see if the SDIO interrupt is being signalled in case the
- * controller has failed to re-detect a card interrupt. Read GPE8 and
- * see if it is low and if so, signal a SDIO interrupt.
- *
- * This is currently called if a request is finished (we assume that the
- * bus is now idle) and when the SDIO IRQ is enabled in case the IRQ is
- * already being indicated.
-*/
-static void s3cmci_check_sdio_irq(struct s3cmci_host *host)
-{
- if (host->sdio_irqen) {
- if (gpio_get_value(S3C2410_GPE(8)) == 0) {
- pr_debug("%s: signalling irq\n", __func__);
- mmc_signal_sdio_irq(host->mmc);
- }
- }
-}
-
-static inline int get_data_buffer(struct s3cmci_host *host,
- u32 *bytes, u32 **pointer)
-{
- struct scatterlist *sg;
-
- if (host->pio_active == XFER_NONE)
- return -EINVAL;
-
- if ((!host->mrq) || (!host->mrq->data))
- return -EINVAL;
-
- if (host->pio_sgptr >= host->mrq->data->sg_len) {
- dbg(host, dbg_debug, "no more buffers (%i/%i)\n",
- host->pio_sgptr, host->mrq->data->sg_len);
- return -EBUSY;
- }
- sg = &host->mrq->data->sg[host->pio_sgptr];
-
- *bytes = sg->length;
- *pointer = sg_virt(sg);
-
- host->pio_sgptr++;
-
- dbg(host, dbg_sg, "new buffer (%i/%i)\n",
- host->pio_sgptr, host->mrq->data->sg_len);
-
- return 0;
-}
-
-static inline u32 fifo_count(struct s3cmci_host *host)
-{
- u32 fifostat = readl(host->base + S3C2410_SDIFSTA);
-
- fifostat &= S3C2410_SDIFSTA_COUNTMASK;
- return fifostat;
-}
-
-static inline u32 fifo_free(struct s3cmci_host *host)
-{
- u32 fifostat = readl(host->base + S3C2410_SDIFSTA);
-
- fifostat &= S3C2410_SDIFSTA_COUNTMASK;
- return 63 - fifostat;
-}
-
-/**
- * s3cmci_enable_irq - enable IRQ, after having disabled it.
- * @host: The device state.
- * @more: True if more IRQs are expected from transfer.
- *
- * Enable the main IRQ if needed after it has been disabled.
- *
- * The IRQ can be one of the following states:
- * - disabled during IDLE
- * - disabled whilst processing data
- * - enabled during transfer
- * - enabled whilst awaiting SDIO interrupt detection
- */
-static void s3cmci_enable_irq(struct s3cmci_host *host, bool more)
-{
- unsigned long flags;
- bool enable = false;
-
- local_irq_save(flags);
-
- host->irq_enabled = more;
- host->irq_disabled = false;
-
- enable = more | host->sdio_irqen;
-
- if (host->irq_state != enable) {
- host->irq_state = enable;
-
- if (enable)
- enable_irq(host->irq);
- else
- disable_irq(host->irq);
- }
-
- local_irq_restore(flags);
-}
-
-/**
- *
- */
-static void s3cmci_disable_irq(struct s3cmci_host *host, bool transfer)
-{
- unsigned long flags;
-
- local_irq_save(flags);
-
- /* pr_debug("%s: transfer %d\n", __func__, transfer); */
-
- host->irq_disabled = transfer;
-
- if (transfer && host->irq_state) {
- host->irq_state = false;
- disable_irq(host->irq);
- }
-
- local_irq_restore(flags);
-}
-
-static void do_pio_read(struct s3cmci_host *host)
-{
- int res;
- u32 fifo;
- u32 *ptr;
- u32 fifo_words;
- void __iomem *from_ptr;
-
- /* write real prescaler to host, it might be set slow to fix */
- writel(host->prescaler, host->base + S3C2410_SDIPRE);
-
- from_ptr = host->base + host->sdidata;
-
- while ((fifo = fifo_count(host))) {
- if (!host->pio_bytes) {
- res = get_data_buffer(host, &host->pio_bytes,
- &host->pio_ptr);
- if (res) {
- host->pio_active = XFER_NONE;
- host->complete_what = COMPLETION_FINALIZE;
-
- dbg(host, dbg_pio, "pio_read(): "
- "complete (no more data).\n");
- return;
- }
-
- dbg(host, dbg_pio,
- "pio_read(): new target: [%i]@[%p]\n",
- host->pio_bytes, host->pio_ptr);
- }
-
- dbg(host, dbg_pio,
- "pio_read(): fifo:[%02i] buffer:[%03i] dcnt:[%08X]\n",
- fifo, host->pio_bytes,
- readl(host->base + S3C2410_SDIDCNT));
-
- /* If we have reached the end of the block, we can
- * read a word and get 1 to 3 bytes. If we in the
- * middle of the block, we have to read full words,
- * otherwise we will write garbage, so round down to
- * an even multiple of 4. */
- if (fifo >= host->pio_bytes)
- fifo = host->pio_bytes;
- else
- fifo -= fifo & 3;
-
- host->pio_bytes -= fifo;
- host->pio_count += fifo;
-
- fifo_words = fifo >> 2;
- ptr = host->pio_ptr;
- while (fifo_words--)
- *ptr++ = readl(from_ptr);
- host->pio_ptr = ptr;
-
- if (fifo & 3) {
- u32 n = fifo & 3;
- u32 data = readl(from_ptr);
- u8 *p = (u8 *)host->pio_ptr;
-
- while (n--) {
- *p++ = data;
- data >>= 8;
- }
- }
- }
-
- if (!host->pio_bytes) {
- res = get_data_buffer(host, &host->pio_bytes, &host->pio_ptr);
- if (res) {
- dbg(host, dbg_pio,
- "pio_read(): complete (no more buffers).\n");
- host->pio_active = XFER_NONE;
- host->complete_what = COMPLETION_FINALIZE;
-
- return;
- }
- }
-
- enable_imask(host,
- S3C2410_SDIIMSK_RXFIFOHALF | S3C2410_SDIIMSK_RXFIFOLAST);
-}
-
-static void do_pio_write(struct s3cmci_host *host)
-{
- void __iomem *to_ptr;
- int res;
- u32 fifo;
- u32 *ptr;
-
- to_ptr = host->base + host->sdidata;
-
- while ((fifo = fifo_free(host)) > 3) {
- if (!host->pio_bytes) {
- res = get_data_buffer(host, &host->pio_bytes,
- &host->pio_ptr);
- if (res) {
- dbg(host, dbg_pio,
- "pio_write(): complete (no more data).\n");
- host->pio_active = XFER_NONE;
-
- return;
- }
-
- dbg(host, dbg_pio,
- "pio_write(): new source: [%i]@[%p]\n",
- host->pio_bytes, host->pio_ptr);
-
- }
-
- /* If we have reached the end of the block, we have to
- * write exactly the remaining number of bytes. If we
- * in the middle of the block, we have to write full
- * words, so round down to an even multiple of 4. */
- if (fifo >= host->pio_bytes)
- fifo = host->pio_bytes;
- else
- fifo -= fifo & 3;
-
- host->pio_bytes -= fifo;
- host->pio_count += fifo;
-
- fifo = (fifo + 3) >> 2;
- ptr = host->pio_ptr;
- while (fifo--)
- writel(*ptr++, to_ptr);
- host->pio_ptr = ptr;
- }
-
- enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);
-}
-
-static void pio_tasklet(unsigned long data)
-{
- struct s3cmci_host *host = (struct s3cmci_host *) data;
-
- s3cmci_disable_irq(host, true);
-
- if (host->pio_active == XFER_WRITE)
- do_pio_write(host);
-
- if (host->pio_active == XFER_READ)
- do_pio_read(host);
-
- if (host->complete_what == COMPLETION_FINALIZE) {
- clear_imask(host);
- if (host->pio_active != XFER_NONE) {
- dbg(host, dbg_err, "unfinished %s "
- "- pio_count:[%u] pio_bytes:[%u]\n",
- (host->pio_active == XFER_READ) ? "read" : "write",
- host->pio_count, host->pio_bytes);
-
- if (host->mrq->data)
- host->mrq->data->error = -EINVAL;
- }
-
- s3cmci_enable_irq(host, false);
- finalize_request(host);
- } else
- s3cmci_enable_irq(host, true);
-}
-
-/*
- * ISR for SDI Interface IRQ
- * Communication between driver and ISR works as follows:
- * host->mrq points to current request
- * host->complete_what Indicates when the request is considered done
- * COMPLETION_CMDSENT when the command was sent
- * COMPLETION_RSPFIN when a response was received
- * COMPLETION_XFERFINISH when the data transfer is finished
- * COMPLETION_XFERFINISH_RSPFIN both of the above.
- * host->complete_request is the completion-object the driver waits for
- *
- * 1) Driver sets up host->mrq and host->complete_what
- * 2) Driver prepares the transfer
- * 3) Driver enables interrupts
- * 4) Driver starts transfer
- * 5) Driver waits for host->complete_rquest
- * 6) ISR checks for request status (errors and success)
- * 6) ISR sets host->mrq->cmd->error and host->mrq->data->error
- * 7) ISR completes host->complete_request
- * 8) ISR disables interrupts
- * 9) Driver wakes up and takes care of the request
- *
- * Note: "->error"-fields are expected to be set to 0 before the request
- * was issued by mmc.c - therefore they are only set, when an error
- * contition comes up
- */
-
-static irqreturn_t s3cmci_irq(int irq, void *dev_id)
-{
- struct s3cmci_host *host = dev_id;
- struct mmc_command *cmd;
- u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt, mci_imsk;
- u32 mci_cclear = 0, mci_dclear;
- unsigned long iflags;
-
- mci_dsta = readl(host->base + S3C2410_SDIDSTA);
- mci_imsk = readl(host->base + host->sdiimsk);
-
- if (mci_dsta & S3C2410_SDIDSTA_SDIOIRQDETECT) {
- if (mci_imsk & S3C2410_SDIIMSK_SDIOIRQ) {
- mci_dclear = S3C2410_SDIDSTA_SDIOIRQDETECT;
- writel(mci_dclear, host->base + S3C2410_SDIDSTA);
-
- mmc_signal_sdio_irq(host->mmc);
- return IRQ_HANDLED;
- }
- }
-
- spin_lock_irqsave(&host->complete_lock, iflags);
-
- mci_csta = readl(host->base + S3C2410_SDICMDSTAT);
- mci_dcnt = readl(host->base + S3C2410_SDIDCNT);
- mci_fsta = readl(host->base + S3C2410_SDIFSTA);
- mci_dclear = 0;
-
- if ((host->complete_what == COMPLETION_NONE) ||
- (host->complete_what == COMPLETION_FINALIZE)) {
- host->status = "nothing to complete";
- clear_imask(host);
- goto irq_out;
- }
-
- if (!host->mrq) {
- host->status = "no active mrq";
- clear_imask(host);
- goto irq_out;
- }
-
- cmd = host->cmd_is_stop ? host->mrq->stop : host->mrq->cmd;
-
- if (!cmd) {
- host->status = "no active cmd";
- clear_imask(host);
- goto irq_out;
- }
-
- if (!s3cmci_host_usedma(host)) {
- if ((host->pio_active == XFER_WRITE) &&
- (mci_fsta & S3C2410_SDIFSTA_TFDET)) {
-
- disable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);
- tasklet_schedule(&host->pio_tasklet);
- host->status = "pio tx";
- }
-
- if ((host->pio_active == XFER_READ) &&
- (mci_fsta & S3C2410_SDIFSTA_RFDET)) {
-
- disable_imask(host,
- S3C2410_SDIIMSK_RXFIFOHALF |
- S3C2410_SDIIMSK_RXFIFOLAST);
-
- tasklet_schedule(&host->pio_tasklet);
- host->status = "pio rx";
- }
- }
-
- if (mci_csta & S3C2410_SDICMDSTAT_CMDTIMEOUT) {
- dbg(host, dbg_err, "CMDSTAT: error CMDTIMEOUT\n");
- cmd->error = -ETIMEDOUT;
- host->status = "error: command timeout";
- goto fail_transfer;
- }
-
- if (mci_csta & S3C2410_SDICMDSTAT_CMDSENT) {
- if (host->complete_what == COMPLETION_CMDSENT) {
- host->status = "ok: command sent";
- goto close_transfer;
- }
-
- mci_cclear |= S3C2410_SDICMDSTAT_CMDSENT;
- }
-
- if (mci_csta & S3C2410_SDICMDSTAT_CRCFAIL) {
- if (cmd->flags & MMC_RSP_CRC) {
- if (host->mrq->cmd->flags & MMC_RSP_136) {
- dbg(host, dbg_irq,
- "fixup: ignore CRC fail with long rsp\n");
- } else {
- /* note, we used to fail the transfer
- * here, but it seems that this is just
- * the hardware getting it wrong.
- *
- * cmd->error = -EILSEQ;
- * host->status = "error: bad command crc";
- * goto fail_transfer;
- */
- }
- }
-
- mci_cclear |= S3C2410_SDICMDSTAT_CRCFAIL;
- }
-
- if (mci_csta & S3C2410_SDICMDSTAT_RSPFIN) {
- if (host->complete_what == COMPLETION_RSPFIN) {
- host->status = "ok: command response received";
- goto close_transfer;
- }
-
- if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN)
- host->complete_what = COMPLETION_XFERFINISH;
-
- mci_cclear |= S3C2410_SDICMDSTAT_RSPFIN;
- }
-
- /* errors handled after this point are only relevant
- when a data transfer is in progress */
-
- if (!cmd->data)
- goto clear_status_bits;
-
- /* Check for FIFO failure */
- if (host->is2440) {
- if (mci_fsta & S3C2440_SDIFSTA_FIFOFAIL) {
- dbg(host, dbg_err, "FIFO failure\n");
- host->mrq->data->error = -EILSEQ;
- host->status = "error: 2440 fifo failure";
- goto fail_transfer;
- }
- } else {
- if (mci_dsta & S3C2410_SDIDSTA_FIFOFAIL) {
- dbg(host, dbg_err, "FIFO failure\n");
- cmd->data->error = -EILSEQ;
- host->status = "error: fifo failure";
- goto fail_transfer;
- }
- }
-
- if (mci_dsta & S3C2410_SDIDSTA_RXCRCFAIL) {
- dbg(host, dbg_err, "bad data crc (outgoing)\n");
- cmd->data->error = -EILSEQ;
- host->status = "error: bad data crc (outgoing)";
- goto fail_transfer;
- }
-
- if (mci_dsta & S3C2410_SDIDSTA_CRCFAIL) {
- dbg(host, dbg_err, "bad data crc (incoming)\n");
- cmd->data->error = -EILSEQ;
- host->status = "error: bad data crc (incoming)";
- goto fail_transfer;
- }
-
- if (mci_dsta & S3C2410_SDIDSTA_DATATIMEOUT) {
- dbg(host, dbg_err, "data timeout\n");
- cmd->data->error = -ETIMEDOUT;
- host->status = "error: data timeout";
- goto fail_transfer;
- }
-
- if (mci_dsta & S3C2410_SDIDSTA_XFERFINISH) {
- if (host->complete_what == COMPLETION_XFERFINISH) {
- host->status = "ok: data transfer completed";
- goto close_transfer;
- }
-
- if (host->complete_what == COMPLETION_XFERFINISH_RSPFIN)
- host->complete_what = COMPLETION_RSPFIN;
-
- mci_dclear |= S3C2410_SDIDSTA_XFERFINISH;
- }
-
-clear_status_bits:
- writel(mci_cclear, host->base + S3C2410_SDICMDSTAT);
- writel(mci_dclear, host->base + S3C2410_SDIDSTA);
-
- goto irq_out;
-
-fail_transfer:
- host->pio_active = XFER_NONE;
-
-close_transfer:
- host->complete_what = COMPLETION_FINALIZE;
-
- clear_imask(host);
- tasklet_schedule(&host->pio_tasklet);
-
- goto irq_out;
-
-irq_out:
- dbg(host, dbg_irq,
- "csta:0x%08x dsta:0x%08x fsta:0x%08x dcnt:0x%08x status:%s.\n",
- mci_csta, mci_dsta, mci_fsta, mci_dcnt, host->status);
-
- spin_unlock_irqrestore(&host->complete_lock, iflags);
- return IRQ_HANDLED;
-
-}
-
-/*
- * ISR for the CardDetect Pin
-*/
-
-static irqreturn_t s3cmci_irq_cd(int irq, void *dev_id)
-{
- struct s3cmci_host *host = (struct s3cmci_host *)dev_id;
-
- dbg(host, dbg_irq, "card detect\n");
-
- mmc_detect_change(host->mmc, msecs_to_jiffies(500));
-
- return IRQ_HANDLED;
-}
-
-static void s3cmci_dma_done_callback(struct s3c2410_dma_chan *dma_ch,
- void *buf_id, int size,
- enum s3c2410_dma_buffresult result)
-{
- struct s3cmci_host *host = buf_id;
- unsigned long iflags;
- u32 mci_csta, mci_dsta, mci_fsta, mci_dcnt;
-
- mci_csta = readl(host->base + S3C2410_SDICMDSTAT);
- mci_dsta = readl(host->base + S3C2410_SDIDSTA);
- mci_fsta = readl(host->base + S3C2410_SDIFSTA);
- mci_dcnt = readl(host->base + S3C2410_SDIDCNT);
-
- BUG_ON(!host->mrq);
- BUG_ON(!host->mrq->data);
- BUG_ON(!host->dmatogo);
-
- spin_lock_irqsave(&host->complete_lock, iflags);
-
- if (result != S3C2410_RES_OK) {
- dbg(host, dbg_fail, "DMA FAILED: csta=0x%08x dsta=0x%08x "
- "fsta=0x%08x dcnt:0x%08x result:0x%08x toGo:%u\n",
- mci_csta, mci_dsta, mci_fsta,
- mci_dcnt, result, host->dmatogo);
-
- goto fail_request;
- }
-
- host->dmatogo--;
- if (host->dmatogo) {
- dbg(host, dbg_dma, "DMA DONE Size:%i DSTA:[%08x] "
- "DCNT:[%08x] toGo:%u\n",
- size, mci_dsta, mci_dcnt, host->dmatogo);
-
- goto out;
- }
-
- dbg(host, dbg_dma, "DMA FINISHED Size:%i DSTA:%08x DCNT:%08x\n",
- size, mci_dsta, mci_dcnt);
-
- host->dma_complete = 1;
- host->complete_what = COMPLETION_FINALIZE;
-
-out:
- tasklet_schedule(&host->pio_tasklet);
- spin_unlock_irqrestore(&host->complete_lock, iflags);
- return;
-
-fail_request:
- host->mrq->data->error = -EINVAL;
- host->complete_what = COMPLETION_FINALIZE;
- clear_imask(host);
-
- goto out;
-}
-
-static void finalize_request(struct s3cmci_host *host)
-{
- struct mmc_request *mrq = host->mrq;
- struct mmc_command *cmd;
- int debug_as_failure = 0;
-
- if (host->complete_what != COMPLETION_FINALIZE)
- return;
-
- if (!mrq)
- return;
- cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd;
-
- if (cmd->data && (cmd->error == 0) &&
- (cmd->data->error == 0)) {
- if (s3cmci_host_usedma(host) && (!host->dma_complete)) {
- dbg(host, dbg_dma, "DMA Missing (%d)!\n",
- host->dma_complete);
- return;
- }
- }
-
- /* Read response from controller. */
- cmd->resp[0] = readl(host->base + S3C2410_SDIRSP0);
- cmd->resp[1] = readl(host->base + S3C2410_SDIRSP1);
- cmd->resp[2] = readl(host->base + S3C2410_SDIRSP2);
- cmd->resp[3] = readl(host->base + S3C2410_SDIRSP3);
-
- writel(host->prescaler, host->base + S3C2410_SDIPRE);
-
- if (cmd->error)
- debug_as_failure = 1;
-
- if (cmd->data && cmd->data->error)
- debug_as_failure = 1;
-
- dbg_dumpcmd(host, cmd, debug_as_failure);
-
- /* Cleanup controller */
- writel(0, host->base + S3C2410_SDICMDARG);
- writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON);
- writel(0, host->base + S3C2410_SDICMDCON);
- clear_imask(host);
-
- if (cmd->data && cmd->error)
- cmd->data->error = cmd->error;
-
- if (cmd->data && cmd->data->stop && (!host->cmd_is_stop)) {
- host->cmd_is_stop = 1;
- s3cmci_send_request(host->mmc);
- return;
- }
-
- /* If we have no data transfer we are finished here */
- if (!mrq->data)
- goto request_done;
-
- /* Calculate the amout of bytes transfer if there was no error */
- if (mrq->data->error == 0) {
- mrq->data->bytes_xfered =
- (mrq->data->blocks * mrq->data->blksz);
- } else {
- mrq->data->bytes_xfered = 0;
- }
-
- /* If we had an error while transferring data we flush the
- * DMA channel and the fifo to clear out any garbage. */
- if (mrq->data->error != 0) {
- if (s3cmci_host_usedma(host))
- s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
-
- if (host->is2440) {
- /* Clear failure register and reset fifo. */
- writel(S3C2440_SDIFSTA_FIFORESET |
- S3C2440_SDIFSTA_FIFOFAIL,
- host->base + S3C2410_SDIFSTA);
- } else {
- u32 mci_con;
-
- /* reset fifo */
- mci_con = readl(host->base + S3C2410_SDICON);
- mci_con |= S3C2410_SDICON_FIFORESET;
-
- writel(mci_con, host->base + S3C2410_SDICON);
- }
- }
-
-request_done:
- host->complete_what = COMPLETION_NONE;
- host->mrq = NULL;
-
- s3cmci_check_sdio_irq(host);
- mmc_request_done(host->mmc, mrq);
-}
-
-static void s3cmci_dma_setup(struct s3cmci_host *host,
- enum dma_data_direction source)
-{
- static enum dma_data_direction last_source = -1;
- static int setup_ok;
-
- if (last_source == source)
- return;
-
- last_source = source;
-
- s3c2410_dma_devconfig(host->dma, source,
- host->mem->start + host->sdidata);
-
- if (!setup_ok) {
- s3c2410_dma_config(host->dma, 4);
- s3c2410_dma_set_buffdone_fn(host->dma,
- s3cmci_dma_done_callback);
- s3c2410_dma_setflags(host->dma, S3C2410_DMAF_AUTOSTART);
- setup_ok = 1;
- }
-}
-
-static void s3cmci_send_command(struct s3cmci_host *host,
- struct mmc_command *cmd)
-{
- u32 ccon, imsk;
-
- imsk = S3C2410_SDIIMSK_CRCSTATUS | S3C2410_SDIIMSK_CMDTIMEOUT |
- S3C2410_SDIIMSK_RESPONSEND | S3C2410_SDIIMSK_CMDSENT |
- S3C2410_SDIIMSK_RESPONSECRC;
-
- enable_imask(host, imsk);
-
- if (cmd->data)
- host->complete_what = COMPLETION_XFERFINISH_RSPFIN;
- else if (cmd->flags & MMC_RSP_PRESENT)
- host->complete_what = COMPLETION_RSPFIN;
- else
- host->complete_what = COMPLETION_CMDSENT;
-
- writel(cmd->arg, host->base + S3C2410_SDICMDARG);
-
- ccon = cmd->opcode & S3C2410_SDICMDCON_INDEX;
- ccon |= S3C2410_SDICMDCON_SENDERHOST | S3C2410_SDICMDCON_CMDSTART;
-
- if (cmd->flags & MMC_RSP_PRESENT)
- ccon |= S3C2410_SDICMDCON_WAITRSP;
-
- if (cmd->flags & MMC_RSP_136)
- ccon |= S3C2410_SDICMDCON_LONGRSP;
-
- writel(ccon, host->base + S3C2410_SDICMDCON);
-}
-
-static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data)
-{
- u32 dcon, imsk, stoptries = 3;
-
- /* write DCON register */
-
- if (!data) {
- writel(0, host->base + S3C2410_SDIDCON);
- return 0;
- }
-
- if ((data->blksz & 3) != 0) {
- /* We cannot deal with unaligned blocks with more than
- * one block being transferred. */
-
- if (data->blocks > 1) {
- pr_warning("%s: can't do non-word sized block transfers (blksz %d)\n", __func__, data->blksz);
- return -EINVAL;
- }
- }
-
- while (readl(host->base + S3C2410_SDIDSTA) &
- (S3C2410_SDIDSTA_TXDATAON | S3C2410_SDIDSTA_RXDATAON)) {
-
- dbg(host, dbg_err,
- "mci_setup_data() transfer stillin progress.\n");
-
- writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON);
- s3cmci_reset(host);
-
- if ((stoptries--) == 0) {
- dbg_dumpregs(host, "DRF");
- return -EINVAL;
- }
- }
-
- dcon = data->blocks & S3C2410_SDIDCON_BLKNUM_MASK;
-
- if (s3cmci_host_usedma(host))
- dcon |= S3C2410_SDIDCON_DMAEN;
-
- if (host->bus_width == MMC_BUS_WIDTH_4)
- dcon |= S3C2410_SDIDCON_WIDEBUS;
-
- if (!(data->flags & MMC_DATA_STREAM))
- dcon |= S3C2410_SDIDCON_BLOCKMODE;
-
- if (data->flags & MMC_DATA_WRITE) {
- dcon |= S3C2410_SDIDCON_TXAFTERRESP;
- dcon |= S3C2410_SDIDCON_XFER_TXSTART;
- }
-
- if (data->flags & MMC_DATA_READ) {
- dcon |= S3C2410_SDIDCON_RXAFTERCMD;
- dcon |= S3C2410_SDIDCON_XFER_RXSTART;
- }
-
- if (host->is2440) {
- dcon |= S3C2440_SDIDCON_DS_WORD;
- dcon |= S3C2440_SDIDCON_DATSTART;
- }
-
- writel(dcon, host->base + S3C2410_SDIDCON);
-
- /* write BSIZE register */
-
- writel(data->blksz, host->base + S3C2410_SDIBSIZE);
-
- /* add to IMASK register */
- imsk = S3C2410_SDIIMSK_FIFOFAIL | S3C2410_SDIIMSK_DATACRC |
- S3C2410_SDIIMSK_DATATIMEOUT | S3C2410_SDIIMSK_DATAFINISH;
-
- enable_imask(host, imsk);
-
- /* write TIMER register */
-
- if (host->is2440) {
- writel(0x007FFFFF, host->base + S3C2410_SDITIMER);
- } else {
- writel(0x0000FFFF, host->base + S3C2410_SDITIMER);
-
- /* FIX: set slow clock to prevent timeouts on read */
- if (data->flags & MMC_DATA_READ)
- writel(0xFF, host->base + S3C2410_SDIPRE);
- }
-
- return 0;
-}
-
-#define BOTH_DIR (MMC_DATA_WRITE | MMC_DATA_READ)
-
-static int s3cmci_prepare_pio(struct s3cmci_host *host, struct mmc_data *data)
-{
- int rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0;
-
- BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR);
-
- host->pio_sgptr = 0;
- host->pio_bytes = 0;
- host->pio_count = 0;
- host->pio_active = rw ? XFER_WRITE : XFER_READ;
-
- if (rw) {
- do_pio_write(host);
- enable_imask(host, S3C2410_SDIIMSK_TXFIFOHALF);
- } else {
- enable_imask(host, S3C2410_SDIIMSK_RXFIFOHALF
- | S3C2410_SDIIMSK_RXFIFOLAST);
- }
-
- return 0;
-}
-
-static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data)
-{
- int dma_len, i;
- int rw = data->flags & MMC_DATA_WRITE;
-
- BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR);
-
- s3cmci_dma_setup(host, rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
-
- dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-
- if (dma_len == 0)
- return -ENOMEM;
-
- host->dma_complete = 0;
- host->dmatogo = dma_len;
-
- for (i = 0; i < dma_len; i++) {
- int res;
-
- dbg(host, dbg_dma, "enqueue %i: %08x@%u\n", i,
- sg_dma_address(&data->sg[i]),
- sg_dma_len(&data->sg[i]));
-
- res = s3c2410_dma_enqueue(host->dma, host,
- sg_dma_address(&data->sg[i]),
- sg_dma_len(&data->sg[i]));
-
- if (res) {
- s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
- return -EBUSY;
- }
- }
-
- s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_START);
-
- return 0;
-}
-
-static void s3cmci_send_request(struct mmc_host *mmc)
-{
- struct s3cmci_host *host = mmc_priv(mmc);
- struct mmc_request *mrq = host->mrq;
- struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd;
-
- host->ccnt++;
- prepare_dbgmsg(host, cmd, host->cmd_is_stop);
-
- /* Clear command, data and fifo status registers
- Fifo clear only necessary on 2440, but doesn't hurt on 2410
- */
- writel(0xFFFFFFFF, host->base + S3C2410_SDICMDSTAT);
- writel(0xFFFFFFFF, host->base + S3C2410_SDIDSTA);
- writel(0xFFFFFFFF, host->base + S3C2410_SDIFSTA);
-
- if (cmd->data) {
- int res = s3cmci_setup_data(host, cmd->data);
-
- host->dcnt++;
-
- if (res) {
- dbg(host, dbg_err, "setup data error %d\n", res);
- cmd->error = res;
- cmd->data->error = res;
-
- mmc_request_done(mmc, mrq);
- return;
- }
-
- if (s3cmci_host_usedma(host))
- res = s3cmci_prepare_dma(host, cmd->data);
- else
- res = s3cmci_prepare_pio(host, cmd->data);
-
- if (res) {
- dbg(host, dbg_err, "data prepare error %d\n", res);
- cmd->error = res;
- cmd->data->error = res;
-
- mmc_request_done(mmc, mrq);
- return;
- }
- }
-
- /* Send command */
- s3cmci_send_command(host, cmd);
-
- /* Enable Interrupt */
- s3cmci_enable_irq(host, true);
-}
-
-static int s3cmci_card_present(struct mmc_host *mmc)
-{
- struct s3cmci_host *host = mmc_priv(mmc);
- struct s3c24xx_mci_pdata *pdata = host->pdata;
- int ret;
-
- if (pdata->no_detect)
- return -ENOSYS;
-
- ret = gpio_get_value(pdata->gpio_detect) ? 0 : 1;
- return ret ^ pdata->detect_invert;
-}
-
-static void s3cmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct s3cmci_host *host = mmc_priv(mmc);
-
- host->status = "mmc request";
- host->cmd_is_stop = 0;
- host->mrq = mrq;
-
- if (s3cmci_card_present(mmc) == 0) {
- dbg(host, dbg_err, "%s: no medium present\n", __func__);
- host->mrq->cmd->error = -ENOMEDIUM;
- mmc_request_done(mmc, mrq);
- } else
- s3cmci_send_request(mmc);
-}
-
-static void s3cmci_set_clk(struct s3cmci_host *host, struct mmc_ios *ios)
-{
- u32 mci_psc;
-
- /* Set clock */
- for (mci_psc = 0; mci_psc < 255; mci_psc++) {
- host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1));
-
- if (host->real_rate <= ios->clock)
- break;
- }
-
- if (mci_psc > 255)
- mci_psc = 255;
-
- host->prescaler = mci_psc;
- writel(host->prescaler, host->base + S3C2410_SDIPRE);
-
- /* If requested clock is 0, real_rate will be 0, too */
- if (ios->clock == 0)
- host->real_rate = 0;
-}
-
-static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct s3cmci_host *host = mmc_priv(mmc);
- u32 mci_con;
-
- /* Set the power state */
-
- mci_con = readl(host->base + S3C2410_SDICON);
-
- switch (ios->power_mode) {
- case MMC_POWER_ON:
- case MMC_POWER_UP:
- s3c2410_gpio_cfgpin(S3C2410_GPE(5), S3C2410_GPE5_SDCLK);
- s3c2410_gpio_cfgpin(S3C2410_GPE(6), S3C2410_GPE6_SDCMD);
- s3c2410_gpio_cfgpin(S3C2410_GPE(7), S3C2410_GPE7_SDDAT0);
- s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1);
- s3c2410_gpio_cfgpin(S3C2410_GPE(9), S3C2410_GPE9_SDDAT2);
- s3c2410_gpio_cfgpin(S3C2410_GPE(10), S3C2410_GPE10_SDDAT3);
-
- if (host->pdata->set_power)
- host->pdata->set_power(ios->power_mode, ios->vdd);
-
- if (!host->is2440)
- mci_con |= S3C2410_SDICON_FIFORESET;
-
- break;
-
- case MMC_POWER_OFF:
- default:
- gpio_direction_output(S3C2410_GPE(5), 0);
-
- if (host->is2440)
- mci_con |= S3C2440_SDICON_SDRESET;
-
- if (host->pdata->set_power)
- host->pdata->set_power(ios->power_mode, ios->vdd);
-
- break;
- }
-
- s3cmci_set_clk(host, ios);
-
- /* Set CLOCK_ENABLE */
- if (ios->clock)
- mci_con |= S3C2410_SDICON_CLOCKTYPE;
- else
- mci_con &= ~S3C2410_SDICON_CLOCKTYPE;
-
- writel(mci_con, host->base + S3C2410_SDICON);
-
- if ((ios->power_mode == MMC_POWER_ON) ||
- (ios->power_mode == MMC_POWER_UP)) {
- dbg(host, dbg_conf, "running at %lukHz (requested: %ukHz).\n",
- host->real_rate/1000, ios->clock/1000);
- } else {
- dbg(host, dbg_conf, "powered down.\n");
- }
-
- host->bus_width = ios->bus_width;
-}
-
-static void s3cmci_reset(struct s3cmci_host *host)
-{
- u32 con = readl(host->base + S3C2410_SDICON);
-
- con |= S3C2440_SDICON_SDRESET;
- writel(con, host->base + S3C2410_SDICON);
-}
-
-static int s3cmci_get_ro(struct mmc_host *mmc)
-{
- struct s3cmci_host *host = mmc_priv(mmc);
- struct s3c24xx_mci_pdata *pdata = host->pdata;
- int ret;
-
- if (pdata->no_wprotect)
- return 0;
-
- ret = gpio_get_value(pdata->gpio_wprotect) ? 1 : 0;
- ret ^= pdata->wprotect_invert;
-
- return ret;
-}
-
-static void s3cmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
- struct s3cmci_host *host = mmc_priv(mmc);
- unsigned long flags;
- u32 con;
-
- local_irq_save(flags);
-
- con = readl(host->base + S3C2410_SDICON);
- host->sdio_irqen = enable;
-
- if (enable == host->sdio_irqen)
- goto same_state;
-
- if (enable) {
- con |= S3C2410_SDICON_SDIOIRQ;
- enable_imask(host, S3C2410_SDIIMSK_SDIOIRQ);
-
- if (!host->irq_state && !host->irq_disabled) {
- host->irq_state = true;
- enable_irq(host->irq);
- }
- } else {
- disable_imask(host, S3C2410_SDIIMSK_SDIOIRQ);
- con &= ~S3C2410_SDICON_SDIOIRQ;
-
- if (!host->irq_enabled && host->irq_state) {
- disable_irq_nosync(host->irq);
- host->irq_state = false;
- }
- }
-
- writel(con, host->base + S3C2410_SDICON);
-
- same_state:
- local_irq_restore(flags);
-
- s3cmci_check_sdio_irq(host);
-}
-
-static struct mmc_host_ops s3cmci_ops = {
- .request = s3cmci_request,
- .set_ios = s3cmci_set_ios,
- .get_ro = s3cmci_get_ro,
- .get_cd = s3cmci_card_present,
- .enable_sdio_irq = s3cmci_enable_sdio_irq,
-};
-
-static struct s3c24xx_mci_pdata s3cmci_def_pdata = {
- /* This is currently here to avoid a number of if (host->pdata)
- * checks. Any zero fields to ensure reasonable defaults are picked. */
- .no_wprotect = 1,
- .no_detect = 1,
-};
-
-#ifdef CONFIG_CPU_FREQ
-
-static int s3cmci_cpufreq_transition(struct notifier_block *nb,
- unsigned long val, void *data)
-{
- struct s3cmci_host *host;
- struct mmc_host *mmc;
- unsigned long newclk;
- unsigned long flags;
-
- host = container_of(nb, struct s3cmci_host, freq_transition);
- newclk = clk_get_rate(host->clk);
- mmc = host->mmc;
-
- if ((val == CPUFREQ_PRECHANGE && newclk > host->clk_rate) ||
- (val == CPUFREQ_POSTCHANGE && newclk < host->clk_rate)) {
- spin_lock_irqsave(&mmc->lock, flags);
-
- host->clk_rate = newclk;
-
- if (mmc->ios.power_mode != MMC_POWER_OFF &&
- mmc->ios.clock != 0)
- s3cmci_set_clk(host, &mmc->ios);
-
- spin_unlock_irqrestore(&mmc->lock, flags);
- }
-
- return 0;
-}
-
-static inline int s3cmci_cpufreq_register(struct s3cmci_host *host)
-{
- host->freq_transition.notifier_call = s3cmci_cpufreq_transition;
-
- return cpufreq_register_notifier(&host->freq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
-}
-
-static inline void s3cmci_cpufreq_deregister(struct s3cmci_host *host)
-{
- cpufreq_unregister_notifier(&host->freq_transition,
- CPUFREQ_TRANSITION_NOTIFIER);
-}
-
-#else
-static inline int s3cmci_cpufreq_register(struct s3cmci_host *host)
-{
- return 0;
-}
-
-static inline void s3cmci_cpufreq_deregister(struct s3cmci_host *host)
-{
-}
-#endif
-
-
-#ifdef CONFIG_DEBUG_FS
-
-static int s3cmci_state_show(struct seq_file *seq, void *v)
-{
- struct s3cmci_host *host = seq->private;
-
- seq_printf(seq, "Register base = 0x%08x\n", (u32)host->base);
- seq_printf(seq, "Clock rate = %ld\n", host->clk_rate);
- seq_printf(seq, "Prescale = %d\n", host->prescaler);
- seq_printf(seq, "is2440 = %d\n", host->is2440);
- seq_printf(seq, "IRQ = %d\n", host->irq);
- seq_printf(seq, "IRQ enabled = %d\n", host->irq_enabled);
- seq_printf(seq, "IRQ disabled = %d\n", host->irq_disabled);
- seq_printf(seq, "IRQ state = %d\n", host->irq_state);
- seq_printf(seq, "CD IRQ = %d\n", host->irq_cd);
- seq_printf(seq, "Do DMA = %d\n", s3cmci_host_usedma(host));
- seq_printf(seq, "SDIIMSK at %d\n", host->sdiimsk);
- seq_printf(seq, "SDIDATA at %d\n", host->sdidata);
-
- return 0;
-}
-
-static int s3cmci_state_open(struct inode *inode, struct file *file)
-{
- return single_open(file, s3cmci_state_show, inode->i_private);
-}
-
-static const struct file_operations s3cmci_fops_state = {
- .owner = THIS_MODULE,
- .open = s3cmci_state_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-#define DBG_REG(_r) { .addr = S3C2410_SDI##_r, .name = #_r }
-
-struct s3cmci_reg {
- unsigned short addr;
- unsigned char *name;
-} debug_regs[] = {
- DBG_REG(CON),
- DBG_REG(PRE),
- DBG_REG(CMDARG),
- DBG_REG(CMDCON),
- DBG_REG(CMDSTAT),
- DBG_REG(RSP0),
- DBG_REG(RSP1),
- DBG_REG(RSP2),
- DBG_REG(RSP3),
- DBG_REG(TIMER),
- DBG_REG(BSIZE),
- DBG_REG(DCON),
- DBG_REG(DCNT),
- DBG_REG(DSTA),
- DBG_REG(FSTA),
- {}
-};
-
-static int s3cmci_regs_show(struct seq_file *seq, void *v)
-{
- struct s3cmci_host *host = seq->private;
- struct s3cmci_reg *rptr = debug_regs;
-
- for (; rptr->name; rptr++)
- seq_printf(seq, "SDI%s\t=0x%08x\n", rptr->name,
- readl(host->base + rptr->addr));
-
- seq_printf(seq, "SDIIMSK\t=0x%08x\n", readl(host->base + host->sdiimsk));
-
- return 0;
-}
-
-static int s3cmci_regs_open(struct inode *inode, struct file *file)
-{
- return single_open(file, s3cmci_regs_show, inode->i_private);
-}
-
-static const struct file_operations s3cmci_fops_regs = {
- .owner = THIS_MODULE,
- .open = s3cmci_regs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static void s3cmci_debugfs_attach(struct s3cmci_host *host)
-{
- struct device *dev = &host->pdev->dev;
-
- host->debug_root = debugfs_create_dir(dev_name(dev), NULL);
- if (IS_ERR(host->debug_root)) {
- dev_err(dev, "failed to create debugfs root\n");
- return;
- }
-
- host->debug_state = debugfs_create_file("state", 0444,
- host->debug_root, host,
- &s3cmci_fops_state);
-
- if (IS_ERR(host->debug_state))
- dev_err(dev, "failed to create debug state file\n");
-
- host->debug_regs = debugfs_create_file("regs", 0444,
- host->debug_root, host,
- &s3cmci_fops_regs);
-
- if (IS_ERR(host->debug_regs))
- dev_err(dev, "failed to create debug regs file\n");
-}
-
-static void s3cmci_debugfs_remove(struct s3cmci_host *host)
-{
- debugfs_remove(host->debug_regs);
- debugfs_remove(host->debug_state);
- debugfs_remove(host->debug_root);
-}
-
-#else
-static inline void s3cmci_debugfs_attach(struct s3cmci_host *host) { }
-static inline void s3cmci_debugfs_remove(struct s3cmci_host *host) { }
-
-#endif /* CONFIG_DEBUG_FS */
-
-static int __devinit s3cmci_probe(struct platform_device *pdev)
-{
- struct s3cmci_host *host;
- struct mmc_host *mmc;
- int ret;
- int is2440;
- int i;
-
- is2440 = platform_get_device_id(pdev)->driver_data;
-
- mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev);
- if (!mmc) {
- ret = -ENOMEM;
- goto probe_out;
- }
-
- for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) {
- ret = gpio_request(i, dev_name(&pdev->dev));
- if (ret) {
- dev_err(&pdev->dev, "failed to get gpio %d\n", i);
-
- for (i--; i >= S3C2410_GPE(5); i--)
- gpio_free(i);
-
- goto probe_free_host;
- }
- }
-
- host = mmc_priv(mmc);
- host->mmc = mmc;
- host->pdev = pdev;
- host->is2440 = is2440;
-
- host->pdata = pdev->dev.platform_data;
- if (!host->pdata) {
- pdev->dev.platform_data = &s3cmci_def_pdata;
- host->pdata = &s3cmci_def_pdata;
- }
-
- spin_lock_init(&host->complete_lock);
- tasklet_init(&host->pio_tasklet, pio_tasklet, (unsigned long) host);
-
- if (is2440) {
- host->sdiimsk = S3C2440_SDIIMSK;
- host->sdidata = S3C2440_SDIDATA;
- host->clk_div = 1;
- } else {
- host->sdiimsk = S3C2410_SDIIMSK;
- host->sdidata = S3C2410_SDIDATA;
- host->clk_div = 2;
- }
-
- host->complete_what = COMPLETION_NONE;
- host->pio_active = XFER_NONE;
-
-#ifdef CONFIG_MMC_S3C_PIODMA
- host->dodma = host->pdata->use_dma;
-#endif
-
- host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!host->mem) {
- dev_err(&pdev->dev,
- "failed to get io memory region resource.\n");
-
- ret = -ENOENT;
- goto probe_free_gpio;
- }
-
- host->mem = request_mem_region(host->mem->start,
- resource_size(host->mem), pdev->name);
-
- if (!host->mem) {
- dev_err(&pdev->dev, "failed to request io memory region.\n");
- ret = -ENOENT;
- goto probe_free_gpio;
- }
-
- host->base = ioremap(host->mem->start, resource_size(host->mem));
- if (!host->base) {
- dev_err(&pdev->dev, "failed to ioremap() io memory region.\n");
- ret = -EINVAL;
- goto probe_free_mem_region;
- }
-
- host->irq = platform_get_irq(pdev, 0);
- if (host->irq == 0) {
- dev_err(&pdev->dev, "failed to get interrupt resource.\n");
- ret = -EINVAL;
- goto probe_iounmap;
- }
-
- if (request_irq(host->irq, s3cmci_irq, 0, DRIVER_NAME, host)) {
- dev_err(&pdev->dev, "failed to request mci interrupt.\n");
- ret = -ENOENT;
- goto probe_iounmap;
- }
-
- /* We get spurious interrupts even when we have set the IMSK
- * register to ignore everything, so use disable_irq() to make
- * ensure we don't lock the system with un-serviceable requests. */
-
- disable_irq(host->irq);
- host->irq_state = false;
-
- if (!host->pdata->no_detect) {
- ret = gpio_request(host->pdata->gpio_detect, "s3cmci detect");
- if (ret) {
- dev_err(&pdev->dev, "failed to get detect gpio\n");
- goto probe_free_irq;
- }
-
- host->irq_cd = gpio_to_irq(host->pdata->gpio_detect);
-
- if (host->irq_cd >= 0) {
- if (request_irq(host->irq_cd, s3cmci_irq_cd,
- IRQF_TRIGGER_RISING |
- IRQF_TRIGGER_FALLING,
- DRIVER_NAME, host)) {
- dev_err(&pdev->dev,
- "can't get card detect irq.\n");
- ret = -ENOENT;
- goto probe_free_gpio_cd;
- }
- } else {
- dev_warn(&pdev->dev,
- "host detect has no irq available\n");
- gpio_direction_input(host->pdata->gpio_detect);
- }
- } else
- host->irq_cd = -1;
-
- if (!host->pdata->no_wprotect) {
- ret = gpio_request(host->pdata->gpio_wprotect, "s3cmci wp");
- if (ret) {
- dev_err(&pdev->dev, "failed to get writeprotect\n");
- goto probe_free_irq_cd;
- }
-
- gpio_direction_input(host->pdata->gpio_wprotect);
- }
-
- /* depending on the dma state, get a dma channel to use. */
-
- if (s3cmci_host_usedma(host)) {
- host->dma = s3c2410_dma_request(DMACH_SDI, &s3cmci_dma_client,
- host);
- if (host->dma < 0) {
- dev_err(&pdev->dev, "cannot get DMA channel.\n");
- if (!s3cmci_host_canpio()) {
- ret = -EBUSY;
- goto probe_free_gpio_wp;
- } else {
- dev_warn(&pdev->dev, "falling back to PIO.\n");
- host->dodma = 0;
- }
- }
- }
-
- host->clk = clk_get(&pdev->dev, "sdi");
- if (IS_ERR(host->clk)) {
- dev_err(&pdev->dev, "failed to find clock source.\n");
- ret = PTR_ERR(host->clk);
- host->clk = NULL;
- goto probe_free_dma;
- }
-
- ret = clk_enable(host->clk);
- if (ret) {
- dev_err(&pdev->dev, "failed to enable clock source.\n");
- goto clk_free;
- }
-
- host->clk_rate = clk_get_rate(host->clk);
-
- mmc->ops = &s3cmci_ops;
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-#ifdef CONFIG_MMC_S3C_HW_SDIO_IRQ
- mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
-#else
- mmc->caps = MMC_CAP_4_BIT_DATA;
-#endif
- mmc->f_min = host->clk_rate / (host->clk_div * 256);
- mmc->f_max = host->clk_rate / host->clk_div;
-
- if (host->pdata->ocr_avail)
- mmc->ocr_avail = host->pdata->ocr_avail;
-
- mmc->max_blk_count = 4095;
- mmc->max_blk_size = 4095;
- mmc->max_req_size = 4095 * 512;
- mmc->max_seg_size = mmc->max_req_size;
-
- mmc->max_segs = 128;
-
- dbg(host, dbg_debug,
- "probe: mode:%s mapped mci_base:%p irq:%u irq_cd:%u dma:%u.\n",
- (host->is2440?"2440":""),
- host->base, host->irq, host->irq_cd, host->dma);
-
- ret = s3cmci_cpufreq_register(host);
- if (ret) {
- dev_err(&pdev->dev, "failed to register cpufreq\n");
- goto free_dmabuf;
- }
-
- ret = mmc_add_host(mmc);
- if (ret) {
- dev_err(&pdev->dev, "failed to add mmc host.\n");
- goto free_cpufreq;
- }
-
- s3cmci_debugfs_attach(host);
-
- platform_set_drvdata(pdev, mmc);
- dev_info(&pdev->dev, "%s - using %s, %s SDIO IRQ\n", mmc_hostname(mmc),
- s3cmci_host_usedma(host) ? "dma" : "pio",
- mmc->caps & MMC_CAP_SDIO_IRQ ? "hw" : "sw");
-
- return 0;
-
- free_cpufreq:
- s3cmci_cpufreq_deregister(host);
-
- free_dmabuf:
- clk_disable(host->clk);
-
- clk_free:
- clk_put(host->clk);
-
- probe_free_dma:
- if (s3cmci_host_usedma(host))
- s3c2410_dma_free(host->dma, &s3cmci_dma_client);
-
- probe_free_gpio_wp:
- if (!host->pdata->no_wprotect)
- gpio_free(host->pdata->gpio_wprotect);
-
- probe_free_gpio_cd:
- if (!host->pdata->no_detect)
- gpio_free(host->pdata->gpio_detect);
-
- probe_free_irq_cd:
- if (host->irq_cd >= 0)
- free_irq(host->irq_cd, host);
-
- probe_free_irq:
- free_irq(host->irq, host);
-
- probe_iounmap:
- iounmap(host->base);
-
- probe_free_mem_region:
- release_mem_region(host->mem->start, resource_size(host->mem));
-
- probe_free_gpio:
- for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++)
- gpio_free(i);
-
- probe_free_host:
- mmc_free_host(mmc);
-
- probe_out:
- return ret;
-}
-
-static void s3cmci_shutdown(struct platform_device *pdev)
-{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
- struct s3cmci_host *host = mmc_priv(mmc);
-
- if (host->irq_cd >= 0)
- free_irq(host->irq_cd, host);
-
- s3cmci_debugfs_remove(host);
- s3cmci_cpufreq_deregister(host);
- mmc_remove_host(mmc);
- clk_disable(host->clk);
-}
-
-static int __devexit s3cmci_remove(struct platform_device *pdev)
-{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
- struct s3cmci_host *host = mmc_priv(mmc);
- struct s3c24xx_mci_pdata *pd = host->pdata;
- int i;
-
- s3cmci_shutdown(pdev);
-
- clk_put(host->clk);
-
- tasklet_disable(&host->pio_tasklet);
-
- if (s3cmci_host_usedma(host))
- s3c2410_dma_free(host->dma, &s3cmci_dma_client);
-
- free_irq(host->irq, host);
-
- if (!pd->no_wprotect)
- gpio_free(pd->gpio_wprotect);
-
- if (!pd->no_detect)
- gpio_free(pd->gpio_detect);
-
- for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++)
- gpio_free(i);
-
-
- iounmap(host->base);
- release_mem_region(host->mem->start, resource_size(host->mem));
-
- mmc_free_host(mmc);
- return 0;
-}
-
-static struct platform_device_id s3cmci_driver_ids[] = {
- {
- .name = "s3c2410-sdi",
- .driver_data = 0,
- }, {
- .name = "s3c2412-sdi",
- .driver_data = 1,
- }, {
- .name = "s3c2440-sdi",
- .driver_data = 1,
- },
- { }
-};
-
-MODULE_DEVICE_TABLE(platform, s3cmci_driver_ids);
-
-
-#ifdef CONFIG_PM
-
-static int s3cmci_suspend(struct device *dev)
-{
- struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev));
-
- return mmc_suspend_host(mmc);
-}
-
-static int s3cmci_resume(struct device *dev)
-{
- struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev));
-
- return mmc_resume_host(mmc);
-}
-
-static const struct dev_pm_ops s3cmci_pm = {
- .suspend = s3cmci_suspend,
- .resume = s3cmci_resume,
-};
-
-#define s3cmci_pm_ops &s3cmci_pm
-#else /* CONFIG_PM */
-#define s3cmci_pm_ops NULL
-#endif /* CONFIG_PM */
-
-
-static struct platform_driver s3cmci_driver = {
- .driver = {
- .name = "s3c-sdi",
- .owner = THIS_MODULE,
- .pm = s3cmci_pm_ops,
- },
- .id_table = s3cmci_driver_ids,
- .probe = s3cmci_probe,
- .remove = __devexit_p(s3cmci_remove),
- .shutdown = s3cmci_shutdown,
-};
-
-module_platform_driver(s3cmci_driver);
-
-MODULE_DESCRIPTION("Samsung S3C MMC/SD Card Interface driver");
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Thomas Kleffel <tk@maintech.de>, Ben Dooks <ben-linux@fluff.org>");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/s3cmci.h b/ANDROID_3.4.5/drivers/mmc/host/s3cmci.h
deleted file mode 100644
index c76b53db..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/s3cmci.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * linux/drivers/mmc/s3cmci.h - Samsung S3C MCI driver
- *
- * Copyright (C) 2004-2006 Thomas Kleffel, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-enum s3cmci_waitfor {
- COMPLETION_NONE,
- COMPLETION_FINALIZE,
- COMPLETION_CMDSENT,
- COMPLETION_RSPFIN,
- COMPLETION_XFERFINISH,
- COMPLETION_XFERFINISH_RSPFIN,
-};
-
-struct s3cmci_host {
- struct platform_device *pdev;
- struct s3c24xx_mci_pdata *pdata;
- struct mmc_host *mmc;
- struct resource *mem;
- struct clk *clk;
- void __iomem *base;
- int irq;
- int irq_cd;
- int dma;
-
- unsigned long clk_rate;
- unsigned long clk_div;
- unsigned long real_rate;
- u8 prescaler;
-
- int is2440;
- unsigned sdiimsk;
- unsigned sdidata;
- int dodma;
- int dmatogo;
-
- bool irq_disabled;
- bool irq_enabled;
- bool irq_state;
- int sdio_irqen;
-
- struct mmc_request *mrq;
- int cmd_is_stop;
-
- spinlock_t complete_lock;
- enum s3cmci_waitfor complete_what;
-
- int dma_complete;
-
- u32 pio_sgptr;
- u32 pio_bytes;
- u32 pio_count;
- u32 *pio_ptr;
-#define XFER_NONE 0
-#define XFER_READ 1
-#define XFER_WRITE 2
- u32 pio_active;
-
- int bus_width;
-
- char dbgmsg_cmd[301];
- char dbgmsg_dat[301];
- char *status;
-
- unsigned int ccnt, dcnt;
- struct tasklet_struct pio_tasklet;
-
-#ifdef CONFIG_DEBUG_FS
- struct dentry *debug_root;
- struct dentry *debug_state;
- struct dentry *debug_regs;
-#endif
-
-#ifdef CONFIG_CPU_FREQ
- struct notifier_block freq_transition;
-#endif
-};
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-cns3xxx.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-cns3xxx.c
deleted file mode 100644
index 28a87080..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-cns3xxx.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * SDHCI support for CNS3xxx SoC
- *
- * Copyright 2008 Cavium Networks
- * Copyright 2010 MontaVista Software, LLC.
- *
- * Authors: Scott Shu
- * Anton Vorontsov <avorontsov@mvista.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.
- */
-
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/mmc/host.h>
-#include <linux/module.h>
-#include <mach/cns3xxx.h>
-#include "sdhci-pltfm.h"
-
-static unsigned int sdhci_cns3xxx_get_max_clk(struct sdhci_host *host)
-{
- return 150000000;
-}
-
-static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock)
-{
- struct device *dev = mmc_dev(host->mmc);
- int div = 1;
- u16 clk;
- unsigned long timeout;
-
- if (clock == host->clock)
- return;
-
- sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
-
- if (clock == 0)
- goto out;
-
- while (host->max_clk / div > clock) {
- /*
- * On CNS3xxx divider grows linearly up to 4, and then
- * exponentially up to 256.
- */
- if (div < 4)
- div += 1;
- else if (div < 256)
- div *= 2;
- else
- break;
- }
-
- dev_dbg(dev, "desired SD clock: %d, actual: %d\n",
- clock, host->max_clk / div);
-
- /* Divide by 3 is special. */
- if (div != 3)
- div >>= 1;
-
- clk = div << SDHCI_DIVIDER_SHIFT;
- clk |= SDHCI_CLOCK_INT_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
- timeout = 20;
- while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
- & SDHCI_CLOCK_INT_STABLE)) {
- if (timeout == 0) {
- dev_warn(dev, "clock is unstable");
- break;
- }
- timeout--;
- mdelay(1);
- }
-
- clk |= SDHCI_CLOCK_CARD_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-out:
- host->clock = clock;
-}
-
-static struct sdhci_ops sdhci_cns3xxx_ops = {
- .get_max_clock = sdhci_cns3xxx_get_max_clk,
- .set_clock = sdhci_cns3xxx_set_clock,
-};
-
-static struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
- .ops = &sdhci_cns3xxx_ops,
- .quirks = SDHCI_QUIRK_BROKEN_DMA |
- SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
- SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
- SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
- SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
- SDHCI_QUIRK_NONSTANDARD_CLOCK,
-};
-
-static int __devinit sdhci_cns3xxx_probe(struct platform_device *pdev)
-{
- return sdhci_pltfm_register(pdev, &sdhci_cns3xxx_pdata);
-}
-
-static int __devexit sdhci_cns3xxx_remove(struct platform_device *pdev)
-{
- return sdhci_pltfm_unregister(pdev);
-}
-
-static struct platform_driver sdhci_cns3xxx_driver = {
- .driver = {
- .name = "sdhci-cns3xxx",
- .owner = THIS_MODULE,
- .pm = SDHCI_PLTFM_PMOPS,
- },
- .probe = sdhci_cns3xxx_probe,
- .remove = __devexit_p(sdhci_cns3xxx_remove),
-};
-
-module_platform_driver(sdhci_cns3xxx_driver);
-
-MODULE_DESCRIPTION("SDHCI driver for CNS3xxx");
-MODULE_AUTHOR("Scott Shu, "
- "Anton Vorontsov <avorontsov@mvista.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-dove.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-dove.c
deleted file mode 100644
index 177f697b..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-dove.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * sdhci-dove.c Support for SDHCI on Marvell's Dove SoC
- *
- * Author: Saeed Bishara <saeed@marvell.com>
- * Mike Rapoport <mike@compulab.co.il>
- * Based on sdhci-cns3xxx.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/mmc/host.h>
-
-#include "sdhci-pltfm.h"
-
-static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)
-{
- u16 ret;
-
- switch (reg) {
- case SDHCI_HOST_VERSION:
- case SDHCI_SLOT_INT_STATUS:
- /* those registers don't exist */
- return 0;
- default:
- ret = readw(host->ioaddr + reg);
- }
- return ret;
-}
-
-static u32 sdhci_dove_readl(struct sdhci_host *host, int reg)
-{
- u32 ret;
-
- switch (reg) {
- case SDHCI_CAPABILITIES:
- ret = readl(host->ioaddr + reg);
- /* Mask the support for 3.0V */
- ret &= ~SDHCI_CAN_VDD_300;
- break;
- default:
- ret = readl(host->ioaddr + reg);
- }
- return ret;
-}
-
-static struct sdhci_ops sdhci_dove_ops = {
- .read_w = sdhci_dove_readw,
- .read_l = sdhci_dove_readl,
-};
-
-static struct sdhci_pltfm_data sdhci_dove_pdata = {
- .ops = &sdhci_dove_ops,
- .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
- SDHCI_QUIRK_NO_BUSY_IRQ |
- SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
- SDHCI_QUIRK_FORCE_DMA,
-};
-
-static int __devinit sdhci_dove_probe(struct platform_device *pdev)
-{
- return sdhci_pltfm_register(pdev, &sdhci_dove_pdata);
-}
-
-static int __devexit sdhci_dove_remove(struct platform_device *pdev)
-{
- return sdhci_pltfm_unregister(pdev);
-}
-
-static struct platform_driver sdhci_dove_driver = {
- .driver = {
- .name = "sdhci-dove",
- .owner = THIS_MODULE,
- .pm = SDHCI_PLTFM_PMOPS,
- },
- .probe = sdhci_dove_probe,
- .remove = __devexit_p(sdhci_dove_remove),
-};
-
-module_platform_driver(sdhci_dove_driver);
-
-MODULE_DESCRIPTION("SDHCI driver for Dove");
-MODULE_AUTHOR("Saeed Bishara <saeed@marvell.com>, "
- "Mike Rapoport <mike@compulab.co.il>");
-MODULE_LICENSE("GPL v2");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-esdhc-imx.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-esdhc-imx.c
deleted file mode 100644
index 8abdaf66..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-esdhc-imx.c
+++ /dev/null
@@ -1,613 +0,0 @@
-/*
- * 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/gpio.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/sdio.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
-#include <mach/esdhc.h>
-#include "sdhci-pltfm.h"
-#include "sdhci-esdhc.h"
-
-#define SDHCI_CTRL_D3CD 0x08
-/* VENDOR SPEC register */
-#define SDHCI_VENDOR_SPEC 0xC0
-#define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002
-#define SDHCI_WTMK_LVL 0x44
-#define SDHCI_MIX_CTRL 0x48
-
-/*
- * There is an INT DMA ERR mis-match between eSDHC and STD SDHC SPEC:
- * Bit25 is used in STD SPEC, and is reserved in fsl eSDHC design,
- * but bit28 is used as the INT DMA ERR in fsl eSDHC design.
- * Define this macro DMA error INT for fsl eSDHC
- */
-#define SDHCI_INT_VENDOR_SPEC_DMA_ERR 0x10000000
-
-/*
- * The CMDTYPE of the CMD register (offset 0xE) should be set to
- * "11" when the STOP CMD12 is issued on imx53 to abort one
- * open ended multi-blk IO. Otherwise the TC INT wouldn't
- * be generated.
- * In exact block transfer, the controller doesn't complete the
- * operations automatically as required at the end of the
- * transfer and remains on hold if the abort command is not sent.
- * As a result, the TC flag is not asserted and SW received timeout
- * exeception. Bit1 of Vendor Spec registor is used to fix it.
- */
-#define ESDHC_FLAG_MULTIBLK_NO_INT (1 << 1)
-
-enum imx_esdhc_type {
- IMX25_ESDHC,
- IMX35_ESDHC,
- IMX51_ESDHC,
- IMX53_ESDHC,
- IMX6Q_USDHC,
-};
-
-struct pltfm_imx_data {
- int flags;
- u32 scratchpad;
- enum imx_esdhc_type devtype;
- struct esdhc_platform_data boarddata;
-};
-
-static struct platform_device_id imx_esdhc_devtype[] = {
- {
- .name = "sdhci-esdhc-imx25",
- .driver_data = IMX25_ESDHC,
- }, {
- .name = "sdhci-esdhc-imx35",
- .driver_data = IMX35_ESDHC,
- }, {
- .name = "sdhci-esdhc-imx51",
- .driver_data = IMX51_ESDHC,
- }, {
- .name = "sdhci-esdhc-imx53",
- .driver_data = IMX53_ESDHC,
- }, {
- .name = "sdhci-usdhc-imx6q",
- .driver_data = IMX6Q_USDHC,
- }, {
- /* sentinel */
- }
-};
-MODULE_DEVICE_TABLE(platform, imx_esdhc_devtype);
-
-static const struct of_device_id imx_esdhc_dt_ids[] = {
- { .compatible = "fsl,imx25-esdhc", .data = &imx_esdhc_devtype[IMX25_ESDHC], },
- { .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], },
- { .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], },
- { .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], },
- { .compatible = "fsl,imx6q-usdhc", .data = &imx_esdhc_devtype[IMX6Q_USDHC], },
- { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids);
-
-static inline int is_imx25_esdhc(struct pltfm_imx_data *data)
-{
- return data->devtype == IMX25_ESDHC;
-}
-
-static inline int is_imx35_esdhc(struct pltfm_imx_data *data)
-{
- return data->devtype == IMX35_ESDHC;
-}
-
-static inline int is_imx51_esdhc(struct pltfm_imx_data *data)
-{
- return data->devtype == IMX51_ESDHC;
-}
-
-static inline int is_imx53_esdhc(struct pltfm_imx_data *data)
-{
- return data->devtype == IMX53_ESDHC;
-}
-
-static inline int is_imx6q_usdhc(struct pltfm_imx_data *data)
-{
- return data->devtype == IMX6Q_USDHC;
-}
-
-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 u32 esdhc_readl_le(struct sdhci_host *host, int reg)
-{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct pltfm_imx_data *imx_data = pltfm_host->priv;
- struct esdhc_platform_data *boarddata = &imx_data->boarddata;
-
- /* fake CARD_PRESENT flag */
- u32 val = readl(host->ioaddr + reg);
-
- if (unlikely((reg == SDHCI_PRESENT_STATE)
- && gpio_is_valid(boarddata->cd_gpio))) {
- if (gpio_get_value(boarddata->cd_gpio))
- /* no card, if a valid gpio says so... */
- val &= ~SDHCI_CARD_PRESENT;
- else
- /* ... in all other cases assume card is present */
- val |= SDHCI_CARD_PRESENT;
- }
-
- if (unlikely(reg == SDHCI_CAPABILITIES)) {
- /* In FSL esdhc IC module, only bit20 is used to indicate the
- * ADMA2 capability of esdhc, but this bit is messed up on
- * some SOCs (e.g. on MX25, MX35 this bit is set, but they
- * don't actually support ADMA2). So set the BROKEN_ADMA
- * uirk on MX25/35 platforms.
- */
-
- if (val & SDHCI_CAN_DO_ADMA1) {
- val &= ~SDHCI_CAN_DO_ADMA1;
- val |= SDHCI_CAN_DO_ADMA2;
- }
- }
-
- if (unlikely(reg == SDHCI_INT_STATUS)) {
- if (val & SDHCI_INT_VENDOR_SPEC_DMA_ERR) {
- val &= ~SDHCI_INT_VENDOR_SPEC_DMA_ERR;
- val |= SDHCI_INT_ADMA_ERROR;
- }
- }
-
- return val;
-}
-
-static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
-{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct pltfm_imx_data *imx_data = pltfm_host->priv;
- struct esdhc_platform_data *boarddata = &imx_data->boarddata;
- u32 data;
-
- if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) {
- if (boarddata->cd_type == ESDHC_CD_GPIO)
- /*
- * These interrupts won't work with a custom
- * card_detect gpio (only applied to mx25/35)
- */
- val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
-
- if (val & SDHCI_INT_CARD_INT) {
- /*
- * Clear and then set D3CD bit to avoid missing the
- * card interrupt. This is a eSDHC controller problem
- * so we need to apply the following workaround: clear
- * and set D3CD bit will make eSDHC re-sample the card
- * interrupt. In case a card interrupt was lost,
- * re-sample it by the following steps.
- */
- data = readl(host->ioaddr + SDHCI_HOST_CONTROL);
- data &= ~SDHCI_CTRL_D3CD;
- writel(data, host->ioaddr + SDHCI_HOST_CONTROL);
- data |= SDHCI_CTRL_D3CD;
- writel(data, host->ioaddr + SDHCI_HOST_CONTROL);
- }
- }
-
- if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
- && (reg == SDHCI_INT_STATUS)
- && (val & SDHCI_INT_DATA_END))) {
- u32 v;
- v = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
- v &= ~SDHCI_VENDOR_SPEC_SDIO_QUIRK;
- writel(v, host->ioaddr + SDHCI_VENDOR_SPEC);
- }
-
- if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) {
- if (val & SDHCI_INT_ADMA_ERROR) {
- val &= ~SDHCI_INT_ADMA_ERROR;
- val |= SDHCI_INT_VENDOR_SPEC_DMA_ERR;
- }
- }
-
- writel(val, host->ioaddr + reg);
-}
-
-static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
-{
- if (unlikely(reg == SDHCI_HOST_VERSION)) {
- u16 val = readw(host->ioaddr + (reg ^ 2));
- /*
- * uSDHC supports SDHCI v3.0, but it's encoded as value
- * 0x3 in host controller version register, which violates
- * SDHCI_SPEC_300 definition. Work it around here.
- */
- if ((val & SDHCI_SPEC_VER_MASK) == 3)
- return --val;
- }
-
- 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);
- struct pltfm_imx_data *imx_data = pltfm_host->priv;
-
- switch (reg) {
- case SDHCI_TRANSFER_MODE:
- /*
- * Postpone this write, we must do it together with a
- * command write that is down below.
- */
- if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)
- && (host->cmd->opcode == SD_IO_RW_EXTENDED)
- && (host->cmd->data->blocks > 1)
- && (host->cmd->data->flags & MMC_DATA_READ)) {
- u32 v;
- v = readl(host->ioaddr + SDHCI_VENDOR_SPEC);
- v |= SDHCI_VENDOR_SPEC_SDIO_QUIRK;
- writel(v, host->ioaddr + SDHCI_VENDOR_SPEC);
- }
- imx_data->scratchpad = val;
- return;
- case SDHCI_COMMAND:
- if ((host->cmd->opcode == MMC_STOP_TRANSMISSION ||
- host->cmd->opcode == MMC_SET_BLOCK_COUNT) &&
- (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT))
- val |= SDHCI_CMD_ABORTCMD;
-
- if (is_imx6q_usdhc(imx_data)) {
- u32 m = readl(host->ioaddr + SDHCI_MIX_CTRL);
- m = imx_data->scratchpad | (m & 0xffff0000);
- writel(m, host->ioaddr + SDHCI_MIX_CTRL);
- writel(val << 16,
- host->ioaddr + SDHCI_TRANSFER_MODE);
- } else {
- writel(val << 16 | imx_data->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 three */
- new_val = val & (SDHCI_CTRL_LED | \
- SDHCI_CTRL_4BITBUS | \
- SDHCI_CTRL_D3CD);
- /* 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);
-
- /*
- * The esdhc has a design violation to SDHC spec which tells
- * that software reset should not affect card detection circuit.
- * But esdhc clears its SYSCTL register bits [0..2] during the
- * software reset. This will stop those clocks that card detection
- * circuit relies on. To work around it, we turn the clocks on back
- * to keep card detection circuit functional.
- */
- if ((reg == SDHCI_SOFTWARE_RESET) && (val & 1))
- esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL);
-}
-
-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 unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
-{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct pltfm_imx_data *imx_data = pltfm_host->priv;
- struct esdhc_platform_data *boarddata = &imx_data->boarddata;
-
- switch (boarddata->wp_type) {
- case ESDHC_WP_GPIO:
- if (gpio_is_valid(boarddata->wp_gpio))
- return gpio_get_value(boarddata->wp_gpio);
- case ESDHC_WP_CONTROLLER:
- return !(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
- SDHCI_WRITE_PROTECT);
- case ESDHC_WP_NONE:
- break;
- }
-
- return -ENOSYS;
-}
-
-static struct sdhci_ops sdhci_esdhc_ops = {
- .read_l = esdhc_readl_le,
- .read_w = esdhc_readw_le,
- .write_l = esdhc_writel_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,
- .get_ro = esdhc_pltfm_get_ro,
-};
-
-static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
- .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_HISPD_BIT
- | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
- | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC
- | SDHCI_QUIRK_BROKEN_CARD_DETECTION,
- .ops = &sdhci_esdhc_ops,
-};
-
-static irqreturn_t cd_irq(int irq, void *data)
-{
- struct sdhci_host *sdhost = (struct sdhci_host *)data;
-
- tasklet_schedule(&sdhost->card_tasklet);
- return IRQ_HANDLED;
-};
-
-#ifdef CONFIG_OF
-static int __devinit
-sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
- struct esdhc_platform_data *boarddata)
-{
- struct device_node *np = pdev->dev.of_node;
-
- if (!np)
- return -ENODEV;
-
- if (of_get_property(np, "fsl,card-wired", NULL))
- boarddata->cd_type = ESDHC_CD_PERMANENT;
-
- if (of_get_property(np, "fsl,cd-controller", NULL))
- boarddata->cd_type = ESDHC_CD_CONTROLLER;
-
- if (of_get_property(np, "fsl,wp-controller", NULL))
- boarddata->wp_type = ESDHC_WP_CONTROLLER;
-
- boarddata->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
- if (gpio_is_valid(boarddata->cd_gpio))
- boarddata->cd_type = ESDHC_CD_GPIO;
-
- boarddata->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
- if (gpio_is_valid(boarddata->wp_gpio))
- boarddata->wp_type = ESDHC_WP_GPIO;
-
- return 0;
-}
-#else
-static inline int
-sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
- struct esdhc_platform_data *boarddata)
-{
- return -ENODEV;
-}
-#endif
-
-static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
-{
- const struct of_device_id *of_id =
- of_match_device(imx_esdhc_dt_ids, &pdev->dev);
- struct sdhci_pltfm_host *pltfm_host;
- struct sdhci_host *host;
- struct esdhc_platform_data *boarddata;
- struct clk *clk;
- int err;
- struct pltfm_imx_data *imx_data;
-
- host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata);
- if (IS_ERR(host))
- return PTR_ERR(host);
-
- pltfm_host = sdhci_priv(host);
-
- imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
- if (!imx_data) {
- err = -ENOMEM;
- goto err_imx_data;
- }
-
- if (of_id)
- pdev->id_entry = of_id->data;
- imx_data->devtype = pdev->id_entry->driver_data;
- pltfm_host->priv = imx_data;
-
- clk = clk_get(mmc_dev(host->mmc), NULL);
- if (IS_ERR(clk)) {
- dev_err(mmc_dev(host->mmc), "clk err\n");
- err = PTR_ERR(clk);
- goto err_clk_get;
- }
- clk_prepare_enable(clk);
- pltfm_host->clk = clk;
-
- host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
-
- if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data))
- /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
- host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK
- | SDHCI_QUIRK_BROKEN_ADMA;
-
- if (is_imx53_esdhc(imx_data))
- imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT;
-
- /*
- * The imx6q ROM code will change the default watermark level setting
- * to something insane. Change it back here.
- */
- if (is_imx6q_usdhc(imx_data))
- writel(0x08100810, host->ioaddr + SDHCI_WTMK_LVL);
-
- boarddata = &imx_data->boarddata;
- if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) {
- if (!host->mmc->parent->platform_data) {
- dev_err(mmc_dev(host->mmc), "no board data!\n");
- err = -EINVAL;
- goto no_board_data;
- }
- imx_data->boarddata = *((struct esdhc_platform_data *)
- host->mmc->parent->platform_data);
- }
-
- /* write_protect */
- if (boarddata->wp_type == ESDHC_WP_GPIO) {
- err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP");
- if (err) {
- dev_warn(mmc_dev(host->mmc),
- "no write-protect pin available!\n");
- boarddata->wp_gpio = -EINVAL;
- }
- } else {
- boarddata->wp_gpio = -EINVAL;
- }
-
- /* card_detect */
- if (boarddata->cd_type != ESDHC_CD_GPIO)
- boarddata->cd_gpio = -EINVAL;
-
- switch (boarddata->cd_type) {
- case ESDHC_CD_GPIO:
- err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD");
- if (err) {
- dev_err(mmc_dev(host->mmc),
- "no card-detect pin available!\n");
- goto no_card_detect_pin;
- }
-
- err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- mmc_hostname(host->mmc), host);
- if (err) {
- dev_err(mmc_dev(host->mmc), "request irq error\n");
- goto no_card_detect_irq;
- }
- /* fall through */
-
- case ESDHC_CD_CONTROLLER:
- /* we have a working card_detect back */
- host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
- break;
-
- case ESDHC_CD_PERMANENT:
- host->mmc->caps = MMC_CAP_NONREMOVABLE;
- break;
-
- case ESDHC_CD_NONE:
- break;
- }
-
- err = sdhci_add_host(host);
- if (err)
- goto err_add_host;
-
- return 0;
-
-err_add_host:
- if (gpio_is_valid(boarddata->cd_gpio))
- free_irq(gpio_to_irq(boarddata->cd_gpio), host);
-no_card_detect_irq:
- if (gpio_is_valid(boarddata->cd_gpio))
- gpio_free(boarddata->cd_gpio);
- if (gpio_is_valid(boarddata->wp_gpio))
- gpio_free(boarddata->wp_gpio);
-no_card_detect_pin:
-no_board_data:
- clk_disable_unprepare(pltfm_host->clk);
- clk_put(pltfm_host->clk);
-err_clk_get:
- kfree(imx_data);
-err_imx_data:
- sdhci_pltfm_free(pdev);
- return err;
-}
-
-static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
-{
- struct sdhci_host *host = platform_get_drvdata(pdev);
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct pltfm_imx_data *imx_data = pltfm_host->priv;
- struct esdhc_platform_data *boarddata = &imx_data->boarddata;
- int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
-
- sdhci_remove_host(host, dead);
-
- if (gpio_is_valid(boarddata->wp_gpio))
- gpio_free(boarddata->wp_gpio);
-
- if (gpio_is_valid(boarddata->cd_gpio)) {
- free_irq(gpio_to_irq(boarddata->cd_gpio), host);
- gpio_free(boarddata->cd_gpio);
- }
-
- clk_disable_unprepare(pltfm_host->clk);
- clk_put(pltfm_host->clk);
- kfree(imx_data);
-
- sdhci_pltfm_free(pdev);
-
- return 0;
-}
-
-static struct platform_driver sdhci_esdhc_imx_driver = {
- .driver = {
- .name = "sdhci-esdhc-imx",
- .owner = THIS_MODULE,
- .of_match_table = imx_esdhc_dt_ids,
- .pm = SDHCI_PLTFM_PMOPS,
- },
- .id_table = imx_esdhc_devtype,
- .probe = sdhci_esdhc_imx_probe,
- .remove = __devexit_p(sdhci_esdhc_imx_remove),
-};
-
-module_platform_driver(sdhci_esdhc_imx_driver);
-
-MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC");
-MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
-MODULE_LICENSE("GPL v2");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-esdhc.h b/ANDROID_3.4.5/drivers/mmc/host/sdhci-esdhc.h
deleted file mode 100644
index b97b2f5d..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-esdhc.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * 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_NO_BUSY_IRQ | \
- SDHCI_QUIRK_NONSTANDARD_CLOCK | \
- SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \
- SDHCI_QUIRK_PIO_NEEDS_DELAY | \
- SDHCI_QUIRK_RESTORE_IRQS_AFTER_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(1);
-out:
- host->clock = clock;
-}
-
-#endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-of-esdhc.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-of-esdhc.c
deleted file mode 100644
index f8eb1fb0..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-of-esdhc.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Freescale eSDHC controller driver.
- *
- * Copyright (c) 2007, 2010, 2012 Freescale Semiconductor, Inc.
- * Copyright (c) 2009 MontaVista Software, Inc.
- *
- * Authors: Xiaobo Xie <X.Xie@freescale.com>
- * Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/mmc/host.h>
-#include "sdhci-pltfm.h"
-#include "sdhci-esdhc.h"
-
-static u16 esdhc_readw(struct sdhci_host *host, int reg)
-{
- u16 ret;
- int base = reg & ~0x3;
- int shift = (reg & 0x2) * 8;
-
- if (unlikely(reg == SDHCI_HOST_VERSION))
- ret = in_be32(host->ioaddr + base) & 0xffff;
- else
- ret = (in_be32(host->ioaddr + base) >> shift) & 0xffff;
- return ret;
-}
-
-static u8 esdhc_readb(struct sdhci_host *host, int reg)
-{
- int base = reg & ~0x3;
- int shift = (reg & 0x3) * 8;
- u8 ret = (in_be32(host->ioaddr + base) >> shift) & 0xff;
-
- /*
- * "DMA select" locates at offset 0x28 in SD specification, but on
- * P5020 or P3041, it locates at 0x29.
- */
- if (reg == SDHCI_HOST_CONTROL) {
- u32 dma_bits;
-
- dma_bits = in_be32(host->ioaddr + reg);
- /* DMA select is 22,23 bits in Protocol Control Register */
- dma_bits = (dma_bits >> 5) & SDHCI_CTRL_DMA_MASK;
-
- /* fixup the result */
- ret &= ~SDHCI_CTRL_DMA_MASK;
- ret |= dma_bits;
- }
-
- return ret;
-}
-
-static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
-{
- if (reg == SDHCI_BLOCK_SIZE) {
- /*
- * Two last DMA bits are reserved, and first one is used for
- * non-standard blksz of 4096 bytes that we don't support
- * yet. So clear the DMA boundary bits.
- */
- val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
- }
- sdhci_be32bs_writew(host, val, reg);
-}
-
-static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
-{
- /*
- * "DMA select" location is offset 0x28 in SD specification, but on
- * P5020 or P3041, it's located at 0x29.
- */
- if (reg == SDHCI_HOST_CONTROL) {
- u32 dma_bits;
-
- /* DMA select is 22,23 bits in Protocol Control Register */
- dma_bits = (val & SDHCI_CTRL_DMA_MASK) << 5;
- clrsetbits_be32(host->ioaddr + reg , SDHCI_CTRL_DMA_MASK << 5,
- dma_bits);
- val &= ~SDHCI_CTRL_DMA_MASK;
- val |= in_be32(host->ioaddr + reg) & SDHCI_CTRL_DMA_MASK;
- }
-
- /* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */
- if (reg == SDHCI_HOST_CONTROL)
- val &= ~ESDHC_HOST_CONTROL_RES;
- sdhci_be32bs_writeb(host, val, reg);
-}
-
-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_of_get_max_clock(struct sdhci_host *host)
-{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-
- return pltfm_host->clock;
-}
-
-static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
-{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-
- return pltfm_host->clock / 256 / 16;
-}
-
-static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
-{
- /* Workaround to reduce the clock frequency for p1010 esdhc */
- if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) {
- if (clock > 20000000)
- clock -= 5000000;
- if (clock > 40000000)
- clock -= 5000000;
- }
-
- /* Set the clock */
- esdhc_set_clock(host, clock);
-}
-
-#ifdef CONFIG_PM
-static u32 esdhc_proctl;
-static void esdhc_of_suspend(struct sdhci_host *host)
-{
- esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL);
-}
-
-static void esdhc_of_resume(struct sdhci_host *host)
-{
- esdhc_of_enable_dma(host);
- sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL);
-}
-#endif
-
-static struct sdhci_ops sdhci_esdhc_ops = {
- .read_l = sdhci_be32bs_readl,
- .read_w = esdhc_readw,
- .read_b = esdhc_readb,
- .write_l = sdhci_be32bs_writel,
- .write_w = esdhc_writew,
- .write_b = esdhc_writeb,
- .set_clock = esdhc_of_set_clock,
- .enable_dma = esdhc_of_enable_dma,
- .get_max_clock = esdhc_of_get_max_clock,
- .get_min_clock = esdhc_of_get_min_clock,
-#ifdef CONFIG_PM
- .platform_suspend = esdhc_of_suspend,
- .platform_resume = esdhc_of_resume,
-#endif
-};
-
-static struct sdhci_pltfm_data sdhci_esdhc_pdata = {
- /* card detection could be handled via GPIO */
- .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION
- | SDHCI_QUIRK_NO_CARD_NO_RESET,
- .ops = &sdhci_esdhc_ops,
-};
-
-static int __devinit sdhci_esdhc_probe(struct platform_device *pdev)
-{
- return sdhci_pltfm_register(pdev, &sdhci_esdhc_pdata);
-}
-
-static int __devexit sdhci_esdhc_remove(struct platform_device *pdev)
-{
- return sdhci_pltfm_unregister(pdev);
-}
-
-static const struct of_device_id sdhci_esdhc_of_match[] = {
- { .compatible = "fsl,mpc8379-esdhc" },
- { .compatible = "fsl,mpc8536-esdhc" },
- { .compatible = "fsl,esdhc" },
- { }
-};
-MODULE_DEVICE_TABLE(of, sdhci_esdhc_of_match);
-
-static struct platform_driver sdhci_esdhc_driver = {
- .driver = {
- .name = "sdhci-esdhc",
- .owner = THIS_MODULE,
- .of_match_table = sdhci_esdhc_of_match,
- .pm = SDHCI_PLTFM_PMOPS,
- },
- .probe = sdhci_esdhc_probe,
- .remove = __devexit_p(sdhci_esdhc_remove),
-};
-
-module_platform_driver(sdhci_esdhc_driver);
-
-MODULE_DESCRIPTION("SDHCI OF driver for Freescale MPC eSDHC");
-MODULE_AUTHOR("Xiaobo Xie <X.Xie@freescale.com>, "
- "Anton Vorontsov <avorontsov@ru.mvista.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-of-hlwd.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-of-hlwd.c
deleted file mode 100644
index 0ce088ae..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-of-hlwd.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * drivers/mmc/host/sdhci-of-hlwd.c
- *
- * Nintendo Wii Secure Digital Host Controller Interface.
- * Copyright (C) 2009 The GameCube Linux Team
- * Copyright (C) 2009 Albert Herranz
- *
- * Based on sdhci-of-esdhc.c
- *
- * Copyright (c) 2007 Freescale Semiconductor, Inc.
- * Copyright (c) 2009 MontaVista Software, Inc.
- *
- * Authors: Xiaobo Xie <X.Xie@freescale.com>
- * Anton Vorontsov <avorontsov@ru.mvista.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/mmc/host.h>
-#include "sdhci-pltfm.h"
-
-/*
- * Ops and quirks for the Nintendo Wii SDHCI controllers.
- */
-
-/*
- * We need a small delay after each write, or things go horribly wrong.
- */
-#define SDHCI_HLWD_WRITE_DELAY 5 /* usecs */
-
-static void sdhci_hlwd_writel(struct sdhci_host *host, u32 val, int reg)
-{
- sdhci_be32bs_writel(host, val, reg);
- udelay(SDHCI_HLWD_WRITE_DELAY);
-}
-
-static void sdhci_hlwd_writew(struct sdhci_host *host, u16 val, int reg)
-{
- sdhci_be32bs_writew(host, val, reg);
- udelay(SDHCI_HLWD_WRITE_DELAY);
-}
-
-static void sdhci_hlwd_writeb(struct sdhci_host *host, u8 val, int reg)
-{
- sdhci_be32bs_writeb(host, val, reg);
- udelay(SDHCI_HLWD_WRITE_DELAY);
-}
-
-static struct sdhci_ops sdhci_hlwd_ops = {
- .read_l = sdhci_be32bs_readl,
- .read_w = sdhci_be32bs_readw,
- .read_b = sdhci_be32bs_readb,
- .write_l = sdhci_hlwd_writel,
- .write_w = sdhci_hlwd_writew,
- .write_b = sdhci_hlwd_writeb,
-};
-
-static struct sdhci_pltfm_data sdhci_hlwd_pdata = {
- .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
- SDHCI_QUIRK_32BIT_DMA_SIZE,
- .ops = &sdhci_hlwd_ops,
-};
-
-static int __devinit sdhci_hlwd_probe(struct platform_device *pdev)
-{
- return sdhci_pltfm_register(pdev, &sdhci_hlwd_pdata);
-}
-
-static int __devexit sdhci_hlwd_remove(struct platform_device *pdev)
-{
- return sdhci_pltfm_unregister(pdev);
-}
-
-static const struct of_device_id sdhci_hlwd_of_match[] = {
- { .compatible = "nintendo,hollywood-sdhci" },
- { }
-};
-MODULE_DEVICE_TABLE(of, sdhci_hlwd_of_match);
-
-static struct platform_driver sdhci_hlwd_driver = {
- .driver = {
- .name = "sdhci-hlwd",
- .owner = THIS_MODULE,
- .of_match_table = sdhci_hlwd_of_match,
- .pm = SDHCI_PLTFM_PMOPS,
- },
- .probe = sdhci_hlwd_probe,
- .remove = __devexit_p(sdhci_hlwd_remove),
-};
-
-module_platform_driver(sdhci_hlwd_driver);
-
-MODULE_DESCRIPTION("Nintendo Wii SDHCI OF driver");
-MODULE_AUTHOR("The GameCube Linux Team, Albert Herranz");
-MODULE_LICENSE("GPL v2");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pci-data.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-pci-data.c
deleted file mode 100644
index a6112177..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pci-data.c
+++ /dev/null
@@ -1,5 +0,0 @@
-#include <linux/module.h>
-#include <linux/mmc/sdhci-pci-data.h>
-
-struct sdhci_pci_data *(*sdhci_pci_get_data)(struct pci_dev *pdev, int slotno);
-EXPORT_SYMBOL_GPL(sdhci_pci_get_data);
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pci.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-pci.c
deleted file mode 100644
index 69ef0bea..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pci.c
+++ /dev/null
@@ -1,1499 +0,0 @@
-/* linux/drivers/mmc/host/sdhci-pci.c - SDHCI on PCI bus 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.
- *
- * Thanks to the following companies for their support:
- *
- * - JMicron (hardware and technical support)
- */
-
-#include <linux/delay.h>
-#include <linux/highmem.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/mmc/host.h>
-#include <linux/scatterlist.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/pm_runtime.h>
-#include <linux/mmc/sdhci-pci-data.h>
-
-#include "sdhci.h"
-
-/*
- * PCI device IDs
- */
-#define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809
-#define PCI_DEVICE_ID_INTEL_PCH_SDIO1 0x880a
-
-/*
- * PCI registers
- */
-
-#define PCI_SDHCI_IFPIO 0x00
-#define PCI_SDHCI_IFDMA 0x01
-#define PCI_SDHCI_IFVENDOR 0x02
-
-#define PCI_SLOT_INFO 0x40 /* 8 bits */
-#define PCI_SLOT_INFO_SLOTS(x) ((x >> 4) & 7)
-#define PCI_SLOT_INFO_FIRST_BAR_MASK 0x07
-
-#define MAX_SLOTS 8
-
-struct sdhci_pci_chip;
-struct sdhci_pci_slot;
-
-struct sdhci_pci_fixes {
- unsigned int quirks;
- unsigned int quirks2;
- bool allow_runtime_pm;
-
- int (*probe) (struct sdhci_pci_chip *);
-
- int (*probe_slot) (struct sdhci_pci_slot *);
- void (*remove_slot) (struct sdhci_pci_slot *, int);
-
- int (*suspend) (struct sdhci_pci_chip *);
- int (*resume) (struct sdhci_pci_chip *);
-};
-
-struct sdhci_pci_slot {
- struct sdhci_pci_chip *chip;
- struct sdhci_host *host;
- struct sdhci_pci_data *data;
-
- int pci_bar;
- int rst_n_gpio;
- int cd_gpio;
- int cd_irq;
-};
-
-struct sdhci_pci_chip {
- struct pci_dev *pdev;
-
- unsigned int quirks;
- unsigned int quirks2;
- bool allow_runtime_pm;
- const struct sdhci_pci_fixes *fixes;
-
- int num_slots; /* Slots on controller */
- struct sdhci_pci_slot *slots[MAX_SLOTS]; /* Pointers to host slots */
-};
-
-
-/*****************************************************************************\
- * *
- * Hardware specific quirk handling *
- * *
-\*****************************************************************************/
-
-static int ricoh_probe(struct sdhci_pci_chip *chip)
-{
- if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG ||
- chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SONY)
- chip->quirks |= SDHCI_QUIRK_NO_CARD_NO_RESET;
- return 0;
-}
-
-static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot)
-{
- slot->host->caps =
- ((0x21 << SDHCI_TIMEOUT_CLK_SHIFT)
- & SDHCI_TIMEOUT_CLK_MASK) |
-
- ((0x21 << SDHCI_CLOCK_BASE_SHIFT)
- & SDHCI_CLOCK_BASE_MASK) |
-
- SDHCI_TIMEOUT_CLK_UNIT |
- SDHCI_CAN_VDD_330 |
- SDHCI_CAN_DO_SDMA;
- return 0;
-}
-
-static int ricoh_mmc_resume(struct sdhci_pci_chip *chip)
-{
- /* Apply a delay to allow controller to settle */
- /* Otherwise it becomes confused if card state changed
- during suspend */
- msleep(500);
- return 0;
-}
-
-static const struct sdhci_pci_fixes sdhci_ricoh = {
- .probe = ricoh_probe,
- .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
- SDHCI_QUIRK_FORCE_DMA |
- SDHCI_QUIRK_CLOCK_BEFORE_RESET,
-};
-
-static const struct sdhci_pci_fixes sdhci_ricoh_mmc = {
- .probe_slot = ricoh_mmc_probe_slot,
- .resume = ricoh_mmc_resume,
- .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
- SDHCI_QUIRK_CLOCK_BEFORE_RESET |
- SDHCI_QUIRK_NO_CARD_NO_RESET |
- SDHCI_QUIRK_MISSING_CAPS
-};
-
-static const struct sdhci_pci_fixes sdhci_ene_712 = {
- .quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE |
- SDHCI_QUIRK_BROKEN_DMA,
-};
-
-static const struct sdhci_pci_fixes sdhci_ene_714 = {
- .quirks = SDHCI_QUIRK_SINGLE_POWER_WRITE |
- SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS |
- SDHCI_QUIRK_BROKEN_DMA,
-};
-
-static const struct sdhci_pci_fixes sdhci_cafe = {
- .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
- SDHCI_QUIRK_NO_BUSY_IRQ |
- SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
-};
-
-static int mrst_hc_probe_slot(struct sdhci_pci_slot *slot)
-{
- slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA;
- return 0;
-}
-
-/*
- * ADMA operation is disabled for Moorestown platform due to
- * hardware bugs.
- */
-static int mrst_hc_probe(struct sdhci_pci_chip *chip)
-{
- /*
- * slots number is fixed here for MRST as SDIO3/5 are never used and
- * have hardware bugs.
- */
- chip->num_slots = 1;
- return 0;
-}
-
-static int pch_hc_probe_slot(struct sdhci_pci_slot *slot)
-{
- slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA;
- return 0;
-}
-
-#ifdef CONFIG_PM_RUNTIME
-
-static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id)
-{
- struct sdhci_pci_slot *slot = dev_id;
- struct sdhci_host *host = slot->host;
-
- mmc_detect_change(host->mmc, msecs_to_jiffies(200));
- return IRQ_HANDLED;
-}
-
-static void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot)
-{
- int err, irq, gpio = slot->cd_gpio;
-
- slot->cd_gpio = -EINVAL;
- slot->cd_irq = -EINVAL;
-
- if (!gpio_is_valid(gpio))
- return;
-
- err = gpio_request(gpio, "sd_cd");
- if (err < 0)
- goto out;
-
- err = gpio_direction_input(gpio);
- if (err < 0)
- goto out_free;
-
- irq = gpio_to_irq(gpio);
- if (irq < 0)
- goto out_free;
-
- err = request_irq(irq, sdhci_pci_sd_cd, IRQF_TRIGGER_RISING |
- IRQF_TRIGGER_FALLING, "sd_cd", slot);
- if (err)
- goto out_free;
-
- slot->cd_gpio = gpio;
- slot->cd_irq = irq;
-
- return;
-
-out_free:
- gpio_free(gpio);
-out:
- dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n");
-}
-
-static void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot)
-{
- if (slot->cd_irq >= 0)
- free_irq(slot->cd_irq, slot);
- if (gpio_is_valid(slot->cd_gpio))
- gpio_free(slot->cd_gpio);
-}
-
-#else
-
-static inline void sdhci_pci_add_own_cd(struct sdhci_pci_slot *slot)
-{
-}
-
-static inline void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot)
-{
-}
-
-#endif
-
-static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot)
-{
- slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE;
- slot->host->mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC |
- MMC_CAP2_HC_ERASE_SZ;
- return 0;
-}
-
-static int mfd_sdio_probe_slot(struct sdhci_pci_slot *slot)
-{
- slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE;
- return 0;
-}
-
-static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = {
- .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT,
- .probe_slot = mrst_hc_probe_slot,
-};
-
-static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = {
- .quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT,
- .probe = mrst_hc_probe,
-};
-
-static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = {
- .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
- .allow_runtime_pm = true,
-};
-
-static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = {
- .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
- .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
- .allow_runtime_pm = true,
- .probe_slot = mfd_sdio_probe_slot,
-};
-
-static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = {
- .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
- .allow_runtime_pm = true,
- .probe_slot = mfd_emmc_probe_slot,
-};
-
-static const struct sdhci_pci_fixes sdhci_intel_pch_sdio = {
- .quirks = SDHCI_QUIRK_BROKEN_ADMA,
- .probe_slot = pch_hc_probe_slot,
-};
-
-/* O2Micro extra registers */
-#define O2_SD_LOCK_WP 0xD3
-#define O2_SD_MULTI_VCC3V 0xEE
-#define O2_SD_CLKREQ 0xEC
-#define O2_SD_CAPS 0xE0
-#define O2_SD_ADMA1 0xE2
-#define O2_SD_ADMA2 0xE7
-#define O2_SD_INF_MOD 0xF1
-
-static int o2_probe(struct sdhci_pci_chip *chip)
-{
- int ret;
- u8 scratch;
-
- switch (chip->pdev->device) {
- case PCI_DEVICE_ID_O2_8220:
- case PCI_DEVICE_ID_O2_8221:
- case PCI_DEVICE_ID_O2_8320:
- case PCI_DEVICE_ID_O2_8321:
- /* This extra setup is required due to broken ADMA. */
- ret = pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch);
- if (ret)
- return ret;
- scratch &= 0x7f;
- pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
-
- /* Set Multi 3 to VCC3V# */
- pci_write_config_byte(chip->pdev, O2_SD_MULTI_VCC3V, 0x08);
-
- /* Disable CLK_REQ# support after media DET */
- ret = pci_read_config_byte(chip->pdev, O2_SD_CLKREQ, &scratch);
- if (ret)
- return ret;
- scratch |= 0x20;
- pci_write_config_byte(chip->pdev, O2_SD_CLKREQ, scratch);
-
- /* Choose capabilities, enable SDMA. We have to write 0x01
- * to the capabilities register first to unlock it.
- */
- ret = pci_read_config_byte(chip->pdev, O2_SD_CAPS, &scratch);
- if (ret)
- return ret;
- scratch |= 0x01;
- pci_write_config_byte(chip->pdev, O2_SD_CAPS, scratch);
- pci_write_config_byte(chip->pdev, O2_SD_CAPS, 0x73);
-
- /* Disable ADMA1/2 */
- pci_write_config_byte(chip->pdev, O2_SD_ADMA1, 0x39);
- pci_write_config_byte(chip->pdev, O2_SD_ADMA2, 0x08);
-
- /* Disable the infinite transfer mode */
- ret = pci_read_config_byte(chip->pdev, O2_SD_INF_MOD, &scratch);
- if (ret)
- return ret;
- scratch |= 0x08;
- pci_write_config_byte(chip->pdev, O2_SD_INF_MOD, scratch);
-
- /* Lock WP */
- ret = pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch);
- if (ret)
- return ret;
- scratch |= 0x80;
- pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
- }
-
- return 0;
-}
-
-static int jmicron_pmos(struct sdhci_pci_chip *chip, int on)
-{
- u8 scratch;
- int ret;
-
- ret = pci_read_config_byte(chip->pdev, 0xAE, &scratch);
- if (ret)
- return ret;
-
- /*
- * Turn PMOS on [bit 0], set over current detection to 2.4 V
- * [bit 1:2] and enable over current debouncing [bit 6].
- */
- if (on)
- scratch |= 0x47;
- else
- scratch &= ~0x47;
-
- ret = pci_write_config_byte(chip->pdev, 0xAE, scratch);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int jmicron_probe(struct sdhci_pci_chip *chip)
-{
- int ret;
- u16 mmcdev = 0;
-
- if (chip->pdev->revision == 0) {
- chip->quirks |= SDHCI_QUIRK_32BIT_DMA_ADDR |
- SDHCI_QUIRK_32BIT_DMA_SIZE |
- SDHCI_QUIRK_32BIT_ADMA_SIZE |
- SDHCI_QUIRK_RESET_AFTER_REQUEST |
- SDHCI_QUIRK_BROKEN_SMALL_PIO;
- }
-
- /*
- * JMicron chips can have two interfaces to the same hardware
- * in order to work around limitations in Microsoft's driver.
- * We need to make sure we only bind to one of them.
- *
- * This code assumes two things:
- *
- * 1. The PCI code adds subfunctions in order.
- *
- * 2. The MMC interface has a lower subfunction number
- * than the SD interface.
- */
- if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_SD)
- mmcdev = PCI_DEVICE_ID_JMICRON_JMB38X_MMC;
- else if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD)
- mmcdev = PCI_DEVICE_ID_JMICRON_JMB388_ESD;
-
- if (mmcdev) {
- struct pci_dev *sd_dev;
-
- sd_dev = NULL;
- while ((sd_dev = pci_get_device(PCI_VENDOR_ID_JMICRON,
- mmcdev, sd_dev)) != NULL) {
- if ((PCI_SLOT(chip->pdev->devfn) ==
- PCI_SLOT(sd_dev->devfn)) &&
- (chip->pdev->bus == sd_dev->bus))
- break;
- }
-
- if (sd_dev) {
- pci_dev_put(sd_dev);
- dev_info(&chip->pdev->dev, "Refusing to bind to "
- "secondary interface.\n");
- return -ENODEV;
- }
- }
-
- /*
- * JMicron chips need a bit of a nudge to enable the power
- * output pins.
- */
- ret = jmicron_pmos(chip, 1);
- if (ret) {
- dev_err(&chip->pdev->dev, "Failure enabling card power\n");
- return ret;
- }
-
- /* quirk for unsable RO-detection on JM388 chips */
- if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD ||
- chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD)
- chip->quirks |= SDHCI_QUIRK_UNSTABLE_RO_DETECT;
-
- return 0;
-}
-
-static void jmicron_enable_mmc(struct sdhci_host *host, int on)
-{
- u8 scratch;
-
- scratch = readb(host->ioaddr + 0xC0);
-
- if (on)
- scratch |= 0x01;
- else
- scratch &= ~0x01;
-
- writeb(scratch, host->ioaddr + 0xC0);
-}
-
-static int jmicron_probe_slot(struct sdhci_pci_slot *slot)
-{
- if (slot->chip->pdev->revision == 0) {
- u16 version;
-
- version = readl(slot->host->ioaddr + SDHCI_HOST_VERSION);
- version = (version & SDHCI_VENDOR_VER_MASK) >>
- SDHCI_VENDOR_VER_SHIFT;
-
- /*
- * Older versions of the chip have lots of nasty glitches
- * in the ADMA engine. It's best just to avoid it
- * completely.
- */
- if (version < 0xAC)
- slot->host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
- }
-
- /* JM388 MMC doesn't support 1.8V while SD supports it */
- if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
- slot->host->ocr_avail_sd = MMC_VDD_32_33 | MMC_VDD_33_34 |
- MMC_VDD_29_30 | MMC_VDD_30_31 |
- MMC_VDD_165_195; /* allow 1.8V */
- slot->host->ocr_avail_mmc = MMC_VDD_32_33 | MMC_VDD_33_34 |
- MMC_VDD_29_30 | MMC_VDD_30_31; /* no 1.8V for MMC */
- }
-
- /*
- * The secondary interface requires a bit set to get the
- * interrupts.
- */
- if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
- slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD)
- jmicron_enable_mmc(slot->host, 1);
-
- slot->host->mmc->caps |= MMC_CAP_BUS_WIDTH_TEST;
-
- return 0;
-}
-
-static void jmicron_remove_slot(struct sdhci_pci_slot *slot, int dead)
-{
- if (dead)
- return;
-
- if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
- slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD)
- jmicron_enable_mmc(slot->host, 0);
-}
-
-static int jmicron_suspend(struct sdhci_pci_chip *chip)
-{
- int i;
-
- if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
- chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
- for (i = 0; i < chip->num_slots; i++)
- jmicron_enable_mmc(chip->slots[i]->host, 0);
- }
-
- return 0;
-}
-
-static int jmicron_resume(struct sdhci_pci_chip *chip)
-{
- int ret, i;
-
- if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
- chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
- for (i = 0; i < chip->num_slots; i++)
- jmicron_enable_mmc(chip->slots[i]->host, 1);
- }
-
- ret = jmicron_pmos(chip, 1);
- if (ret) {
- dev_err(&chip->pdev->dev, "Failure enabling card power\n");
- return ret;
- }
-
- return 0;
-}
-
-static const struct sdhci_pci_fixes sdhci_o2 = {
- .probe = o2_probe,
-};
-
-static const struct sdhci_pci_fixes sdhci_jmicron = {
- .probe = jmicron_probe,
-
- .probe_slot = jmicron_probe_slot,
- .remove_slot = jmicron_remove_slot,
-
- .suspend = jmicron_suspend,
- .resume = jmicron_resume,
-};
-
-/* SysKonnect CardBus2SDIO extra registers */
-#define SYSKT_CTRL 0x200
-#define SYSKT_RDFIFO_STAT 0x204
-#define SYSKT_WRFIFO_STAT 0x208
-#define SYSKT_POWER_DATA 0x20c
-#define SYSKT_POWER_330 0xef
-#define SYSKT_POWER_300 0xf8
-#define SYSKT_POWER_184 0xcc
-#define SYSKT_POWER_CMD 0x20d
-#define SYSKT_POWER_START (1 << 7)
-#define SYSKT_POWER_STATUS 0x20e
-#define SYSKT_POWER_STATUS_OK (1 << 0)
-#define SYSKT_BOARD_REV 0x210
-#define SYSKT_CHIP_REV 0x211
-#define SYSKT_CONF_DATA 0x212
-#define SYSKT_CONF_DATA_1V8 (1 << 2)
-#define SYSKT_CONF_DATA_2V5 (1 << 1)
-#define SYSKT_CONF_DATA_3V3 (1 << 0)
-
-static int syskt_probe(struct sdhci_pci_chip *chip)
-{
- if ((chip->pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
- chip->pdev->class &= ~0x0000FF;
- chip->pdev->class |= PCI_SDHCI_IFDMA;
- }
- return 0;
-}
-
-static int syskt_probe_slot(struct sdhci_pci_slot *slot)
-{
- int tm, ps;
-
- u8 board_rev = readb(slot->host->ioaddr + SYSKT_BOARD_REV);
- u8 chip_rev = readb(slot->host->ioaddr + SYSKT_CHIP_REV);
- dev_info(&slot->chip->pdev->dev, "SysKonnect CardBus2SDIO, "
- "board rev %d.%d, chip rev %d.%d\n",
- board_rev >> 4, board_rev & 0xf,
- chip_rev >> 4, chip_rev & 0xf);
- if (chip_rev >= 0x20)
- slot->host->quirks |= SDHCI_QUIRK_FORCE_DMA;
-
- writeb(SYSKT_POWER_330, slot->host->ioaddr + SYSKT_POWER_DATA);
- writeb(SYSKT_POWER_START, slot->host->ioaddr + SYSKT_POWER_CMD);
- udelay(50);
- tm = 10; /* Wait max 1 ms */
- do {
- ps = readw(slot->host->ioaddr + SYSKT_POWER_STATUS);
- if (ps & SYSKT_POWER_STATUS_OK)
- break;
- udelay(100);
- } while (--tm);
- if (!tm) {
- dev_err(&slot->chip->pdev->dev,
- "power regulator never stabilized");
- writeb(0, slot->host->ioaddr + SYSKT_POWER_CMD);
- return -ENODEV;
- }
-
- return 0;
-}
-
-static const struct sdhci_pci_fixes sdhci_syskt = {
- .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER,
- .probe = syskt_probe,
- .probe_slot = syskt_probe_slot,
-};
-
-static int via_probe(struct sdhci_pci_chip *chip)
-{
- if (chip->pdev->revision == 0x10)
- chip->quirks |= SDHCI_QUIRK_DELAY_AFTER_POWER;
-
- return 0;
-}
-
-static const struct sdhci_pci_fixes sdhci_via = {
- .probe = via_probe,
-};
-
-static const struct pci_device_id pci_ids[] __devinitdata = {
- {
- .vendor = PCI_VENDOR_ID_RICOH,
- .device = PCI_DEVICE_ID_RICOH_R5C822,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_ricoh,
- },
-
- {
- .vendor = PCI_VENDOR_ID_RICOH,
- .device = 0x843,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_RICOH,
- .device = 0xe822,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_RICOH,
- .device = 0xe823,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_ENE,
- .device = PCI_DEVICE_ID_ENE_CB712_SD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_ene_712,
- },
-
- {
- .vendor = PCI_VENDOR_ID_ENE,
- .device = PCI_DEVICE_ID_ENE_CB712_SD_2,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_ene_712,
- },
-
- {
- .vendor = PCI_VENDOR_ID_ENE,
- .device = PCI_DEVICE_ID_ENE_CB714_SD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_ene_714,
- },
-
- {
- .vendor = PCI_VENDOR_ID_ENE,
- .device = PCI_DEVICE_ID_ENE_CB714_SD_2,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_ene_714,
- },
-
- {
- .vendor = PCI_VENDOR_ID_MARVELL,
- .device = PCI_DEVICE_ID_MARVELL_88ALP01_SD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_cafe,
- },
-
- {
- .vendor = PCI_VENDOR_ID_JMICRON,
- .device = PCI_DEVICE_ID_JMICRON_JMB38X_SD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_jmicron,
- },
-
- {
- .vendor = PCI_VENDOR_ID_JMICRON,
- .device = PCI_DEVICE_ID_JMICRON_JMB38X_MMC,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_jmicron,
- },
-
- {
- .vendor = PCI_VENDOR_ID_JMICRON,
- .device = PCI_DEVICE_ID_JMICRON_JMB388_SD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_jmicron,
- },
-
- {
- .vendor = PCI_VENDOR_ID_JMICRON,
- .device = PCI_DEVICE_ID_JMICRON_JMB388_ESD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_jmicron,
- },
-
- {
- .vendor = PCI_VENDOR_ID_SYSKONNECT,
- .device = 0x8000,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_syskt,
- },
-
- {
- .vendor = PCI_VENDOR_ID_VIA,
- .device = 0x95d0,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .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_hc2,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_MRST_SD2,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1_hc2,
- },
-
- {
- .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_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_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,
- },
-
- {
- .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,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_PCH_SDIO0,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_pch_sdio,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_PCH_SDIO1,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_pch_sdio,
- },
-
- {
- .vendor = PCI_VENDOR_ID_O2,
- .device = PCI_DEVICE_ID_O2_8120,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_o2,
- },
-
- {
- .vendor = PCI_VENDOR_ID_O2,
- .device = PCI_DEVICE_ID_O2_8220,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_o2,
- },
-
- {
- .vendor = PCI_VENDOR_ID_O2,
- .device = PCI_DEVICE_ID_O2_8221,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_o2,
- },
-
- {
- .vendor = PCI_VENDOR_ID_O2,
- .device = PCI_DEVICE_ID_O2_8320,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_o2,
- },
-
- {
- .vendor = PCI_VENDOR_ID_O2,
- .device = PCI_DEVICE_ID_O2_8321,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_o2,
- },
-
- { /* Generic SD host controller */
- PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
- },
-
- { /* end: all zeroes */ },
-};
-
-MODULE_DEVICE_TABLE(pci, pci_ids);
-
-/*****************************************************************************\
- * *
- * SDHCI core callbacks *
- * *
-\*****************************************************************************/
-
-static int sdhci_pci_enable_dma(struct sdhci_host *host)
-{
- struct sdhci_pci_slot *slot;
- struct pci_dev *pdev;
- int ret;
-
- slot = sdhci_priv(host);
- pdev = slot->chip->pdev;
-
- if (((pdev->class & 0xFFFF00) == (PCI_CLASS_SYSTEM_SDHCI << 8)) &&
- ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) &&
- (host->flags & SDHCI_USE_SDMA)) {
- dev_warn(&pdev->dev, "Will use DMA mode even though HW "
- "doesn't fully claim to support it.\n");
- }
-
- ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- if (ret)
- return ret;
-
- pci_set_master(pdev);
-
- return 0;
-}
-
-static int sdhci_pci_8bit_width(struct sdhci_host *host, int width)
-{
- u8 ctrl;
-
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
-
- switch (width) {
- case MMC_BUS_WIDTH_8:
- ctrl |= SDHCI_CTRL_8BITBUS;
- ctrl &= ~SDHCI_CTRL_4BITBUS;
- break;
- case MMC_BUS_WIDTH_4:
- ctrl |= SDHCI_CTRL_4BITBUS;
- ctrl &= ~SDHCI_CTRL_8BITBUS;
- break;
- default:
- ctrl &= ~(SDHCI_CTRL_8BITBUS | SDHCI_CTRL_4BITBUS);
- break;
- }
-
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-
- return 0;
-}
-
-static void sdhci_pci_hw_reset(struct sdhci_host *host)
-{
- struct sdhci_pci_slot *slot = sdhci_priv(host);
- int rst_n_gpio = slot->rst_n_gpio;
-
- if (!gpio_is_valid(rst_n_gpio))
- return;
- gpio_set_value_cansleep(rst_n_gpio, 0);
- /* For eMMC, minimum is 1us but give it 10us for good measure */
- udelay(10);
- gpio_set_value_cansleep(rst_n_gpio, 1);
- /* For eMMC, minimum is 200us but give it 300us for good measure */
- usleep_range(300, 1000);
-}
-
-static struct sdhci_ops sdhci_pci_ops = {
- .enable_dma = sdhci_pci_enable_dma,
- .platform_8bit_width = sdhci_pci_8bit_width,
- .hw_reset = sdhci_pci_hw_reset,
-};
-
-/*****************************************************************************\
- * *
- * Suspend/resume *
- * *
-\*****************************************************************************/
-
-#ifdef CONFIG_PM
-
-static int sdhci_pci_suspend(struct device *dev)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct sdhci_pci_chip *chip;
- struct sdhci_pci_slot *slot;
- mmc_pm_flag_t slot_pm_flags;
- mmc_pm_flag_t pm_flags = 0;
- int i, ret;
-
- chip = pci_get_drvdata(pdev);
- if (!chip)
- return 0;
-
- for (i = 0; i < chip->num_slots; i++) {
- slot = chip->slots[i];
- if (!slot)
- continue;
-
- ret = sdhci_suspend_host(slot->host);
-
- if (ret)
- goto err_pci_suspend;
-
- slot_pm_flags = slot->host->mmc->pm_flags;
- if (slot_pm_flags & MMC_PM_WAKE_SDIO_IRQ)
- sdhci_enable_irq_wakeups(slot->host);
-
- pm_flags |= slot_pm_flags;
- }
-
- if (chip->fixes && chip->fixes->suspend) {
- ret = chip->fixes->suspend(chip);
- if (ret)
- goto err_pci_suspend;
- }
-
- pci_save_state(pdev);
- if (pm_flags & MMC_PM_KEEP_POWER) {
- if (pm_flags & MMC_PM_WAKE_SDIO_IRQ) {
- pci_pme_active(pdev, true);
- pci_enable_wake(pdev, PCI_D3hot, 1);
- }
- pci_set_power_state(pdev, PCI_D3hot);
- } else {
- pci_enable_wake(pdev, PCI_D3hot, 0);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
- }
-
- return 0;
-
-err_pci_suspend:
- while (--i >= 0)
- sdhci_resume_host(chip->slots[i]->host);
- return ret;
-}
-
-static int sdhci_pci_resume(struct device *dev)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct sdhci_pci_chip *chip;
- struct sdhci_pci_slot *slot;
- int i, ret;
-
- chip = pci_get_drvdata(pdev);
- if (!chip)
- return 0;
-
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
- ret = pci_enable_device(pdev);
- if (ret)
- return ret;
-
- if (chip->fixes && chip->fixes->resume) {
- ret = chip->fixes->resume(chip);
- if (ret)
- return ret;
- }
-
- for (i = 0; i < chip->num_slots; i++) {
- slot = chip->slots[i];
- if (!slot)
- continue;
-
- ret = sdhci_resume_host(slot->host);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-#else /* CONFIG_PM */
-
-#define sdhci_pci_suspend NULL
-#define sdhci_pci_resume NULL
-
-#endif /* CONFIG_PM */
-
-#ifdef CONFIG_PM_RUNTIME
-
-static int sdhci_pci_runtime_suspend(struct device *dev)
-{
- struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
- struct sdhci_pci_chip *chip;
- struct sdhci_pci_slot *slot;
- int i, ret;
-
- chip = pci_get_drvdata(pdev);
- if (!chip)
- return 0;
-
- for (i = 0; i < chip->num_slots; i++) {
- slot = chip->slots[i];
- if (!slot)
- continue;
-
- ret = sdhci_runtime_suspend_host(slot->host);
-
- if (ret)
- goto err_pci_runtime_suspend;
- }
-
- if (chip->fixes && chip->fixes->suspend) {
- ret = chip->fixes->suspend(chip);
- if (ret)
- goto err_pci_runtime_suspend;
- }
-
- return 0;
-
-err_pci_runtime_suspend:
- while (--i >= 0)
- sdhci_runtime_resume_host(chip->slots[i]->host);
- return ret;
-}
-
-static int sdhci_pci_runtime_resume(struct device *dev)
-{
- struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
- struct sdhci_pci_chip *chip;
- struct sdhci_pci_slot *slot;
- int i, ret;
-
- chip = pci_get_drvdata(pdev);
- if (!chip)
- return 0;
-
- if (chip->fixes && chip->fixes->resume) {
- ret = chip->fixes->resume(chip);
- if (ret)
- return ret;
- }
-
- for (i = 0; i < chip->num_slots; i++) {
- slot = chip->slots[i];
- if (!slot)
- continue;
-
- ret = sdhci_runtime_resume_host(slot->host);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int sdhci_pci_runtime_idle(struct device *dev)
-{
- return 0;
-}
-
-#else
-
-#define sdhci_pci_runtime_suspend NULL
-#define sdhci_pci_runtime_resume NULL
-#define sdhci_pci_runtime_idle NULL
-
-#endif
-
-static const struct dev_pm_ops sdhci_pci_pm_ops = {
- .suspend = sdhci_pci_suspend,
- .resume = sdhci_pci_resume,
- .runtime_suspend = sdhci_pci_runtime_suspend,
- .runtime_resume = sdhci_pci_runtime_resume,
- .runtime_idle = sdhci_pci_runtime_idle,
-};
-
-/*****************************************************************************\
- * *
- * Device probing/removal *
- * *
-\*****************************************************************************/
-
-static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
- struct pci_dev *pdev, struct sdhci_pci_chip *chip, int first_bar,
- int slotno)
-{
- struct sdhci_pci_slot *slot;
- struct sdhci_host *host;
- int ret, bar = first_bar + slotno;
-
- if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
- dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar);
- return ERR_PTR(-ENODEV);
- }
-
- if (pci_resource_len(pdev, bar) != 0x100) {
- dev_err(&pdev->dev, "Invalid iomem size. You may "
- "experience problems.\n");
- }
-
- if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
- dev_err(&pdev->dev, "Vendor specific interface. Aborting.\n");
- return ERR_PTR(-ENODEV);
- }
-
- if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) {
- dev_err(&pdev->dev, "Unknown interface. Aborting.\n");
- return ERR_PTR(-ENODEV);
- }
-
- host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pci_slot));
- if (IS_ERR(host)) {
- dev_err(&pdev->dev, "cannot allocate host\n");
- return ERR_CAST(host);
- }
-
- slot = sdhci_priv(host);
-
- slot->chip = chip;
- slot->host = host;
- slot->pci_bar = bar;
- slot->rst_n_gpio = -EINVAL;
- slot->cd_gpio = -EINVAL;
-
- /* Retrieve platform data if there is any */
- if (*sdhci_pci_get_data)
- slot->data = sdhci_pci_get_data(pdev, slotno);
-
- if (slot->data) {
- if (slot->data->setup) {
- ret = slot->data->setup(slot->data);
- if (ret) {
- dev_err(&pdev->dev, "platform setup failed\n");
- goto free;
- }
- }
- slot->rst_n_gpio = slot->data->rst_n_gpio;
- slot->cd_gpio = slot->data->cd_gpio;
- }
-
- host->hw_name = "PCI";
- host->ops = &sdhci_pci_ops;
- host->quirks = chip->quirks;
- host->quirks2 = chip->quirks2;
-
- host->irq = pdev->irq;
-
- ret = pci_request_region(pdev, bar, mmc_hostname(host->mmc));
- if (ret) {
- dev_err(&pdev->dev, "cannot request region\n");
- goto cleanup;
- }
-
- host->ioaddr = pci_ioremap_bar(pdev, bar);
- if (!host->ioaddr) {
- dev_err(&pdev->dev, "failed to remap registers\n");
- ret = -ENOMEM;
- goto release;
- }
-
- if (chip->fixes && chip->fixes->probe_slot) {
- ret = chip->fixes->probe_slot(slot);
- if (ret)
- goto unmap;
- }
-
- if (gpio_is_valid(slot->rst_n_gpio)) {
- if (!gpio_request(slot->rst_n_gpio, "eMMC_reset")) {
- gpio_direction_output(slot->rst_n_gpio, 1);
- slot->host->mmc->caps |= MMC_CAP_HW_RESET;
- } else {
- dev_warn(&pdev->dev, "failed to request rst_n_gpio\n");
- slot->rst_n_gpio = -EINVAL;
- }
- }
-
- host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
-
- ret = sdhci_add_host(host);
- if (ret)
- goto remove;
-
- sdhci_pci_add_own_cd(slot);
-
- return slot;
-
-remove:
- if (gpio_is_valid(slot->rst_n_gpio))
- gpio_free(slot->rst_n_gpio);
-
- if (chip->fixes && chip->fixes->remove_slot)
- chip->fixes->remove_slot(slot, 0);
-
-unmap:
- iounmap(host->ioaddr);
-
-release:
- pci_release_region(pdev, bar);
-
-cleanup:
- if (slot->data && slot->data->cleanup)
- slot->data->cleanup(slot->data);
-
-free:
- sdhci_free_host(host);
-
- return ERR_PTR(ret);
-}
-
-static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
-{
- int dead;
- u32 scratch;
-
- sdhci_pci_remove_own_cd(slot);
-
- dead = 0;
- scratch = readl(slot->host->ioaddr + SDHCI_INT_STATUS);
- if (scratch == (u32)-1)
- dead = 1;
-
- sdhci_remove_host(slot->host, dead);
-
- if (gpio_is_valid(slot->rst_n_gpio))
- gpio_free(slot->rst_n_gpio);
-
- if (slot->chip->fixes && slot->chip->fixes->remove_slot)
- slot->chip->fixes->remove_slot(slot, dead);
-
- if (slot->data && slot->data->cleanup)
- slot->data->cleanup(slot->data);
-
- pci_release_region(slot->chip->pdev, slot->pci_bar);
-
- sdhci_free_host(slot->host);
-}
-
-static void __devinit sdhci_pci_runtime_pm_allow(struct device *dev)
-{
- pm_runtime_put_noidle(dev);
- pm_runtime_allow(dev);
- pm_runtime_set_autosuspend_delay(dev, 50);
- pm_runtime_use_autosuspend(dev);
- pm_suspend_ignore_children(dev, 1);
-}
-
-static void __devexit sdhci_pci_runtime_pm_forbid(struct device *dev)
-{
- pm_runtime_forbid(dev);
- pm_runtime_get_noresume(dev);
-}
-
-static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- struct sdhci_pci_chip *chip;
- struct sdhci_pci_slot *slot;
-
- u8 slots, first_bar;
- int ret, i;
-
- BUG_ON(pdev == NULL);
- BUG_ON(ent == NULL);
-
- dev_info(&pdev->dev, "SDHCI controller found [%04x:%04x] (rev %x)\n",
- (int)pdev->vendor, (int)pdev->device, (int)pdev->revision);
-
- ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots);
- if (ret)
- return ret;
-
- slots = PCI_SLOT_INFO_SLOTS(slots) + 1;
- dev_dbg(&pdev->dev, "found %d slot(s)\n", slots);
- if (slots == 0)
- return -ENODEV;
-
- BUG_ON(slots > MAX_SLOTS);
-
- ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &first_bar);
- if (ret)
- return ret;
-
- first_bar &= PCI_SLOT_INFO_FIRST_BAR_MASK;
-
- if (first_bar > 5) {
- dev_err(&pdev->dev, "Invalid first BAR. Aborting.\n");
- return -ENODEV;
- }
-
- ret = pci_enable_device(pdev);
- if (ret)
- return ret;
-
- chip = kzalloc(sizeof(struct sdhci_pci_chip), GFP_KERNEL);
- if (!chip) {
- ret = -ENOMEM;
- goto err;
- }
-
- chip->pdev = pdev;
- chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data;
- if (chip->fixes) {
- chip->quirks = chip->fixes->quirks;
- chip->quirks2 = chip->fixes->quirks2;
- chip->allow_runtime_pm = chip->fixes->allow_runtime_pm;
- }
- chip->num_slots = slots;
-
- pci_set_drvdata(pdev, chip);
-
- if (chip->fixes && chip->fixes->probe) {
- ret = chip->fixes->probe(chip);
- if (ret)
- 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)) {
- for (i--; i >= 0; i--)
- sdhci_pci_remove_slot(chip->slots[i]);
- ret = PTR_ERR(slot);
- goto free;
- }
-
- chip->slots[i] = slot;
- }
-
- if (chip->allow_runtime_pm)
- sdhci_pci_runtime_pm_allow(&pdev->dev);
-
- return 0;
-
-free:
- pci_set_drvdata(pdev, NULL);
- kfree(chip);
-
-err:
- pci_disable_device(pdev);
- return ret;
-}
-
-static void __devexit sdhci_pci_remove(struct pci_dev *pdev)
-{
- int i;
- struct sdhci_pci_chip *chip;
-
- chip = pci_get_drvdata(pdev);
-
- if (chip) {
- if (chip->allow_runtime_pm)
- sdhci_pci_runtime_pm_forbid(&pdev->dev);
-
- for (i = 0; i < chip->num_slots; i++)
- sdhci_pci_remove_slot(chip->slots[i]);
-
- pci_set_drvdata(pdev, NULL);
- kfree(chip);
- }
-
- pci_disable_device(pdev);
-}
-
-static struct pci_driver sdhci_driver = {
- .name = "sdhci-pci",
- .id_table = pci_ids,
- .probe = sdhci_pci_probe,
- .remove = __devexit_p(sdhci_pci_remove),
- .driver = {
- .pm = &sdhci_pci_pm_ops
- },
-};
-
-/*****************************************************************************\
- * *
- * Driver init/exit *
- * *
-\*****************************************************************************/
-
-static int __init sdhci_drv_init(void)
-{
- return pci_register_driver(&sdhci_driver);
-}
-
-static void __exit sdhci_drv_exit(void)
-{
- pci_unregister_driver(&sdhci_driver);
-}
-
-module_init(sdhci_drv_init);
-module_exit(sdhci_drv_exit);
-
-MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>");
-MODULE_DESCRIPTION("Secure Digital Host Controller Interface PCI driver");
-MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pltfm.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-pltfm.c
deleted file mode 100644
index c5c2a48b..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pltfm.c
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * sdhci-pltfm.c Support for SDHCI platform devices
- * Copyright (c) 2009 Intel Corporation
- *
- * Copyright (c) 2007, 2011 Freescale Semiconductor, Inc.
- * Copyright (c) 2009 MontaVista Software, Inc.
- *
- * Authors: Xiaobo Xie <X.Xie@freescale.com>
- * Anton Vorontsov <avorontsov@ru.mvista.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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* Supports:
- * SDHCI platform devices
- *
- * Inspired by sdhci-pci.c, by Pierre Ossman
- */
-
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#ifdef CONFIG_PPC
-#include <asm/machdep.h>
-#endif
-#include "sdhci-pltfm.h"
-
-static struct sdhci_ops sdhci_pltfm_ops = {
-};
-
-#ifdef CONFIG_OF
-static bool sdhci_of_wp_inverted(struct device_node *np)
-{
- if (of_get_property(np, "sdhci,wp-inverted", NULL))
- return true;
-
- /* Old device trees don't have the wp-inverted property. */
-#ifdef CONFIG_PPC
- return machine_is(mpc837x_rdb) || machine_is(mpc837x_mds);
-#else
- return false;
-#endif /* CONFIG_PPC */
-}
-
-void sdhci_get_of_property(struct platform_device *pdev)
-{
- struct device_node *np = pdev->dev.of_node;
- struct sdhci_host *host = platform_get_drvdata(pdev);
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- const __be32 *clk;
- int size;
-
- if (of_device_is_available(np)) {
- if (of_get_property(np, "sdhci,auto-cmd12", NULL))
- host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
-
- if (of_get_property(np, "sdhci,1-bit-only", NULL))
- host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
-
- if (sdhci_of_wp_inverted(np))
- host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
-
- if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc"))
- host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
-
- if (of_device_is_compatible(np, "fsl,p2020-esdhc") ||
- of_device_is_compatible(np, "fsl,p1010-esdhc") ||
- of_device_is_compatible(np, "fsl,mpc8536-esdhc"))
- host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
-
- clk = of_get_property(np, "clock-frequency", &size);
- if (clk && size == sizeof(*clk) && *clk)
- pltfm_host->clock = be32_to_cpup(clk);
- }
-}
-#else
-void sdhci_get_of_property(struct platform_device *pdev) {}
-#endif /* CONFIG_OF */
-EXPORT_SYMBOL_GPL(sdhci_get_of_property);
-
-struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
- struct sdhci_pltfm_data *pdata)
-{
- struct sdhci_host *host;
- struct sdhci_pltfm_host *pltfm_host;
- struct device_node *np = pdev->dev.of_node;
- struct resource *iomem;
- int ret;
-
- iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!iomem) {
- ret = -ENOMEM;
- goto err;
- }
-
- if (resource_size(iomem) < 0x100)
- dev_err(&pdev->dev, "Invalid iomem size!\n");
-
- /* Some PCI-based MFD need the parent here */
- if (pdev->dev.parent != &platform_bus && !np)
- host = sdhci_alloc_host(pdev->dev.parent, sizeof(*pltfm_host));
- else
- 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 = dev_name(&pdev->dev);
- if (pdata && pdata->ops)
- host->ops = pdata->ops;
- else
- host->ops = &sdhci_pltfm_ops;
- if (pdata)
- host->quirks = pdata->quirks;
- host->irq = platform_get_irq(pdev, 0);
-
- if (!request_mem_region(iomem->start, resource_size(iomem),
- mmc_hostname(host->mmc))) {
- dev_err(&pdev->dev, "cannot request region\n");
- ret = -EBUSY;
- goto err_request;
- }
-
- host->ioaddr = ioremap(iomem->start, resource_size(iomem));
- if (!host->ioaddr) {
- dev_err(&pdev->dev, "failed to remap registers\n");
- ret = -ENOMEM;
- goto err_remap;
- }
-
- platform_set_drvdata(pdev, host);
-
- return host;
-
-err_remap:
- release_mem_region(iomem->start, resource_size(iomem));
-err_request:
- sdhci_free_host(host);
-err:
- dev_err(&pdev->dev, "%s failed %d\n", __func__, ret);
- return ERR_PTR(ret);
-}
-EXPORT_SYMBOL_GPL(sdhci_pltfm_init);
-
-void sdhci_pltfm_free(struct platform_device *pdev)
-{
- struct sdhci_host *host = platform_get_drvdata(pdev);
- struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- iounmap(host->ioaddr);
- release_mem_region(iomem->start, resource_size(iomem));
- sdhci_free_host(host);
- platform_set_drvdata(pdev, NULL);
-}
-EXPORT_SYMBOL_GPL(sdhci_pltfm_free);
-
-int sdhci_pltfm_register(struct platform_device *pdev,
- struct sdhci_pltfm_data *pdata)
-{
- struct sdhci_host *host;
- int ret = 0;
-
- host = sdhci_pltfm_init(pdev, pdata);
- if (IS_ERR(host))
- return PTR_ERR(host);
-
- sdhci_get_of_property(pdev);
-
- ret = sdhci_add_host(host);
- if (ret)
- sdhci_pltfm_free(pdev);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(sdhci_pltfm_register);
-
-int sdhci_pltfm_unregister(struct platform_device *pdev)
-{
- struct sdhci_host *host = platform_get_drvdata(pdev);
- int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
-
- sdhci_remove_host(host, dead);
- sdhci_pltfm_free(pdev);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(sdhci_pltfm_unregister);
-
-#ifdef CONFIG_PM
-static int sdhci_pltfm_suspend(struct device *dev)
-{
- struct sdhci_host *host = dev_get_drvdata(dev);
-
- return sdhci_suspend_host(host);
-}
-
-static int sdhci_pltfm_resume(struct device *dev)
-{
- struct sdhci_host *host = dev_get_drvdata(dev);
-
- return sdhci_resume_host(host);
-}
-
-const struct dev_pm_ops sdhci_pltfm_pmops = {
- .suspend = sdhci_pltfm_suspend,
- .resume = sdhci_pltfm_resume,
-};
-EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops);
-#endif /* CONFIG_PM */
-
-static int __init sdhci_pltfm_drv_init(void)
-{
- pr_info("sdhci-pltfm: SDHCI platform and OF driver helper\n");
-
- return 0;
-}
-module_init(sdhci_pltfm_drv_init);
-
-static void __exit sdhci_pltfm_drv_exit(void)
-{
-}
-module_exit(sdhci_pltfm_drv_exit);
-
-MODULE_DESCRIPTION("SDHCI platform and OF driver helper");
-MODULE_AUTHOR("Intel Corporation");
-MODULE_LICENSE("GPL v2");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pltfm.h b/ANDROID_3.4.5/drivers/mmc/host/sdhci-pltfm.h
deleted file mode 100644
index 37e0e184..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pltfm.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2010 MontaVista Software, LLC.
- *
- * Author: Anton Vorontsov <avorontsov@ru.mvista.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.
- */
-
-#ifndef _DRIVERS_MMC_SDHCI_PLTFM_H
-#define _DRIVERS_MMC_SDHCI_PLTFM_H
-
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include "sdhci.h"
-
-struct sdhci_pltfm_data {
- struct sdhci_ops *ops;
- unsigned int quirks;
-};
-
-struct sdhci_pltfm_host {
- struct clk *clk;
- void *priv; /* to handle quirks across io-accessor calls */
-
- /* migrate from sdhci_of_host */
- unsigned int clock;
- u16 xfer_mode_shadow;
-};
-
-#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
-/*
- * These accessors are designed for big endian hosts doing I/O to
- * little endian controllers incorporating a 32-bit hardware byte swapper.
- */
-static inline u32 sdhci_be32bs_readl(struct sdhci_host *host, int reg)
-{
- return in_be32(host->ioaddr + reg);
-}
-
-static inline u16 sdhci_be32bs_readw(struct sdhci_host *host, int reg)
-{
- return in_be16(host->ioaddr + (reg ^ 0x2));
-}
-
-static inline u8 sdhci_be32bs_readb(struct sdhci_host *host, int reg)
-{
- return in_8(host->ioaddr + (reg ^ 0x3));
-}
-
-static inline void sdhci_be32bs_writel(struct sdhci_host *host,
- u32 val, int reg)
-{
- out_be32(host->ioaddr + reg, val);
-}
-
-static inline void sdhci_be32bs_writew(struct sdhci_host *host,
- u16 val, int reg)
-{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- int base = reg & ~0x3;
- int shift = (reg & 0x2) * 8;
-
- switch (reg) {
- case SDHCI_TRANSFER_MODE:
- /*
- * Postpone this write, we must do it together with a
- * command write that is down below.
- */
- pltfm_host->xfer_mode_shadow = val;
- return;
- case SDHCI_COMMAND:
- sdhci_be32bs_writel(host,
- val << 16 | pltfm_host->xfer_mode_shadow,
- SDHCI_TRANSFER_MODE);
- return;
- }
- clrsetbits_be32(host->ioaddr + base, 0xffff << shift, val << shift);
-}
-
-static inline void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
-{
- int base = reg & ~0x3;
- int shift = (reg & 0x3) * 8;
-
- clrsetbits_be32(host->ioaddr + base , 0xff << shift, val << shift);
-}
-#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */
-
-extern void sdhci_get_of_property(struct platform_device *pdev);
-
-extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
- struct sdhci_pltfm_data *pdata);
-extern void sdhci_pltfm_free(struct platform_device *pdev);
-
-extern int sdhci_pltfm_register(struct platform_device *pdev,
- struct sdhci_pltfm_data *pdata);
-extern int sdhci_pltfm_unregister(struct platform_device *pdev);
-
-#ifdef CONFIG_PM
-extern const struct dev_pm_ops sdhci_pltfm_pmops;
-#define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops)
-#else
-#define SDHCI_PLTFM_PMOPS NULL
-#endif
-
-#endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pxav2.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-pxav2.c
deleted file mode 100644
index dbb75bfb..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pxav2.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (C) 2010 Marvell International Ltd.
- * Zhangfei Gao <zhangfei.gao@marvell.com>
- * Kevin Wang <dwang4@marvell.com>
- * Jun Nie <njun@marvell.com>
- * Qiming Wu <wuqm@marvell.com>
- * Philip Rakity <prakity@marvell.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-#include <linux/platform_data/pxa_sdhci.h>
-#include <linux/slab.h>
-#include "sdhci.h"
-#include "sdhci-pltfm.h"
-
-#define SD_FIFO_PARAM 0xe0
-#define DIS_PAD_SD_CLK_GATE 0x0400 /* Turn on/off Dynamic SD Clock Gating */
-#define CLK_GATE_ON 0x0200 /* Disable/enable Clock Gate */
-#define CLK_GATE_CTL 0x0100 /* Clock Gate Control */
-#define CLK_GATE_SETTING_BITS (DIS_PAD_SD_CLK_GATE | \
- CLK_GATE_ON | CLK_GATE_CTL)
-
-#define SD_CLOCK_BURST_SIZE_SETUP 0xe6
-#define SDCLK_SEL_SHIFT 8
-#define SDCLK_SEL_MASK 0x3
-#define SDCLK_DELAY_SHIFT 10
-#define SDCLK_DELAY_MASK 0x3c
-
-#define SD_CE_ATA_2 0xea
-#define MMC_CARD 0x1000
-#define MMC_WIDTH 0x0100
-
-static void pxav2_set_private_registers(struct sdhci_host *host, u8 mask)
-{
- struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
- struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
-
- if (mask == SDHCI_RESET_ALL) {
- u16 tmp = 0;
-
- /*
- * tune timing of read data/command when crc error happen
- * no performance impact
- */
- if (pdata && pdata->clk_delay_sel == 1) {
- tmp = readw(host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP);
-
- tmp &= ~(SDCLK_DELAY_MASK << SDCLK_DELAY_SHIFT);
- tmp |= (pdata->clk_delay_cycles & SDCLK_DELAY_MASK)
- << SDCLK_DELAY_SHIFT;
- tmp &= ~(SDCLK_SEL_MASK << SDCLK_SEL_SHIFT);
- tmp |= (1 & SDCLK_SEL_MASK) << SDCLK_SEL_SHIFT;
-
- writew(tmp, host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP);
- }
-
- if (pdata && (pdata->flags & PXA_FLAG_ENABLE_CLOCK_GATING)) {
- tmp = readw(host->ioaddr + SD_FIFO_PARAM);
- tmp &= ~CLK_GATE_SETTING_BITS;
- writew(tmp, host->ioaddr + SD_FIFO_PARAM);
- } else {
- tmp = readw(host->ioaddr + SD_FIFO_PARAM);
- tmp &= ~CLK_GATE_SETTING_BITS;
- tmp |= CLK_GATE_SETTING_BITS;
- writew(tmp, host->ioaddr + SD_FIFO_PARAM);
- }
- }
-}
-
-static int pxav2_mmc_set_width(struct sdhci_host *host, int width)
-{
- u8 ctrl;
- u16 tmp;
-
- ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
- tmp = readw(host->ioaddr + SD_CE_ATA_2);
- if (width == MMC_BUS_WIDTH_8) {
- ctrl &= ~SDHCI_CTRL_4BITBUS;
- tmp |= MMC_CARD | MMC_WIDTH;
- } else {
- tmp &= ~(MMC_CARD | MMC_WIDTH);
- if (width == MMC_BUS_WIDTH_4)
- ctrl |= SDHCI_CTRL_4BITBUS;
- else
- ctrl &= ~SDHCI_CTRL_4BITBUS;
- }
- writew(tmp, host->ioaddr + SD_CE_ATA_2);
- writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
-
- return 0;
-}
-
-static u32 pxav2_get_max_clock(struct sdhci_host *host)
-{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-
- return clk_get_rate(pltfm_host->clk);
-}
-
-static struct sdhci_ops pxav2_sdhci_ops = {
- .get_max_clock = pxav2_get_max_clock,
- .platform_reset_exit = pxav2_set_private_registers,
- .platform_8bit_width = pxav2_mmc_set_width,
-};
-
-static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
-{
- struct sdhci_pltfm_host *pltfm_host;
- struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
- struct device *dev = &pdev->dev;
- struct sdhci_host *host = NULL;
- struct sdhci_pxa *pxa = NULL;
- int ret;
- struct clk *clk;
-
- pxa = kzalloc(sizeof(struct sdhci_pxa), GFP_KERNEL);
- if (!pxa)
- return -ENOMEM;
-
- host = sdhci_pltfm_init(pdev, NULL);
- if (IS_ERR(host)) {
- kfree(pxa);
- return PTR_ERR(host);
- }
- pltfm_host = sdhci_priv(host);
- pltfm_host->priv = pxa;
-
- clk = clk_get(dev, "PXA-SDHCLK");
- if (IS_ERR(clk)) {
- dev_err(dev, "failed to get io clock\n");
- ret = PTR_ERR(clk);
- goto err_clk_get;
- }
- pltfm_host->clk = clk;
- clk_enable(clk);
-
- host->quirks = SDHCI_QUIRK_BROKEN_ADMA
- | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
- | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
-
- if (pdata) {
- if (pdata->flags & PXA_FLAG_CARD_PERMANENT) {
- /* on-chip device */
- host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
- host->mmc->caps |= MMC_CAP_NONREMOVABLE;
- }
-
- /* If slot design supports 8 bit data, indicate this to MMC. */
- if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT)
- host->mmc->caps |= MMC_CAP_8_BIT_DATA;
-
- if (pdata->quirks)
- host->quirks |= pdata->quirks;
- if (pdata->host_caps)
- host->mmc->caps |= pdata->host_caps;
- if (pdata->pm_caps)
- host->mmc->pm_caps |= pdata->pm_caps;
- }
-
- host->ops = &pxav2_sdhci_ops;
-
- ret = sdhci_add_host(host);
- if (ret) {
- dev_err(&pdev->dev, "failed to add host\n");
- goto err_add_host;
- }
-
- platform_set_drvdata(pdev, host);
-
- return 0;
-
-err_add_host:
- clk_disable(clk);
- clk_put(clk);
-err_clk_get:
- sdhci_pltfm_free(pdev);
- kfree(pxa);
- return ret;
-}
-
-static int __devexit sdhci_pxav2_remove(struct platform_device *pdev)
-{
- struct sdhci_host *host = platform_get_drvdata(pdev);
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct sdhci_pxa *pxa = pltfm_host->priv;
-
- sdhci_remove_host(host, 1);
-
- clk_disable(pltfm_host->clk);
- clk_put(pltfm_host->clk);
- sdhci_pltfm_free(pdev);
- kfree(pxa);
-
- platform_set_drvdata(pdev, NULL);
-
- return 0;
-}
-
-static struct platform_driver sdhci_pxav2_driver = {
- .driver = {
- .name = "sdhci-pxav2",
- .owner = THIS_MODULE,
- .pm = SDHCI_PLTFM_PMOPS,
- },
- .probe = sdhci_pxav2_probe,
- .remove = __devexit_p(sdhci_pxav2_remove),
-};
-
-module_platform_driver(sdhci_pxav2_driver);
-
-MODULE_DESCRIPTION("SDHCI driver for pxav2");
-MODULE_AUTHOR("Marvell International Ltd.");
-MODULE_LICENSE("GPL v2");
-
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pxav3.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-pxav3.c
deleted file mode 100644
index f2969568..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-pxav3.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * 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 software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-#include <linux/platform_data/pxa_sdhci.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include "sdhci.h"
-#include "sdhci-pltfm.h"
-
-#define SD_CLOCK_BURST_SIZE_SETUP 0x10A
-#define SDCLK_SEL 0x100
-#define SDCLK_DELAY_SHIFT 9
-#define SDCLK_DELAY_MASK 0x1f
-
-#define SD_CFG_FIFO_PARAM 0x100
-#define SDCFG_GEN_PAD_CLK_ON (1<<6)
-#define SDCFG_GEN_PAD_CLK_CNT_MASK 0xFF
-#define SDCFG_GEN_PAD_CLK_CNT_SHIFT 24
-
-#define SD_SPI_MODE 0x108
-#define SD_CE_ATA_1 0x10C
-
-#define SD_CE_ATA_2 0x10E
-#define SDCE_MISC_INT (1<<2)
-#define SDCE_MISC_INT_EN (1<<1)
-
-static void pxav3_set_private_registers(struct sdhci_host *host, u8 mask)
-{
- struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
- struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
-
- if (mask == SDHCI_RESET_ALL) {
- /*
- * tune timing of read data/command when crc error happen
- * no performance impact
- */
- if (pdata && 0 != pdata->clk_delay_cycles) {
- u16 tmp;
-
- tmp = readw(host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP);
- tmp |= (pdata->clk_delay_cycles & SDCLK_DELAY_MASK)
- << SDCLK_DELAY_SHIFT;
- tmp |= SDCLK_SEL;
- writew(tmp, host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP);
- }
- }
-}
-
-#define MAX_WAIT_COUNT 5
-static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode)
-{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct sdhci_pxa *pxa = pltfm_host->priv;
- u16 tmp;
- int count;
-
- if (pxa->power_mode == MMC_POWER_UP
- && power_mode == MMC_POWER_ON) {
-
- dev_dbg(mmc_dev(host->mmc),
- "%s: slot->power_mode = %d,"
- "ios->power_mode = %d\n",
- __func__,
- pxa->power_mode,
- power_mode);
-
- /* set we want notice of when 74 clocks are sent */
- tmp = readw(host->ioaddr + SD_CE_ATA_2);
- tmp |= SDCE_MISC_INT_EN;
- writew(tmp, host->ioaddr + SD_CE_ATA_2);
-
- /* start sending the 74 clocks */
- tmp = readw(host->ioaddr + SD_CFG_FIFO_PARAM);
- tmp |= SDCFG_GEN_PAD_CLK_ON;
- writew(tmp, host->ioaddr + SD_CFG_FIFO_PARAM);
-
- /* slowest speed is about 100KHz or 10usec per clock */
- udelay(740);
- count = 0;
-
- while (count++ < MAX_WAIT_COUNT) {
- if ((readw(host->ioaddr + SD_CE_ATA_2)
- & SDCE_MISC_INT) == 0)
- break;
- udelay(10);
- }
-
- if (count == MAX_WAIT_COUNT)
- dev_warn(mmc_dev(host->mmc), "74 clock interrupt not cleared\n");
-
- /* clear the interrupt bit if posted */
- tmp = readw(host->ioaddr + SD_CE_ATA_2);
- tmp |= SDCE_MISC_INT;
- writew(tmp, host->ioaddr + SD_CE_ATA_2);
- }
- pxa->power_mode = power_mode;
-}
-
-static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
-{
- u16 ctrl_2;
-
- /*
- * Set V18_EN -- UHS modes do not work without this.
- * does not change signaling voltage
- */
- ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-
- /* Select Bus Speed Mode for host */
- ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
- switch (uhs) {
- case MMC_TIMING_UHS_SDR12:
- ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
- break;
- case MMC_TIMING_UHS_SDR25:
- ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
- break;
- case MMC_TIMING_UHS_SDR50:
- ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180;
- break;
- case MMC_TIMING_UHS_SDR104:
- ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180;
- break;
- case MMC_TIMING_UHS_DDR50:
- ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180;
- break;
- }
-
- sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
- dev_dbg(mmc_dev(host->mmc),
- "%s uhs = %d, ctrl_2 = %04X\n",
- __func__, uhs, ctrl_2);
-
- return 0;
-}
-
-static struct sdhci_ops pxav3_sdhci_ops = {
- .platform_reset_exit = pxav3_set_private_registers,
- .set_uhs_signaling = pxav3_set_uhs_signaling,
- .platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
-};
-
-static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
-{
- struct sdhci_pltfm_host *pltfm_host;
- struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
- struct device *dev = &pdev->dev;
- struct sdhci_host *host = NULL;
- struct sdhci_pxa *pxa = NULL;
- int ret;
- struct clk *clk;
-
- pxa = kzalloc(sizeof(struct sdhci_pxa), GFP_KERNEL);
- if (!pxa)
- return -ENOMEM;
-
- host = sdhci_pltfm_init(pdev, NULL);
- if (IS_ERR(host)) {
- kfree(pxa);
- return PTR_ERR(host);
- }
- pltfm_host = sdhci_priv(host);
- pltfm_host->priv = pxa;
-
- clk = clk_get(dev, "PXA-SDHCLK");
- if (IS_ERR(clk)) {
- dev_err(dev, "failed to get io clock\n");
- ret = PTR_ERR(clk);
- goto err_clk_get;
- }
- pltfm_host->clk = clk;
- clk_enable(clk);
-
- host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
- | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
- | SDHCI_QUIRK_32BIT_ADMA_SIZE;
-
- /* enable 1/8V DDR capable */
- host->mmc->caps |= MMC_CAP_1_8V_DDR;
-
- if (pdata) {
- if (pdata->flags & PXA_FLAG_CARD_PERMANENT) {
- /* on-chip device */
- host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
- host->mmc->caps |= MMC_CAP_NONREMOVABLE;
- }
-
- /* If slot design supports 8 bit data, indicate this to MMC. */
- if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT)
- host->mmc->caps |= MMC_CAP_8_BIT_DATA;
-
- if (pdata->quirks)
- host->quirks |= pdata->quirks;
- if (pdata->host_caps)
- host->mmc->caps |= pdata->host_caps;
- if (pdata->pm_caps)
- host->mmc->pm_caps |= pdata->pm_caps;
- }
-
- host->ops = &pxav3_sdhci_ops;
-
- ret = sdhci_add_host(host);
- if (ret) {
- dev_err(&pdev->dev, "failed to add host\n");
- goto err_add_host;
- }
-
- platform_set_drvdata(pdev, host);
-
- return 0;
-
-err_add_host:
- clk_disable(clk);
- clk_put(clk);
-err_clk_get:
- sdhci_pltfm_free(pdev);
- kfree(pxa);
- return ret;
-}
-
-static int __devexit sdhci_pxav3_remove(struct platform_device *pdev)
-{
- struct sdhci_host *host = platform_get_drvdata(pdev);
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct sdhci_pxa *pxa = pltfm_host->priv;
-
- sdhci_remove_host(host, 1);
-
- clk_disable(pltfm_host->clk);
- clk_put(pltfm_host->clk);
- sdhci_pltfm_free(pdev);
- kfree(pxa);
-
- platform_set_drvdata(pdev, NULL);
-
- return 0;
-}
-
-static struct platform_driver sdhci_pxav3_driver = {
- .driver = {
- .name = "sdhci-pxav3",
- .owner = THIS_MODULE,
- .pm = SDHCI_PLTFM_PMOPS,
- },
- .probe = sdhci_pxav3_probe,
- .remove = __devexit_p(sdhci_pxav3_remove),
-};
-
-module_platform_driver(sdhci_pxav3_driver);
-
-MODULE_DESCRIPTION("SDHCI driver for pxav3");
-MODULE_AUTHOR("Marvell International Ltd.");
-MODULE_LICENSE("GPL v2");
-
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-s3c.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-s3c.c
deleted file mode 100644
index 55a164fc..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-s3c.c
+++ /dev/null
@@ -1,756 +0,0 @@
-/* linux/drivers/mmc/host/sdhci-s3c.c
- *
- * Copyright 2008 Openmoko Inc.
- * Copyright 2008 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
- * http://armlinux.simtec.co.uk/
- *
- * SDHCI (HSMMC) support for Samsung SoC
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/pm.h>
-#include <linux/pm_runtime.h>
-
-#include <linux/mmc/host.h>
-
-#include <plat/sdhci.h>
-#include <plat/regs-sdhci.h>
-
-#include "sdhci.h"
-
-#define MAX_BUS_CLK (4)
-
-/**
- * struct sdhci_s3c - S3C SDHCI instance
- * @host: The SDHCI host created
- * @pdev: The platform device we where created from.
- * @ioarea: The resource created when we claimed the IO area.
- * @pdata: The platform data for this controller.
- * @cur_clk: The index of the current bus clock.
- * @clk_io: The clock for the internal bus interface.
- * @clk_bus: The clocks that are available for the SD/MMC bus clock.
- */
-struct sdhci_s3c {
- struct sdhci_host *host;
- struct platform_device *pdev;
- struct resource *ioarea;
- struct s3c_sdhci_platdata *pdata;
- unsigned int cur_clk;
- int ext_cd_irq;
- int ext_cd_gpio;
-
- struct clk *clk_io;
- struct clk *clk_bus[MAX_BUS_CLK];
-};
-
-/**
- * struct sdhci_s3c_driver_data - S3C SDHCI platform specific driver data
- * @sdhci_quirks: sdhci host specific quirks.
- *
- * Specifies platform specific configuration of sdhci controller.
- * Note: A structure for driver specific platform data is used for future
- * expansion of its usage.
- */
-struct sdhci_s3c_drv_data {
- unsigned int sdhci_quirks;
-};
-
-static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host)
-{
- return sdhci_priv(host);
-}
-
-/**
- * get_curclk - convert ctrl2 register to clock source number
- * @ctrl2: Control2 register value.
- */
-static u32 get_curclk(u32 ctrl2)
-{
- ctrl2 &= S3C_SDHCI_CTRL2_SELBASECLK_MASK;
- ctrl2 >>= S3C_SDHCI_CTRL2_SELBASECLK_SHIFT;
-
- return ctrl2;
-}
-
-static void sdhci_s3c_check_sclk(struct sdhci_host *host)
-{
- struct sdhci_s3c *ourhost = to_s3c(host);
- u32 tmp = readl(host->ioaddr + S3C_SDHCI_CONTROL2);
-
- if (get_curclk(tmp) != ourhost->cur_clk) {
- dev_dbg(&ourhost->pdev->dev, "restored ctrl2 clock setting\n");
-
- tmp &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK;
- tmp |= ourhost->cur_clk << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT;
- writel(tmp, host->ioaddr + S3C_SDHCI_CONTROL2);
- }
-}
-
-/**
- * sdhci_s3c_get_max_clk - callback to get maximum clock frequency.
- * @host: The SDHCI host instance.
- *
- * Callback to return the maximum clock rate acheivable by the controller.
-*/
-static unsigned int sdhci_s3c_get_max_clk(struct sdhci_host *host)
-{
- struct sdhci_s3c *ourhost = to_s3c(host);
- struct clk *busclk;
- unsigned int rate, max;
- int clk;
-
- /* note, a reset will reset the clock source */
-
- sdhci_s3c_check_sclk(host);
-
- for (max = 0, clk = 0; clk < MAX_BUS_CLK; clk++) {
- busclk = ourhost->clk_bus[clk];
- if (!busclk)
- continue;
-
- rate = clk_get_rate(busclk);
- if (rate > max)
- max = rate;
- }
-
- return max;
-}
-
-/**
- * sdhci_s3c_consider_clock - consider one the bus clocks for current setting
- * @ourhost: Our SDHCI instance.
- * @src: The source clock index.
- * @wanted: The clock frequency wanted.
- */
-static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,
- unsigned int src,
- unsigned int wanted)
-{
- unsigned long rate;
- struct clk *clksrc = ourhost->clk_bus[src];
- int div;
-
- if (!clksrc)
- return UINT_MAX;
-
- /*
- * If controller uses a non-standard clock division, find the best clock
- * speed possible with selected clock source and skip the division.
- */
- if (ourhost->host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) {
- rate = clk_round_rate(clksrc, wanted);
- return wanted - rate;
- }
-
- rate = clk_get_rate(clksrc);
-
- for (div = 1; div < 256; div *= 2) {
- if ((rate / div) <= wanted)
- break;
- }
-
- dev_dbg(&ourhost->pdev->dev, "clk %d: rate %ld, want %d, got %ld\n",
- src, rate, wanted, rate / div);
-
- return (wanted - (rate / div));
-}
-
-/**
- * sdhci_s3c_set_clock - callback on clock change
- * @host: The SDHCI host being changed
- * @clock: The clock rate being requested.
- *
- * When the card's clock is going to be changed, look at the new frequency
- * and find the best clock source to go with it.
-*/
-static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)
-{
- struct sdhci_s3c *ourhost = to_s3c(host);
- unsigned int best = UINT_MAX;
- unsigned int delta;
- int best_src = 0;
- int src;
- u32 ctrl;
-
- /* don't bother if the clock is going off. */
- if (clock == 0)
- return;
-
- for (src = 0; src < MAX_BUS_CLK; src++) {
- delta = sdhci_s3c_consider_clock(ourhost, src, clock);
- if (delta < best) {
- best = delta;
- best_src = src;
- }
- }
-
- dev_dbg(&ourhost->pdev->dev,
- "selected source %d, clock %d, delta %d\n",
- best_src, clock, best);
-
- /* select the new clock source */
-
- if (ourhost->cur_clk != best_src) {
- struct clk *clk = ourhost->clk_bus[best_src];
-
- /* turn clock off to card before changing clock source */
- writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
-
- ourhost->cur_clk = best_src;
- host->max_clk = clk_get_rate(clk);
-
- ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2);
- ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK;
- ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT;
- writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2);
- }
-
- /* reprogram default hardware configuration */
- writel(S3C64XX_SDHCI_CONTROL4_DRIVE_9mA,
- host->ioaddr + S3C64XX_SDHCI_CONTROL4);
-
- ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2);
- ctrl |= (S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR |
- S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK |
- S3C_SDHCI_CTRL2_ENFBCLKRX |
- S3C_SDHCI_CTRL2_DFCNT_NONE |
- S3C_SDHCI_CTRL2_ENCLKOUTHOLD);
- writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2);
-
- /* reconfigure the controller for new clock rate */
- ctrl = (S3C_SDHCI_CTRL3_FCSEL1 | S3C_SDHCI_CTRL3_FCSEL0);
- if (clock < 25 * 1000000)
- ctrl |= (S3C_SDHCI_CTRL3_FCSEL3 | S3C_SDHCI_CTRL3_FCSEL2);
- writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL3);
-}
-
-/**
- * sdhci_s3c_get_min_clock - callback to get minimal supported clock value
- * @host: The SDHCI host being queried
- *
- * To init mmc host properly a minimal clock value is needed. For high system
- * bus clock's values the standard formula gives values out of allowed range.
- * The clock still can be set to lower values, if clock source other then
- * system bus is selected.
-*/
-static unsigned int sdhci_s3c_get_min_clock(struct sdhci_host *host)
-{
- struct sdhci_s3c *ourhost = to_s3c(host);
- unsigned int delta, min = UINT_MAX;
- int src;
-
- for (src = 0; src < MAX_BUS_CLK; src++) {
- delta = sdhci_s3c_consider_clock(ourhost, src, 0);
- if (delta == UINT_MAX)
- continue;
- /* delta is a negative value in this case */
- if (-delta < min)
- min = -delta;
- }
- return min;
-}
-
-/* sdhci_cmu_get_max_clk - callback to get maximum clock frequency.*/
-static unsigned int sdhci_cmu_get_max_clock(struct sdhci_host *host)
-{
- struct sdhci_s3c *ourhost = to_s3c(host);
-
- return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], UINT_MAX);
-}
-
-/* sdhci_cmu_get_min_clock - callback to get minimal supported clock value. */
-static unsigned int sdhci_cmu_get_min_clock(struct sdhci_host *host)
-{
- struct sdhci_s3c *ourhost = to_s3c(host);
-
- /*
- * initial clock can be in the frequency range of
- * 100KHz-400KHz, so we set it as max value.
- */
- return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], 400000);
-}
-
-/* sdhci_cmu_set_clock - callback on clock change.*/
-static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
-{
- struct sdhci_s3c *ourhost = to_s3c(host);
- unsigned long timeout;
- u16 clk = 0;
-
- /* don't bother if the clock is going off */
- if (clock == 0)
- return;
-
- sdhci_s3c_set_clock(host, clock);
-
- clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock);
-
- host->clock = clock;
-
- clk = SDHCI_CLOCK_INT_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
- /* Wait max 20 ms */
- timeout = 20;
- while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
- & SDHCI_CLOCK_INT_STABLE)) {
- if (timeout == 0) {
- printk(KERN_ERR "%s: Internal clock never "
- "stabilised.\n", mmc_hostname(host->mmc));
- return;
- }
- timeout--;
- mdelay(1);
- }
-
- clk |= SDHCI_CLOCK_CARD_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-}
-
-/**
- * sdhci_s3c_platform_8bit_width - support 8bit buswidth
- * @host: The SDHCI host being queried
- * @width: MMC_BUS_WIDTH_ macro for the bus width being requested
- *
- * We have 8-bit width support but is not a v3 controller.
- * So we add platform_8bit_width() and support 8bit width.
- */
-static int sdhci_s3c_platform_8bit_width(struct sdhci_host *host, int width)
-{
- u8 ctrl;
-
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
-
- switch (width) {
- case MMC_BUS_WIDTH_8:
- ctrl |= SDHCI_CTRL_8BITBUS;
- ctrl &= ~SDHCI_CTRL_4BITBUS;
- break;
- case MMC_BUS_WIDTH_4:
- ctrl |= SDHCI_CTRL_4BITBUS;
- ctrl &= ~SDHCI_CTRL_8BITBUS;
- break;
- default:
- ctrl &= ~SDHCI_CTRL_4BITBUS;
- ctrl &= ~SDHCI_CTRL_8BITBUS;
- break;
- }
-
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-
- return 0;
-}
-
-static struct sdhci_ops sdhci_s3c_ops = {
- .get_max_clock = sdhci_s3c_get_max_clk,
- .set_clock = sdhci_s3c_set_clock,
- .get_min_clock = sdhci_s3c_get_min_clock,
- .platform_8bit_width = sdhci_s3c_platform_8bit_width,
-};
-
-static void sdhci_s3c_notify_change(struct platform_device *dev, int state)
-{
- struct sdhci_host *host = platform_get_drvdata(dev);
- unsigned long flags;
-
- if (host) {
- spin_lock_irqsave(&host->lock, flags);
- if (state) {
- dev_dbg(&dev->dev, "card inserted.\n");
- host->flags &= ~SDHCI_DEVICE_DEAD;
- host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
- } else {
- dev_dbg(&dev->dev, "card removed.\n");
- host->flags |= SDHCI_DEVICE_DEAD;
- host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
- }
- tasklet_schedule(&host->card_tasklet);
- spin_unlock_irqrestore(&host->lock, flags);
- }
-}
-
-static irqreturn_t sdhci_s3c_gpio_card_detect_thread(int irq, void *dev_id)
-{
- struct sdhci_s3c *sc = dev_id;
- int status = gpio_get_value(sc->ext_cd_gpio);
- if (sc->pdata->ext_cd_gpio_invert)
- status = !status;
- sdhci_s3c_notify_change(sc->pdev, status);
- return IRQ_HANDLED;
-}
-
-static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc)
-{
- struct s3c_sdhci_platdata *pdata = sc->pdata;
- struct device *dev = &sc->pdev->dev;
-
- if (gpio_request(pdata->ext_cd_gpio, "SDHCI EXT CD") == 0) {
- sc->ext_cd_gpio = pdata->ext_cd_gpio;
- sc->ext_cd_irq = gpio_to_irq(pdata->ext_cd_gpio);
- if (sc->ext_cd_irq &&
- request_threaded_irq(sc->ext_cd_irq, NULL,
- sdhci_s3c_gpio_card_detect_thread,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- dev_name(dev), sc) == 0) {
- int status = gpio_get_value(sc->ext_cd_gpio);
- if (pdata->ext_cd_gpio_invert)
- status = !status;
- sdhci_s3c_notify_change(sc->pdev, status);
- } else {
- dev_warn(dev, "cannot request irq for card detect\n");
- sc->ext_cd_irq = 0;
- }
- } else {
- dev_err(dev, "cannot request gpio for card detect\n");
- }
-}
-
-static inline struct sdhci_s3c_drv_data *sdhci_s3c_get_driver_data(
- struct platform_device *pdev)
-{
- return (struct sdhci_s3c_drv_data *)
- platform_get_device_id(pdev)->driver_data;
-}
-
-static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
-{
- struct s3c_sdhci_platdata *pdata;
- struct sdhci_s3c_drv_data *drv_data;
- struct device *dev = &pdev->dev;
- struct sdhci_host *host;
- struct sdhci_s3c *sc;
- struct resource *res;
- int ret, irq, ptr, clks;
-
- if (!pdev->dev.platform_data) {
- dev_err(dev, "no device data specified\n");
- return -ENOENT;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(dev, "no irq specified\n");
- return irq;
- }
-
- host = sdhci_alloc_host(dev, sizeof(struct sdhci_s3c));
- if (IS_ERR(host)) {
- dev_err(dev, "sdhci_alloc_host() failed\n");
- return PTR_ERR(host);
- }
-
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- ret = -ENOMEM;
- goto err_io_clk;
- }
- memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));
-
- drv_data = sdhci_s3c_get_driver_data(pdev);
- sc = sdhci_priv(host);
-
- sc->host = host;
- sc->pdev = pdev;
- sc->pdata = pdata;
- sc->ext_cd_gpio = -1; /* invalid gpio number */
-
- platform_set_drvdata(pdev, host);
-
- sc->clk_io = clk_get(dev, "hsmmc");
- if (IS_ERR(sc->clk_io)) {
- dev_err(dev, "failed to get io clock\n");
- ret = PTR_ERR(sc->clk_io);
- goto err_io_clk;
- }
-
- /* enable the local io clock and keep it running for the moment. */
- clk_enable(sc->clk_io);
-
- for (clks = 0, ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
- struct clk *clk;
- char name[14];
-
- snprintf(name, 14, "mmc_busclk.%d", ptr);
- clk = clk_get(dev, name);
- if (IS_ERR(clk)) {
- continue;
- }
-
- clks++;
- sc->clk_bus[ptr] = clk;
-
- /*
- * save current clock index to know which clock bus
- * is used later in overriding functions.
- */
- sc->cur_clk = ptr;
-
- clk_enable(clk);
-
- dev_info(dev, "clock source %d: %s (%ld Hz)\n",
- ptr, name, clk_get_rate(clk));
- }
-
- if (clks == 0) {
- dev_err(dev, "failed to find any bus clocks\n");
- ret = -ENOENT;
- goto err_no_busclks;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- host->ioaddr = devm_request_and_ioremap(&pdev->dev, res);
- if (!host->ioaddr) {
- dev_err(dev, "failed to map registers\n");
- ret = -ENXIO;
- goto err_req_regs;
- }
-
- /* Ensure we have minimal gpio selected CMD/CLK/Detect */
- if (pdata->cfg_gpio)
- pdata->cfg_gpio(pdev, pdata->max_width);
-
- host->hw_name = "samsung-hsmmc";
- host->ops = &sdhci_s3c_ops;
- host->quirks = 0;
- host->irq = irq;
-
- /* Setup quirks for the controller */
- host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC;
- host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT;
- if (drv_data)
- host->quirks |= drv_data->sdhci_quirks;
-
-#ifndef CONFIG_MMC_SDHCI_S3C_DMA
-
- /* we currently see overruns on errors, so disable the SDMA
- * support as well. */
- host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
-
-#endif /* CONFIG_MMC_SDHCI_S3C_DMA */
-
- /* It seems we do not get an DATA transfer complete on non-busy
- * transfers, not sure if this is a problem with this specific
- * SDHCI block, or a missing configuration that needs to be set. */
- host->quirks |= SDHCI_QUIRK_NO_BUSY_IRQ;
-
- /* This host supports the Auto CMD12 */
- host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
-
- /* Samsung SoCs need BROKEN_ADMA_ZEROLEN_DESC */
- host->quirks |= SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC;
-
- if (pdata->cd_type == S3C_SDHCI_CD_NONE ||
- pdata->cd_type == S3C_SDHCI_CD_PERMANENT)
- host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
-
- if (pdata->cd_type == S3C_SDHCI_CD_PERMANENT)
- host->mmc->caps = MMC_CAP_NONREMOVABLE;
-
- switch (pdata->max_width) {
- case 8:
- host->mmc->caps |= MMC_CAP_8_BIT_DATA;
- case 4:
- host->mmc->caps |= MMC_CAP_4_BIT_DATA;
- break;
- }
-
- if (pdata->pm_caps)
- host->mmc->pm_caps |= pdata->pm_caps;
-
- host->quirks |= (SDHCI_QUIRK_32BIT_DMA_ADDR |
- SDHCI_QUIRK_32BIT_DMA_SIZE);
-
- /* HSMMC on Samsung SoCs uses SDCLK as timeout clock */
- host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK;
-
- /*
- * If controller does not have internal clock divider,
- * we can use overriding functions instead of default.
- */
- if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) {
- sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock;
- sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock;
- sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock;
- }
-
- /* It supports additional host capabilities if needed */
- if (pdata->host_caps)
- host->mmc->caps |= pdata->host_caps;
-
- if (pdata->host_caps2)
- host->mmc->caps2 |= pdata->host_caps2;
-
- pm_runtime_enable(&pdev->dev);
- pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
- pm_runtime_use_autosuspend(&pdev->dev);
- pm_suspend_ignore_children(&pdev->dev, 1);
-
- ret = sdhci_add_host(host);
- if (ret) {
- dev_err(dev, "sdhci_add_host() failed\n");
- pm_runtime_forbid(&pdev->dev);
- pm_runtime_get_noresume(&pdev->dev);
- goto err_req_regs;
- }
-
- /* The following two methods of card detection might call
- sdhci_s3c_notify_change() immediately, so they can be called
- only after sdhci_add_host(). Setup errors are ignored. */
- if (pdata->cd_type == S3C_SDHCI_CD_EXTERNAL && pdata->ext_cd_init)
- pdata->ext_cd_init(&sdhci_s3c_notify_change);
- if (pdata->cd_type == S3C_SDHCI_CD_GPIO &&
- gpio_is_valid(pdata->ext_cd_gpio))
- sdhci_s3c_setup_card_detect_gpio(sc);
-
- return 0;
-
- err_req_regs:
- for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
- if (sc->clk_bus[ptr]) {
- clk_disable(sc->clk_bus[ptr]);
- clk_put(sc->clk_bus[ptr]);
- }
- }
-
- err_no_busclks:
- clk_disable(sc->clk_io);
- clk_put(sc->clk_io);
-
- err_io_clk:
- sdhci_free_host(host);
-
- return ret;
-}
-
-static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
-{
- struct s3c_sdhci_platdata *pdata = pdev->dev.platform_data;
- struct sdhci_host *host = platform_get_drvdata(pdev);
- struct sdhci_s3c *sc = sdhci_priv(host);
- int ptr;
-
- if (pdata->cd_type == S3C_SDHCI_CD_EXTERNAL && pdata->ext_cd_cleanup)
- pdata->ext_cd_cleanup(&sdhci_s3c_notify_change);
-
- if (sc->ext_cd_irq)
- free_irq(sc->ext_cd_irq, sc);
-
- if (gpio_is_valid(sc->ext_cd_gpio))
- gpio_free(sc->ext_cd_gpio);
-
- sdhci_remove_host(host, 1);
-
- pm_runtime_disable(&pdev->dev);
-
- for (ptr = 0; ptr < 3; ptr++) {
- if (sc->clk_bus[ptr]) {
- clk_disable(sc->clk_bus[ptr]);
- clk_put(sc->clk_bus[ptr]);
- }
- }
- clk_disable(sc->clk_io);
- clk_put(sc->clk_io);
-
- sdhci_free_host(host);
- platform_set_drvdata(pdev, NULL);
-
- return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int sdhci_s3c_suspend(struct device *dev)
-{
- struct sdhci_host *host = dev_get_drvdata(dev);
-
- return sdhci_suspend_host(host);
-}
-
-static int sdhci_s3c_resume(struct device *dev)
-{
- struct sdhci_host *host = dev_get_drvdata(dev);
-
- return sdhci_resume_host(host);
-}
-#endif
-
-#ifdef CONFIG_PM_RUNTIME
-static int sdhci_s3c_runtime_suspend(struct device *dev)
-{
- struct sdhci_host *host = dev_get_drvdata(dev);
-
- return sdhci_runtime_suspend_host(host);
-}
-
-static int sdhci_s3c_runtime_resume(struct device *dev)
-{
- struct sdhci_host *host = dev_get_drvdata(dev);
-
- return sdhci_runtime_resume_host(host);
-}
-#endif
-
-#ifdef CONFIG_PM
-static const struct dev_pm_ops sdhci_s3c_pmops = {
- SET_SYSTEM_SLEEP_PM_OPS(sdhci_s3c_suspend, sdhci_s3c_resume)
- SET_RUNTIME_PM_OPS(sdhci_s3c_runtime_suspend, sdhci_s3c_runtime_resume,
- NULL)
-};
-
-#define SDHCI_S3C_PMOPS (&sdhci_s3c_pmops)
-
-#else
-#define SDHCI_S3C_PMOPS NULL
-#endif
-
-#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212)
-static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = {
- .sdhci_quirks = SDHCI_QUIRK_NONSTANDARD_CLOCK,
-};
-#define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)&exynos4_sdhci_drv_data)
-#else
-#define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)NULL)
-#endif
-
-static struct platform_device_id sdhci_s3c_driver_ids[] = {
- {
- .name = "s3c-sdhci",
- .driver_data = (kernel_ulong_t)NULL,
- }, {
- .name = "exynos4-sdhci",
- .driver_data = EXYNOS4_SDHCI_DRV_DATA,
- },
- { }
-};
-MODULE_DEVICE_TABLE(platform, sdhci_s3c_driver_ids);
-
-static struct platform_driver sdhci_s3c_driver = {
- .probe = sdhci_s3c_probe,
- .remove = __devexit_p(sdhci_s3c_remove),
- .id_table = sdhci_s3c_driver_ids,
- .driver = {
- .owner = THIS_MODULE,
- .name = "s3c-sdhci",
- .pm = SDHCI_S3C_PMOPS,
- },
-};
-
-module_platform_driver(sdhci_s3c_driver);
-
-MODULE_DESCRIPTION("Samsung SDHCI (HSMMC) glue");
-MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:s3c-sdhci");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-spear.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-spear.c
deleted file mode 100644
index 6dfa82e0..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-spear.c
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * drivers/mmc/host/sdhci-spear.c
- *
- * Support of SDHCI platform devices for spear soc family
- *
- * Copyright (C) 2010 ST Microelectronics
- * Viresh Kumar<viresh.kumar@st.com>
- *
- * Inspired by sdhci-pltfm.c
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/clk.h>
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/highmem.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/platform_device.h>
-#include <linux/pm.h>
-#include <linux/slab.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/sdhci-spear.h>
-#include <linux/io.h>
-#include "sdhci.h"
-
-struct spear_sdhci {
- struct clk *clk;
- struct sdhci_plat_data *data;
-};
-
-/* sdhci ops */
-static struct sdhci_ops sdhci_pltfm_ops = {
- /* Nothing to do for now. */
-};
-
-/* gpio card detection interrupt handler */
-static irqreturn_t sdhci_gpio_irq(int irq, void *dev_id)
-{
- struct platform_device *pdev = dev_id;
- struct sdhci_host *host = platform_get_drvdata(pdev);
- struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev);
- unsigned long gpio_irq_type;
- int val;
-
- val = gpio_get_value(sdhci->data->card_int_gpio);
-
- /* val == 1 -> card removed, val == 0 -> card inserted */
- /* if card removed - set irq for low level, else vice versa */
- gpio_irq_type = val ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH;
- irq_set_irq_type(irq, gpio_irq_type);
-
- if (sdhci->data->card_power_gpio >= 0) {
- if (!sdhci->data->power_always_enb) {
- /* if card inserted, give power, otherwise remove it */
- val = sdhci->data->power_active_high ? !val : val ;
- gpio_set_value(sdhci->data->card_power_gpio, val);
- }
- }
-
- /* inform sdhci driver about card insertion/removal */
- tasklet_schedule(&host->card_tasklet);
-
- return IRQ_HANDLED;
-}
-
-static int __devinit sdhci_probe(struct platform_device *pdev)
-{
- struct sdhci_host *host;
- struct resource *iomem;
- struct spear_sdhci *sdhci;
- int ret;
-
- BUG_ON(pdev == NULL);
-
- iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!iomem) {
- ret = -ENOMEM;
- dev_dbg(&pdev->dev, "memory resource not defined\n");
- goto err;
- }
-
- if (!request_mem_region(iomem->start, resource_size(iomem),
- "spear-sdhci")) {
- ret = -EBUSY;
- dev_dbg(&pdev->dev, "cannot request region\n");
- goto err;
- }
-
- sdhci = kzalloc(sizeof(*sdhci), GFP_KERNEL);
- if (!sdhci) {
- ret = -ENOMEM;
- dev_dbg(&pdev->dev, "cannot allocate memory for sdhci\n");
- goto err_kzalloc;
- }
-
- /* clk enable */
- sdhci->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(sdhci->clk)) {
- ret = PTR_ERR(sdhci->clk);
- dev_dbg(&pdev->dev, "Error getting clock\n");
- goto err_clk_get;
- }
-
- ret = clk_enable(sdhci->clk);
- if (ret) {
- dev_dbg(&pdev->dev, "Error enabling clock\n");
- goto err_clk_enb;
- }
-
- /* overwrite platform_data */
- sdhci->data = dev_get_platdata(&pdev->dev);
- pdev->dev.platform_data = sdhci;
-
- if (pdev->dev.parent)
- host = sdhci_alloc_host(pdev->dev.parent, 0);
- else
- host = sdhci_alloc_host(&pdev->dev, 0);
-
- if (IS_ERR(host)) {
- ret = PTR_ERR(host);
- dev_dbg(&pdev->dev, "error allocating host\n");
- goto err_alloc_host;
- }
-
- host->hw_name = "sdhci";
- host->ops = &sdhci_pltfm_ops;
- host->irq = platform_get_irq(pdev, 0);
- host->quirks = SDHCI_QUIRK_BROKEN_ADMA;
-
- host->ioaddr = ioremap(iomem->start, resource_size(iomem));
- if (!host->ioaddr) {
- ret = -ENOMEM;
- dev_dbg(&pdev->dev, "failed to remap registers\n");
- goto err_ioremap;
- }
-
- ret = sdhci_add_host(host);
- if (ret) {
- dev_dbg(&pdev->dev, "error adding host\n");
- goto err_add_host;
- }
-
- platform_set_drvdata(pdev, host);
-
- /*
- * It is optional to use GPIOs for sdhci Power control & sdhci card
- * interrupt detection. If sdhci->data is NULL, then use original sdhci
- * lines otherwise GPIO lines.
- * If GPIO is selected for power control, then power should be disabled
- * after card removal and should be enabled when card insertion
- * interrupt occurs
- */
- if (!sdhci->data)
- return 0;
-
- if (sdhci->data->card_power_gpio >= 0) {
- int val = 0;
-
- ret = gpio_request(sdhci->data->card_power_gpio, "sdhci");
- if (ret < 0) {
- dev_dbg(&pdev->dev, "gpio request fail: %d\n",
- sdhci->data->card_power_gpio);
- goto err_pgpio_request;
- }
-
- if (sdhci->data->power_always_enb)
- val = sdhci->data->power_active_high;
- else
- val = !sdhci->data->power_active_high;
-
- ret = gpio_direction_output(sdhci->data->card_power_gpio, val);
- if (ret) {
- dev_dbg(&pdev->dev, "gpio set direction fail: %d\n",
- sdhci->data->card_power_gpio);
- goto err_pgpio_direction;
- }
- }
-
- if (sdhci->data->card_int_gpio >= 0) {
- ret = gpio_request(sdhci->data->card_int_gpio, "sdhci");
- if (ret < 0) {
- dev_dbg(&pdev->dev, "gpio request fail: %d\n",
- sdhci->data->card_int_gpio);
- goto err_igpio_request;
- }
-
- ret = gpio_direction_input(sdhci->data->card_int_gpio);
- if (ret) {
- dev_dbg(&pdev->dev, "gpio set direction fail: %d\n",
- sdhci->data->card_int_gpio);
- goto err_igpio_direction;
- }
- ret = request_irq(gpio_to_irq(sdhci->data->card_int_gpio),
- sdhci_gpio_irq, IRQF_TRIGGER_LOW,
- mmc_hostname(host->mmc), pdev);
- if (ret) {
- dev_dbg(&pdev->dev, "gpio request irq fail: %d\n",
- sdhci->data->card_int_gpio);
- goto err_igpio_request_irq;
- }
-
- }
-
- return 0;
-
-err_igpio_request_irq:
-err_igpio_direction:
- if (sdhci->data->card_int_gpio >= 0)
- gpio_free(sdhci->data->card_int_gpio);
-err_igpio_request:
-err_pgpio_direction:
- if (sdhci->data->card_power_gpio >= 0)
- gpio_free(sdhci->data->card_power_gpio);
-err_pgpio_request:
- platform_set_drvdata(pdev, NULL);
- sdhci_remove_host(host, 1);
-err_add_host:
- iounmap(host->ioaddr);
-err_ioremap:
- sdhci_free_host(host);
-err_alloc_host:
- clk_disable(sdhci->clk);
-err_clk_enb:
- clk_put(sdhci->clk);
-err_clk_get:
- kfree(sdhci);
-err_kzalloc:
- release_mem_region(iomem->start, resource_size(iomem));
-err:
- dev_err(&pdev->dev, "spear-sdhci probe failed: %d\n", ret);
- return ret;
-}
-
-static int __devexit sdhci_remove(struct platform_device *pdev)
-{
- struct sdhci_host *host = platform_get_drvdata(pdev);
- struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev);
- int dead;
- u32 scratch;
-
- if (sdhci->data) {
- if (sdhci->data->card_int_gpio >= 0) {
- free_irq(gpio_to_irq(sdhci->data->card_int_gpio), pdev);
- gpio_free(sdhci->data->card_int_gpio);
- }
-
- if (sdhci->data->card_power_gpio >= 0)
- gpio_free(sdhci->data->card_power_gpio);
- }
-
- platform_set_drvdata(pdev, NULL);
- dead = 0;
- scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
- if (scratch == (u32)-1)
- dead = 1;
-
- sdhci_remove_host(host, dead);
- iounmap(host->ioaddr);
- sdhci_free_host(host);
- clk_disable(sdhci->clk);
- clk_put(sdhci->clk);
- kfree(sdhci);
- if (iomem)
- release_mem_region(iomem->start, resource_size(iomem));
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int sdhci_suspend(struct device *dev)
-{
- struct sdhci_host *host = dev_get_drvdata(dev);
- struct spear_sdhci *sdhci = dev_get_platdata(dev);
- int ret;
-
- ret = sdhci_suspend_host(host);
- if (!ret)
- clk_disable(sdhci->clk);
-
- return ret;
-}
-
-static int sdhci_resume(struct device *dev)
-{
- struct sdhci_host *host = dev_get_drvdata(dev);
- struct spear_sdhci *sdhci = dev_get_platdata(dev);
- int ret;
-
- ret = clk_enable(sdhci->clk);
- if (ret) {
- dev_dbg(dev, "Resume: Error enabling clock\n");
- return ret;
- }
-
- return sdhci_resume_host(host);
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(sdhci_pm_ops, sdhci_suspend, sdhci_resume);
-
-static struct platform_driver sdhci_driver = {
- .driver = {
- .name = "sdhci",
- .owner = THIS_MODULE,
- .pm = &sdhci_pm_ops,
- },
- .probe = sdhci_probe,
- .remove = __devexit_p(sdhci_remove),
-};
-
-module_platform_driver(sdhci_driver);
-
-MODULE_DESCRIPTION("SPEAr Secure Digital Host Controller Interface driver");
-MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci-tegra.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci-tegra.c
deleted file mode 100644
index 53b26502..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sdhci-tegra.c
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * Copyright (C) 2010 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_gpio.h>
-#include <linux/gpio.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/host.h>
-
-#include <asm/gpio.h>
-
-#include <mach/gpio-tegra.h>
-#include <mach/sdhci.h>
-
-#include "sdhci-pltfm.h"
-
-#define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0)
-#define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1)
-
-struct sdhci_tegra_soc_data {
- struct sdhci_pltfm_data *pdata;
- u32 nvquirks;
-};
-
-struct sdhci_tegra {
- const struct tegra_sdhci_platform_data *plat;
- const struct sdhci_tegra_soc_data *soc_data;
-};
-
-static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg)
-{
- u32 val;
-
- if (unlikely(reg == SDHCI_PRESENT_STATE)) {
- /* Use wp_gpio here instead? */
- val = readl(host->ioaddr + reg);
- return val | SDHCI_WRITE_PROTECT;
- }
-
- return readl(host->ioaddr + reg);
-}
-
-static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
-{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct sdhci_tegra *tegra_host = pltfm_host->priv;
- const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
-
- if (unlikely((soc_data->nvquirks & NVQUIRK_FORCE_SDHCI_SPEC_200) &&
- (reg == SDHCI_HOST_VERSION))) {
- /* Erratum: Version register is invalid in HW. */
- return SDHCI_SPEC_200;
- }
-
- return readw(host->ioaddr + reg);
-}
-
-static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
-{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct sdhci_tegra *tegra_host = pltfm_host->priv;
- const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
-
- /* Seems like we're getting spurious timeout and crc errors, so
- * disable signalling of them. In case of real errors software
- * timers should take care of eventually detecting them.
- */
- if (unlikely(reg == SDHCI_SIGNAL_ENABLE))
- val &= ~(SDHCI_INT_TIMEOUT|SDHCI_INT_CRC);
-
- writel(val, host->ioaddr + reg);
-
- if (unlikely((soc_data->nvquirks & NVQUIRK_ENABLE_BLOCK_GAP_DET) &&
- (reg == SDHCI_INT_ENABLE))) {
- /* Erratum: Must enable block gap interrupt detection */
- u8 gap_ctrl = readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL);
- if (val & SDHCI_INT_CARD_INT)
- gap_ctrl |= 0x8;
- else
- gap_ctrl &= ~0x8;
- writeb(gap_ctrl, host->ioaddr + SDHCI_BLOCK_GAP_CONTROL);
- }
-}
-
-static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host)
-{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct sdhci_tegra *tegra_host = pltfm_host->priv;
- const struct tegra_sdhci_platform_data *plat = tegra_host->plat;
-
- if (!gpio_is_valid(plat->wp_gpio))
- return -1;
-
- return gpio_get_value(plat->wp_gpio);
-}
-
-static irqreturn_t carddetect_irq(int irq, void *data)
-{
- struct sdhci_host *sdhost = (struct sdhci_host *)data;
-
- tasklet_schedule(&sdhost->card_tasklet);
- return IRQ_HANDLED;
-};
-
-static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width)
-{
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct sdhci_tegra *tegra_host = pltfm_host->priv;
- const struct tegra_sdhci_platform_data *plat = tegra_host->plat;
- u32 ctrl;
-
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
- if (plat->is_8bit && bus_width == MMC_BUS_WIDTH_8) {
- ctrl &= ~SDHCI_CTRL_4BITBUS;
- ctrl |= SDHCI_CTRL_8BITBUS;
- } else {
- ctrl &= ~SDHCI_CTRL_8BITBUS;
- if (bus_width == MMC_BUS_WIDTH_4)
- ctrl |= SDHCI_CTRL_4BITBUS;
- else
- ctrl &= ~SDHCI_CTRL_4BITBUS;
- }
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
- return 0;
-}
-
-static struct sdhci_ops tegra_sdhci_ops = {
- .get_ro = tegra_sdhci_get_ro,
- .read_l = tegra_sdhci_readl,
- .read_w = tegra_sdhci_readw,
- .write_l = tegra_sdhci_writel,
- .platform_8bit_width = tegra_sdhci_8bit,
-};
-
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
-static struct sdhci_pltfm_data sdhci_tegra20_pdata = {
- .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
- SDHCI_QUIRK_SINGLE_POWER_WRITE |
- SDHCI_QUIRK_NO_HISPD_BIT |
- SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
- .ops = &tegra_sdhci_ops,
-};
-
-static struct sdhci_tegra_soc_data soc_data_tegra20 = {
- .pdata = &sdhci_tegra20_pdata,
- .nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 |
- NVQUIRK_ENABLE_BLOCK_GAP_DET,
-};
-#endif
-
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
-static struct sdhci_pltfm_data sdhci_tegra30_pdata = {
- .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
- SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
- SDHCI_QUIRK_SINGLE_POWER_WRITE |
- SDHCI_QUIRK_NO_HISPD_BIT |
- SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
- .ops = &tegra_sdhci_ops,
-};
-
-static struct sdhci_tegra_soc_data soc_data_tegra30 = {
- .pdata = &sdhci_tegra30_pdata,
-};
-#endif
-
-static const struct of_device_id sdhci_tegra_dt_match[] __devinitdata = {
-#ifdef CONFIG_ARCH_TEGRA_3x_SOC
- { .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 },
-#endif
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- { .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 },
-#endif
- {}
-};
-MODULE_DEVICE_TABLE(of, sdhci_dt_ids);
-
-static struct tegra_sdhci_platform_data * __devinit sdhci_tegra_dt_parse_pdata(
- struct platform_device *pdev)
-{
- struct tegra_sdhci_platform_data *plat;
- struct device_node *np = pdev->dev.of_node;
-
- if (!np)
- return NULL;
-
- plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
- if (!plat) {
- dev_err(&pdev->dev, "Can't allocate platform data\n");
- return NULL;
- }
-
- plat->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
- plat->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
- plat->power_gpio = of_get_named_gpio(np, "power-gpios", 0);
- if (of_find_property(np, "support-8bit", NULL))
- plat->is_8bit = 1;
-
- return plat;
-}
-
-static int __devinit sdhci_tegra_probe(struct platform_device *pdev)
-{
- const struct of_device_id *match;
- const struct sdhci_tegra_soc_data *soc_data;
- struct sdhci_host *host;
- struct sdhci_pltfm_host *pltfm_host;
- struct tegra_sdhci_platform_data *plat;
- struct sdhci_tegra *tegra_host;
- struct clk *clk;
- int rc;
-
- match = of_match_device(sdhci_tegra_dt_match, &pdev->dev);
- if (match)
- soc_data = match->data;
- else
- soc_data = &soc_data_tegra20;
-
- host = sdhci_pltfm_init(pdev, soc_data->pdata);
- if (IS_ERR(host))
- return PTR_ERR(host);
-
- pltfm_host = sdhci_priv(host);
-
- plat = pdev->dev.platform_data;
-
- if (plat == NULL)
- plat = sdhci_tegra_dt_parse_pdata(pdev);
-
- if (plat == NULL) {
- dev_err(mmc_dev(host->mmc), "missing platform data\n");
- rc = -ENXIO;
- goto err_no_plat;
- }
-
- tegra_host = devm_kzalloc(&pdev->dev, sizeof(*tegra_host), GFP_KERNEL);
- if (!tegra_host) {
- dev_err(mmc_dev(host->mmc), "failed to allocate tegra_host\n");
- rc = -ENOMEM;
- goto err_no_plat;
- }
-
- tegra_host->plat = plat;
- tegra_host->soc_data = soc_data;
-
- pltfm_host->priv = tegra_host;
-
- if (gpio_is_valid(plat->power_gpio)) {
- rc = gpio_request(plat->power_gpio, "sdhci_power");
- if (rc) {
- dev_err(mmc_dev(host->mmc),
- "failed to allocate power gpio\n");
- goto err_power_req;
- }
- tegra_gpio_enable(plat->power_gpio);
- gpio_direction_output(plat->power_gpio, 1);
- }
-
- if (gpio_is_valid(plat->cd_gpio)) {
- rc = gpio_request(plat->cd_gpio, "sdhci_cd");
- if (rc) {
- dev_err(mmc_dev(host->mmc),
- "failed to allocate cd gpio\n");
- goto err_cd_req;
- }
- tegra_gpio_enable(plat->cd_gpio);
- gpio_direction_input(plat->cd_gpio);
-
- rc = request_irq(gpio_to_irq(plat->cd_gpio), carddetect_irq,
- IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
- mmc_hostname(host->mmc), host);
-
- if (rc) {
- dev_err(mmc_dev(host->mmc), "request irq error\n");
- goto err_cd_irq_req;
- }
-
- }
-
- if (gpio_is_valid(plat->wp_gpio)) {
- rc = gpio_request(plat->wp_gpio, "sdhci_wp");
- if (rc) {
- dev_err(mmc_dev(host->mmc),
- "failed to allocate wp gpio\n");
- goto err_wp_req;
- }
- tegra_gpio_enable(plat->wp_gpio);
- gpio_direction_input(plat->wp_gpio);
- }
-
- clk = clk_get(mmc_dev(host->mmc), NULL);
- if (IS_ERR(clk)) {
- dev_err(mmc_dev(host->mmc), "clk err\n");
- rc = PTR_ERR(clk);
- goto err_clk_get;
- }
- clk_enable(clk);
- pltfm_host->clk = clk;
-
- host->mmc->pm_caps = plat->pm_flags;
-
- if (plat->is_8bit)
- host->mmc->caps |= MMC_CAP_8_BIT_DATA;
-
- rc = sdhci_add_host(host);
- if (rc)
- goto err_add_host;
-
- return 0;
-
-err_add_host:
- clk_disable(pltfm_host->clk);
- clk_put(pltfm_host->clk);
-err_clk_get:
- if (gpio_is_valid(plat->wp_gpio)) {
- tegra_gpio_disable(plat->wp_gpio);
- gpio_free(plat->wp_gpio);
- }
-err_wp_req:
- if (gpio_is_valid(plat->cd_gpio))
- free_irq(gpio_to_irq(plat->cd_gpio), host);
-err_cd_irq_req:
- if (gpio_is_valid(plat->cd_gpio)) {
- tegra_gpio_disable(plat->cd_gpio);
- gpio_free(plat->cd_gpio);
- }
-err_cd_req:
- if (gpio_is_valid(plat->power_gpio)) {
- tegra_gpio_disable(plat->power_gpio);
- gpio_free(plat->power_gpio);
- }
-err_power_req:
-err_no_plat:
- sdhci_pltfm_free(pdev);
- return rc;
-}
-
-static int __devexit sdhci_tegra_remove(struct platform_device *pdev)
-{
- struct sdhci_host *host = platform_get_drvdata(pdev);
- struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct sdhci_tegra *tegra_host = pltfm_host->priv;
- const struct tegra_sdhci_platform_data *plat = tegra_host->plat;
- int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
-
- sdhci_remove_host(host, dead);
-
- if (gpio_is_valid(plat->wp_gpio)) {
- tegra_gpio_disable(plat->wp_gpio);
- gpio_free(plat->wp_gpio);
- }
-
- if (gpio_is_valid(plat->cd_gpio)) {
- free_irq(gpio_to_irq(plat->cd_gpio), host);
- tegra_gpio_disable(plat->cd_gpio);
- gpio_free(plat->cd_gpio);
- }
-
- if (gpio_is_valid(plat->power_gpio)) {
- tegra_gpio_disable(plat->power_gpio);
- gpio_free(plat->power_gpio);
- }
-
- clk_disable(pltfm_host->clk);
- clk_put(pltfm_host->clk);
-
- sdhci_pltfm_free(pdev);
-
- return 0;
-}
-
-static struct platform_driver sdhci_tegra_driver = {
- .driver = {
- .name = "sdhci-tegra",
- .owner = THIS_MODULE,
- .of_match_table = sdhci_tegra_dt_match,
- .pm = SDHCI_PLTFM_PMOPS,
- },
- .probe = sdhci_tegra_probe,
- .remove = __devexit_p(sdhci_tegra_remove),
-};
-
-module_platform_driver(sdhci_tegra_driver);
-
-MODULE_DESCRIPTION("SDHCI driver for Tegra");
-MODULE_AUTHOR("Google, Inc.");
-MODULE_LICENSE("GPL v2");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci.c b/ANDROID_3.4.5/drivers/mmc/host/sdhci.c
deleted file mode 100644
index 37601ec6..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sdhci.c
+++ /dev/null
@@ -1,3136 +0,0 @@
-/*
- * linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver
- *
- * 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.
- *
- * Thanks to the following companies for their support:
- *
- * - JMicron (hardware and technical support)
- */
-
-#include <linux/delay.h>
-#include <linux/highmem.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <linux/scatterlist.h>
-#include <linux/regulator/consumer.h>
-#include <linux/pm_runtime.h>
-
-#include <linux/leds.h>
-
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/host.h>
-
-#include "sdhci.h"
-
-#define DRIVER_NAME "sdhci"
-
-#define DBG(f, x...) \
- pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
-
-#if defined(CONFIG_LEDS_CLASS) || (defined(CONFIG_LEDS_CLASS_MODULE) && \
- defined(CONFIG_MMC_SDHCI_MODULE))
-#define SDHCI_USE_LEDS_CLASS
-#endif
-
-#define MAX_TUNING_LOOP 40
-
-static unsigned int debug_quirks = 0;
-static unsigned int debug_quirks2;
-
-static void sdhci_finish_data(struct sdhci_host *);
-
-static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
-static void sdhci_finish_command(struct sdhci_host *);
-static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
-static void sdhci_tuning_timer(unsigned long data);
-
-#ifdef CONFIG_PM_RUNTIME
-static int sdhci_runtime_pm_get(struct sdhci_host *host);
-static int sdhci_runtime_pm_put(struct sdhci_host *host);
-#else
-static inline int sdhci_runtime_pm_get(struct sdhci_host *host)
-{
- return 0;
-}
-static inline int sdhci_runtime_pm_put(struct sdhci_host *host)
-{
- return 0;
-}
-#endif
-
-static void sdhci_dumpregs(struct sdhci_host *host)
-{
- pr_debug(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n",
- mmc_hostname(host->mmc));
-
- pr_debug(DRIVER_NAME ": Sys addr: 0x%08x | Version: 0x%08x\n",
- sdhci_readl(host, SDHCI_DMA_ADDRESS),
- sdhci_readw(host, SDHCI_HOST_VERSION));
- pr_debug(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt: 0x%08x\n",
- sdhci_readw(host, SDHCI_BLOCK_SIZE),
- sdhci_readw(host, SDHCI_BLOCK_COUNT));
- pr_debug(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n",
- sdhci_readl(host, SDHCI_ARGUMENT),
- sdhci_readw(host, SDHCI_TRANSFER_MODE));
- pr_debug(DRIVER_NAME ": Present: 0x%08x | Host ctl: 0x%08x\n",
- sdhci_readl(host, SDHCI_PRESENT_STATE),
- sdhci_readb(host, SDHCI_HOST_CONTROL));
- pr_debug(DRIVER_NAME ": Power: 0x%08x | Blk gap: 0x%08x\n",
- sdhci_readb(host, SDHCI_POWER_CONTROL),
- sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL));
- pr_debug(DRIVER_NAME ": Wake-up: 0x%08x | Clock: 0x%08x\n",
- sdhci_readb(host, SDHCI_WAKE_UP_CONTROL),
- sdhci_readw(host, SDHCI_CLOCK_CONTROL));
- pr_debug(DRIVER_NAME ": Timeout: 0x%08x | Int stat: 0x%08x\n",
- sdhci_readb(host, SDHCI_TIMEOUT_CONTROL),
- sdhci_readl(host, SDHCI_INT_STATUS));
- pr_debug(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
- sdhci_readl(host, SDHCI_INT_ENABLE),
- sdhci_readl(host, SDHCI_SIGNAL_ENABLE));
- pr_debug(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n",
- sdhci_readw(host, SDHCI_ACMD12_ERR),
- sdhci_readw(host, SDHCI_SLOT_INT_STATUS));
- pr_debug(DRIVER_NAME ": Caps: 0x%08x | Caps_1: 0x%08x\n",
- sdhci_readl(host, SDHCI_CAPABILITIES),
- sdhci_readl(host, SDHCI_CAPABILITIES_1));
- pr_debug(DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n",
- sdhci_readw(host, SDHCI_COMMAND),
- sdhci_readl(host, SDHCI_MAX_CURRENT));
- pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n",
- sdhci_readw(host, SDHCI_HOST_CONTROL2));
-
- if (host->flags & SDHCI_USE_ADMA)
- pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
- readl(host->ioaddr + SDHCI_ADMA_ERROR),
- readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
-
- pr_debug(DRIVER_NAME ": ===========================================\n");
-}
-
-/*****************************************************************************\
- * *
- * Low level functions *
- * *
-\*****************************************************************************/
-
-static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
-{
- u32 ier;
-
- ier = sdhci_readl(host, SDHCI_INT_ENABLE);
- ier &= ~clear;
- ier |= set;
- sdhci_writel(host, ier, SDHCI_INT_ENABLE);
- sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
-}
-
-static void sdhci_unmask_irqs(struct sdhci_host *host, u32 irqs)
-{
- sdhci_clear_set_irqs(host, 0, irqs);
-}
-
-static void sdhci_mask_irqs(struct sdhci_host *host, u32 irqs)
-{
- sdhci_clear_set_irqs(host, irqs, 0);
-}
-
-static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
-{
- u32 present, irqs;
-
- if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) ||
- (host->mmc->caps & MMC_CAP_NONREMOVABLE))
- return;
-
- present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
- SDHCI_CARD_PRESENT;
- irqs = present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT;
-
- if (enable)
- sdhci_unmask_irqs(host, irqs);
- else
- sdhci_mask_irqs(host, irqs);
-}
-
-static void sdhci_enable_card_detection(struct sdhci_host *host)
-{
- sdhci_set_card_detection(host, true);
-}
-
-static void sdhci_disable_card_detection(struct sdhci_host *host)
-{
- sdhci_set_card_detection(host, false);
-}
-
-static void sdhci_reset(struct sdhci_host *host, u8 mask)
-{
- unsigned long timeout;
- u32 uninitialized_var(ier);
-
- if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
- if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
- SDHCI_CARD_PRESENT))
- return;
- }
-
- if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
- ier = sdhci_readl(host, SDHCI_INT_ENABLE);
-
- if (host->ops->platform_reset_enter)
- host->ops->platform_reset_enter(host, mask);
-
- sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
-
- if (mask & SDHCI_RESET_ALL)
- host->clock = 0;
-
- /* Wait max 100 ms */
- timeout = 100;
-
- /* hw clears the bit when it's done */
- while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
- if (timeout == 0) {
- pr_err("%s: Reset 0x%x never completed.\n",
- mmc_hostname(host->mmc), (int)mask);
- sdhci_dumpregs(host);
- return;
- }
- timeout--;
- mdelay(1);
- }
-
- if (host->ops->platform_reset_exit)
- host->ops->platform_reset_exit(host, mask);
-
- if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
- sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
-
- if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
- if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL))
- host->ops->enable_dma(host);
- }
-}
-
-static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
-
-static void sdhci_init(struct sdhci_host *host, int soft)
-{
- if (soft)
- sdhci_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
- else
- sdhci_reset(host, SDHCI_RESET_ALL);
-
- sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK,
- SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
- SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
- SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
- SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE);
-
- if (soft) {
- /* force clock reconfiguration */
- host->clock = 0;
- sdhci_set_ios(host->mmc, &host->mmc->ios);
- }
-}
-
-static void sdhci_reinit(struct sdhci_host *host)
-{
- sdhci_init(host, 0);
- sdhci_enable_card_detection(host);
-}
-
-static void sdhci_activate_led(struct sdhci_host *host)
-{
- u8 ctrl;
-
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
- ctrl |= SDHCI_CTRL_LED;
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-}
-
-static void sdhci_deactivate_led(struct sdhci_host *host)
-{
- u8 ctrl;
-
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
- ctrl &= ~SDHCI_CTRL_LED;
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-}
-
-#ifdef SDHCI_USE_LEDS_CLASS
-static void sdhci_led_control(struct led_classdev *led,
- enum led_brightness brightness)
-{
- struct sdhci_host *host = container_of(led, struct sdhci_host, led);
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
-
- if (host->runtime_suspended)
- goto out;
-
- if (brightness == LED_OFF)
- sdhci_deactivate_led(host);
- else
- sdhci_activate_led(host);
-out:
- spin_unlock_irqrestore(&host->lock, flags);
-}
-#endif
-
-/*****************************************************************************\
- * *
- * Core functions *
- * *
-\*****************************************************************************/
-
-static void sdhci_read_block_pio(struct sdhci_host *host)
-{
- unsigned long flags;
- size_t blksize, len, chunk;
- u32 uninitialized_var(scratch);
- u8 *buf;
-
- DBG("PIO reading\n");
-
- blksize = host->data->blksz;
- chunk = 0;
-
- local_irq_save(flags);
-
- while (blksize) {
- if (!sg_miter_next(&host->sg_miter))
- BUG();
-
- len = min(host->sg_miter.length, blksize);
-
- blksize -= len;
- host->sg_miter.consumed = len;
-
- buf = host->sg_miter.addr;
-
- while (len) {
- if (chunk == 0) {
- scratch = sdhci_readl(host, SDHCI_BUFFER);
- chunk = 4;
- }
-
- *buf = scratch & 0xFF;
-
- buf++;
- scratch >>= 8;
- chunk--;
- len--;
- }
- }
-
- sg_miter_stop(&host->sg_miter);
-
- local_irq_restore(flags);
-}
-
-static void sdhci_write_block_pio(struct sdhci_host *host)
-{
- unsigned long flags;
- size_t blksize, len, chunk;
- u32 scratch;
- u8 *buf;
-
- DBG("PIO writing\n");
-
- blksize = host->data->blksz;
- chunk = 0;
- scratch = 0;
-
- local_irq_save(flags);
-
- while (blksize) {
- if (!sg_miter_next(&host->sg_miter))
- BUG();
-
- len = min(host->sg_miter.length, blksize);
-
- blksize -= len;
- host->sg_miter.consumed = len;
-
- buf = host->sg_miter.addr;
-
- while (len) {
- scratch |= (u32)*buf << (chunk * 8);
-
- buf++;
- chunk++;
- len--;
-
- if ((chunk == 4) || ((len == 0) && (blksize == 0))) {
- sdhci_writel(host, scratch, SDHCI_BUFFER);
- chunk = 0;
- scratch = 0;
- }
- }
- }
-
- sg_miter_stop(&host->sg_miter);
-
- local_irq_restore(flags);
-}
-
-static void sdhci_transfer_pio(struct sdhci_host *host)
-{
- u32 mask;
-
- BUG_ON(!host->data);
-
- if (host->blocks == 0)
- return;
-
- if (host->data->flags & MMC_DATA_READ)
- mask = SDHCI_DATA_AVAILABLE;
- else
- mask = SDHCI_SPACE_AVAILABLE;
-
- /*
- * Some controllers (JMicron JMB38x) mess up the buffer bits
- * for transfers < 4 bytes. As long as it is just one block,
- * we can ignore the bits.
- */
- if ((host->quirks & SDHCI_QUIRK_BROKEN_SMALL_PIO) &&
- (host->data->blocks == 1))
- mask = ~0;
-
- while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
- if (host->quirks & SDHCI_QUIRK_PIO_NEEDS_DELAY)
- udelay(100);
-
- if (host->data->flags & MMC_DATA_READ)
- sdhci_read_block_pio(host);
- else
- sdhci_write_block_pio(host);
-
- host->blocks--;
- if (host->blocks == 0)
- break;
- }
-
- DBG("PIO transfer complete.\n");
-}
-
-static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags)
-{
- local_irq_save(*flags);
- return kmap_atomic(sg_page(sg)) + sg->offset;
-}
-
-static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags)
-{
- kunmap_atomic(buffer);
- local_irq_restore(*flags);
-}
-
-static void sdhci_set_adma_desc(u8 *desc, u32 addr, int len, unsigned cmd)
-{
- __le32 *dataddr = (__le32 __force *)(desc + 4);
- __le16 *cmdlen = (__le16 __force *)desc;
-
- /* SDHCI specification says ADMA descriptors should be 4 byte
- * aligned, so using 16 or 32bit operations should be safe. */
-
- cmdlen[0] = cpu_to_le16(cmd);
- cmdlen[1] = cpu_to_le16(len);
-
- dataddr[0] = cpu_to_le32(addr);
-}
-
-static int sdhci_adma_table_pre(struct sdhci_host *host,
- struct mmc_data *data)
-{
- int direction;
-
- u8 *desc;
- u8 *align;
- dma_addr_t addr;
- dma_addr_t align_addr;
- int len, offset;
-
- struct scatterlist *sg;
- int i;
- char *buffer;
- unsigned long flags;
-
- /*
- * The spec does not specify endianness of descriptor table.
- * We currently guess that it is LE.
- */
-
- if (data->flags & MMC_DATA_READ)
- direction = DMA_FROM_DEVICE;
- else
- direction = DMA_TO_DEVICE;
-
- /*
- * The ADMA descriptor table is mapped further down as we
- * need to fill it with data first.
- */
-
- host->align_addr = dma_map_single(mmc_dev(host->mmc),
- host->align_buffer, 128 * 4, direction);
- if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
- goto fail;
- BUG_ON(host->align_addr & 0x3);
-
- host->sg_count = dma_map_sg(mmc_dev(host->mmc),
- data->sg, data->sg_len, direction);
- if (host->sg_count == 0)
- goto unmap_align;
-
- desc = host->adma_desc;
- align = host->align_buffer;
-
- align_addr = host->align_addr;
-
- for_each_sg(data->sg, sg, host->sg_count, i) {
- addr = sg_dma_address(sg);
- len = sg_dma_len(sg);
-
- /*
- * The SDHCI specification states that ADMA
- * addresses must be 32-bit aligned. If they
- * aren't, then we use a bounce buffer for
- * the (up to three) bytes that screw up the
- * alignment.
- */
- offset = (4 - (addr & 0x3)) & 0x3;
- if (offset) {
- if (data->flags & MMC_DATA_WRITE) {
- buffer = sdhci_kmap_atomic(sg, &flags);
- WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3));
- memcpy(align, buffer, offset);
- sdhci_kunmap_atomic(buffer, &flags);
- }
-
- /* tran, valid */
- sdhci_set_adma_desc(desc, align_addr, offset, 0x21);
-
- BUG_ON(offset > 65536);
-
- align += 4;
- align_addr += 4;
-
- desc += 8;
-
- addr += offset;
- len -= offset;
- }
-
- BUG_ON(len > 65536);
-
- /* tran, valid */
- sdhci_set_adma_desc(desc, addr, len, 0x21);
- desc += 8;
-
- /*
- * If this triggers then we have a calculation bug
- * somewhere. :/
- */
- WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 4);
- }
-
- if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) {
- /*
- * Mark the last descriptor as the terminating descriptor
- */
- if (desc != host->adma_desc) {
- desc -= 8;
- desc[0] |= 0x2; /* end */
- }
- } else {
- /*
- * Add a terminating entry.
- */
-
- /* nop, end, valid */
- sdhci_set_adma_desc(desc, 0, 0, 0x3);
- }
-
- /*
- * Resync align buffer as we might have changed it.
- */
- if (data->flags & MMC_DATA_WRITE) {
- dma_sync_single_for_device(mmc_dev(host->mmc),
- host->align_addr, 128 * 4, direction);
- }
-
- host->adma_addr = dma_map_single(mmc_dev(host->mmc),
- host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE);
- if (dma_mapping_error(mmc_dev(host->mmc), host->adma_addr))
- goto unmap_entries;
- BUG_ON(host->adma_addr & 0x3);
-
- return 0;
-
-unmap_entries:
- dma_unmap_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, direction);
-unmap_align:
- dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
- 128 * 4, direction);
-fail:
- return -EINVAL;
-}
-
-static void sdhci_adma_table_post(struct sdhci_host *host,
- struct mmc_data *data)
-{
- int direction;
-
- struct scatterlist *sg;
- int i, size;
- u8 *align;
- char *buffer;
- unsigned long flags;
-
- if (data->flags & MMC_DATA_READ)
- direction = DMA_FROM_DEVICE;
- else
- direction = DMA_TO_DEVICE;
-
- dma_unmap_single(mmc_dev(host->mmc), host->adma_addr,
- (128 * 2 + 1) * 4, DMA_TO_DEVICE);
-
- dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
- 128 * 4, direction);
-
- if (data->flags & MMC_DATA_READ) {
- dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg,
- data->sg_len, direction);
-
- align = host->align_buffer;
-
- for_each_sg(data->sg, sg, host->sg_count, i) {
- if (sg_dma_address(sg) & 0x3) {
- size = 4 - (sg_dma_address(sg) & 0x3);
-
- buffer = sdhci_kmap_atomic(sg, &flags);
- WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3));
- memcpy(buffer, align, size);
- sdhci_kunmap_atomic(buffer, &flags);
-
- align += 4;
- }
- }
- }
-
- dma_unmap_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, direction);
-}
-
-static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
-{
- u8 count;
- struct mmc_data *data = cmd->data;
- unsigned target_timeout, current_timeout;
-
- /*
- * If the host controller provides us with an incorrect timeout
- * value, just skip the check and use 0xE. The hardware may take
- * longer to time out, but that's much better than having a too-short
- * timeout value.
- */
- if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
- return 0xE;
-
- /* Unspecified timeout, assume max */
- if (!data && !cmd->cmd_timeout_ms)
- return 0xE;
-
- /* timeout in us */
- if (!data)
- target_timeout = cmd->cmd_timeout_ms * 1000;
- else {
- target_timeout = data->timeout_ns / 1000;
- if (host->clock)
- target_timeout += data->timeout_clks / host->clock;
- }
-
- /*
- * Figure out needed cycles.
- * We do this in steps in order to fit inside a 32 bit int.
- * The first step is the minimum timeout, which will have a
- * minimum resolution of 6 bits:
- * (1) 2^13*1000 > 2^22,
- * (2) host->timeout_clk < 2^16
- * =>
- * (1) / (2) > 2^6
- */
- count = 0;
- current_timeout = (1 << 13) * 1000 / host->timeout_clk;
- while (current_timeout < target_timeout) {
- count++;
- current_timeout <<= 1;
- if (count >= 0xF)
- break;
- }
-
- if (count >= 0xF)
- count = 0xE;
-
- return count;
-}
-
-static void sdhci_set_transfer_irqs(struct sdhci_host *host)
-{
- u32 pio_irqs = SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL;
- u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;
-
- if (host->flags & SDHCI_REQ_USE_DMA)
- sdhci_clear_set_irqs(host, pio_irqs, dma_irqs);
- else
- sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
-}
-
-static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
-{
- u8 count;
- u8 ctrl;
- struct mmc_data *data = cmd->data;
- int ret;
-
- WARN_ON(host->data);
-
- if (data || (cmd->flags & MMC_RSP_BUSY)) {
- count = sdhci_calc_timeout(host, cmd);
- sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
- }
-
- if (!data)
- return;
-
- /* Sanity checks */
- BUG_ON(data->blksz * data->blocks > 524288);
- BUG_ON(data->blksz > host->mmc->max_blk_size);
- BUG_ON(data->blocks > 65535);
-
- host->data = data;
- host->data_early = 0;
- host->data->bytes_xfered = 0;
-
- if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))
- host->flags |= SDHCI_REQ_USE_DMA;
-
- /*
- * FIXME: This doesn't account for merging when mapping the
- * scatterlist.
- */
- if (host->flags & SDHCI_REQ_USE_DMA) {
- int broken, i;
- struct scatterlist *sg;
-
- broken = 0;
- if (host->flags & SDHCI_USE_ADMA) {
- if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE)
- broken = 1;
- } else {
- if (host->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE)
- broken = 1;
- }
-
- if (unlikely(broken)) {
- for_each_sg(data->sg, sg, data->sg_len, i) {
- if (sg->length & 0x3) {
- DBG("Reverting to PIO because of "
- "transfer size (%d)\n",
- sg->length);
- host->flags &= ~SDHCI_REQ_USE_DMA;
- break;
- }
- }
- }
- }
-
- /*
- * The assumption here being that alignment is the same after
- * translation to device address space.
- */
- if (host->flags & SDHCI_REQ_USE_DMA) {
- int broken, i;
- struct scatterlist *sg;
-
- broken = 0;
- if (host->flags & SDHCI_USE_ADMA) {
- /*
- * As we use 3 byte chunks to work around
- * alignment problems, we need to check this
- * quirk.
- */
- if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE)
- broken = 1;
- } else {
- if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR)
- broken = 1;
- }
-
- if (unlikely(broken)) {
- for_each_sg(data->sg, sg, data->sg_len, i) {
- if (sg->offset & 0x3) {
- DBG("Reverting to PIO because of "
- "bad alignment\n");
- host->flags &= ~SDHCI_REQ_USE_DMA;
- break;
- }
- }
- }
- }
-
- if (host->flags & SDHCI_REQ_USE_DMA) {
- if (host->flags & SDHCI_USE_ADMA) {
- ret = sdhci_adma_table_pre(host, data);
- if (ret) {
- /*
- * This only happens when someone fed
- * us an invalid request.
- */
- WARN_ON(1);
- host->flags &= ~SDHCI_REQ_USE_DMA;
- } else {
- sdhci_writel(host, host->adma_addr,
- SDHCI_ADMA_ADDRESS);
- }
- } else {
- int sg_cnt;
-
- sg_cnt = dma_map_sg(mmc_dev(host->mmc),
- data->sg, data->sg_len,
- (data->flags & MMC_DATA_READ) ?
- DMA_FROM_DEVICE :
- DMA_TO_DEVICE);
- if (sg_cnt == 0) {
- /*
- * This only happens when someone fed
- * us an invalid request.
- */
- WARN_ON(1);
- host->flags &= ~SDHCI_REQ_USE_DMA;
- } else {
- WARN_ON(sg_cnt != 1);
- sdhci_writel(host, sg_dma_address(data->sg),
- SDHCI_DMA_ADDRESS);
- }
- }
- }
-
- /*
- * Always adjust the DMA selection as some controllers
- * (e.g. JMicron) can't do PIO properly when the selection
- * is ADMA.
- */
- if (host->version >= SDHCI_SPEC_200) {
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
- ctrl &= ~SDHCI_CTRL_DMA_MASK;
- if ((host->flags & SDHCI_REQ_USE_DMA) &&
- (host->flags & SDHCI_USE_ADMA))
- ctrl |= SDHCI_CTRL_ADMA32;
- else
- ctrl |= SDHCI_CTRL_SDMA;
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
- }
-
- if (!(host->flags & SDHCI_REQ_USE_DMA)) {
- int flags;
-
- flags = SG_MITER_ATOMIC;
- if (host->data->flags & MMC_DATA_READ)
- flags |= SG_MITER_TO_SG;
- else
- flags |= SG_MITER_FROM_SG;
- sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
- host->blocks = data->blocks;
- }
-
- sdhci_set_transfer_irqs(host);
-
- /* Set the DMA boundary value and block size */
- sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
- data->blksz), SDHCI_BLOCK_SIZE);
- sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
-}
-
-static void sdhci_set_transfer_mode(struct sdhci_host *host,
- struct mmc_command *cmd)
-{
- u16 mode;
- struct mmc_data *data = cmd->data;
-
- if (data == NULL)
- return;
-
- WARN_ON(!host->data);
-
- mode = SDHCI_TRNS_BLK_CNT_EN;
- if (mmc_op_multi(cmd->opcode) || data->blocks > 1) {
- mode |= SDHCI_TRNS_MULTI;
- /*
- * If we are sending CMD23, CMD12 never gets sent
- * on successful completion (so no Auto-CMD12).
- */
- if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12))
- mode |= SDHCI_TRNS_AUTO_CMD12;
- else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
- mode |= SDHCI_TRNS_AUTO_CMD23;
- sdhci_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2);
- }
- }
-
- if (data->flags & MMC_DATA_READ)
- mode |= SDHCI_TRNS_READ;
- if (host->flags & SDHCI_REQ_USE_DMA)
- mode |= SDHCI_TRNS_DMA;
-
- sdhci_writew(host, mode, SDHCI_TRANSFER_MODE);
-}
-
-static void sdhci_finish_data(struct sdhci_host *host)
-{
- struct mmc_data *data;
-
- BUG_ON(!host->data);
-
- data = host->data;
- host->data = NULL;
-
- if (host->flags & SDHCI_REQ_USE_DMA) {
- if (host->flags & SDHCI_USE_ADMA)
- sdhci_adma_table_post(host, data);
- else {
- dma_unmap_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, (data->flags & MMC_DATA_READ) ?
- DMA_FROM_DEVICE : DMA_TO_DEVICE);
- }
- }
-
- /*
- * The specification states that the block count register must
- * be updated, but it does not specify at what point in the
- * data flow. That makes the register entirely useless to read
- * back so we have to assume that nothing made it to the card
- * in the event of an error.
- */
- if (data->error)
- data->bytes_xfered = 0;
- else
- data->bytes_xfered = data->blksz * data->blocks;
-
- /*
- * Need to send CMD12 if -
- * a) open-ended multiblock transfer (no CMD23)
- * b) error in multiblock transfer
- */
- if (data->stop &&
- (data->error ||
- !host->mrq->sbc)) {
-
- /*
- * The controller needs a reset of internal state machines
- * upon error conditions.
- */
- if (data->error) {
- sdhci_reset(host, SDHCI_RESET_CMD);
- sdhci_reset(host, SDHCI_RESET_DATA);
- }
-
- sdhci_send_command(host, data->stop);
- } else
- tasklet_schedule(&host->finish_tasklet);
-}
-
-static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
-{
- int flags;
- u32 mask;
- unsigned long timeout;
-
- WARN_ON(host->cmd);
-
- /* Wait max 10 ms */
- timeout = 10;
-
- mask = SDHCI_CMD_INHIBIT;
- if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
- mask |= SDHCI_DATA_INHIBIT;
-
- /* We shouldn't wait for data inihibit for stop commands, even
- though they might use busy signaling */
- if (host->mrq->data && (cmd == host->mrq->data->stop))
- mask &= ~SDHCI_DATA_INHIBIT;
-
- while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
- if (timeout == 0) {
- pr_err("%s: Controller never released "
- "inhibit bit(s).\n", mmc_hostname(host->mmc));
- sdhci_dumpregs(host);
- cmd->error = -EIO;
- tasklet_schedule(&host->finish_tasklet);
- return;
- }
- timeout--;
- mdelay(1);
- }
-
- mod_timer(&host->timer, jiffies + 10 * HZ);
-
- host->cmd = cmd;
-
- sdhci_prepare_data(host, cmd);
-
- sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
-
- sdhci_set_transfer_mode(host, cmd);
-
- if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
- pr_err("%s: Unsupported response type!\n",
- mmc_hostname(host->mmc));
- cmd->error = -EINVAL;
- tasklet_schedule(&host->finish_tasklet);
- return;
- }
-
- if (!(cmd->flags & MMC_RSP_PRESENT))
- flags = SDHCI_CMD_RESP_NONE;
- else if (cmd->flags & MMC_RSP_136)
- flags = SDHCI_CMD_RESP_LONG;
- else if (cmd->flags & MMC_RSP_BUSY)
- flags = SDHCI_CMD_RESP_SHORT_BUSY;
- else
- flags = SDHCI_CMD_RESP_SHORT;
-
- if (cmd->flags & MMC_RSP_CRC)
- flags |= SDHCI_CMD_CRC;
- if (cmd->flags & MMC_RSP_OPCODE)
- flags |= SDHCI_CMD_INDEX;
-
- /* CMD19 is special in that the Data Present Select should be set */
- if (cmd->data || cmd->opcode == MMC_SEND_TUNING_BLOCK ||
- cmd->opcode == MMC_SEND_TUNING_BLOCK_HS200)
- flags |= SDHCI_CMD_DATA;
-
- sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
-}
-
-static void sdhci_finish_command(struct sdhci_host *host)
-{
- int i;
-
- BUG_ON(host->cmd == NULL);
-
- if (host->cmd->flags & MMC_RSP_PRESENT) {
- if (host->cmd->flags & MMC_RSP_136) {
- /* CRC is stripped so we need to do some shifting. */
- for (i = 0;i < 4;i++) {
- host->cmd->resp[i] = sdhci_readl(host,
- SDHCI_RESPONSE + (3-i)*4) << 8;
- if (i != 3)
- host->cmd->resp[i] |=
- sdhci_readb(host,
- SDHCI_RESPONSE + (3-i)*4-1);
- }
- } else {
- host->cmd->resp[0] = sdhci_readl(host, SDHCI_RESPONSE);
- }
- }
-
- host->cmd->error = 0;
-
- /* Finished CMD23, now send actual command. */
- if (host->cmd == host->mrq->sbc) {
- host->cmd = NULL;
- sdhci_send_command(host, host->mrq->cmd);
- } else {
-
- /* Processed actual command. */
- if (host->data && host->data_early)
- sdhci_finish_data(host);
-
- if (!host->cmd->data)
- tasklet_schedule(&host->finish_tasklet);
-
- host->cmd = NULL;
- }
-}
-
-static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
-{
- int div = 0; /* Initialized for compiler warning */
- int real_div = div, clk_mul = 1;
- u16 clk = 0;
- unsigned long timeout;
-
- if (clock && clock == host->clock)
- return;
-
- host->mmc->actual_clock = 0;
-
- if (host->ops->set_clock) {
- host->ops->set_clock(host, clock);
- if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK)
- return;
- }
-
- sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
-
- if (clock == 0)
- goto out;
-
- if (host->version >= SDHCI_SPEC_300) {
- /*
- * Check if the Host Controller supports Programmable Clock
- * Mode.
- */
- if (host->clk_mul) {
- u16 ctrl;
-
- /*
- * We need to figure out whether the Host Driver needs
- * to select Programmable Clock Mode, or the value can
- * be set automatically by the Host Controller based on
- * the Preset Value registers.
- */
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- if (!(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
- for (div = 1; div <= 1024; div++) {
- if (((host->max_clk * host->clk_mul) /
- div) <= clock)
- break;
- }
- /*
- * Set Programmable Clock Mode in the Clock
- * Control register.
- */
- clk = SDHCI_PROG_CLOCK_MODE;
- real_div = div;
- clk_mul = host->clk_mul;
- div--;
- }
- } else {
- /* 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;
- }
- }
- real_div = div;
- div >>= 1;
- }
- } 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;
- }
- real_div = div;
- div >>= 1;
- }
-
- if (real_div)
- host->mmc->actual_clock = (host->max_clk * clk_mul) / real_div;
-
- 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);
-
- /* Wait max 20 ms */
- timeout = 20;
- while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
- & SDHCI_CLOCK_INT_STABLE)) {
- if (timeout == 0) {
- pr_err("%s: Internal clock never "
- "stabilised.\n", mmc_hostname(host->mmc));
- sdhci_dumpregs(host);
- return;
- }
- timeout--;
- mdelay(1);
- }
-
- clk |= SDHCI_CLOCK_CARD_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
-out:
- host->clock = clock;
-}
-
-static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
-{
- u8 pwr = 0;
-
- if (power != (unsigned short)-1) {
- switch (1 << power) {
- case MMC_VDD_165_195:
- pwr = SDHCI_POWER_180;
- break;
- case MMC_VDD_29_30:
- case MMC_VDD_30_31:
- pwr = SDHCI_POWER_300;
- break;
- case MMC_VDD_32_33:
- case MMC_VDD_33_34:
- pwr = SDHCI_POWER_330;
- break;
- default:
- BUG();
- }
- }
-
- if (host->pwr == pwr)
- return -1;
-
- host->pwr = pwr;
-
- if (pwr == 0) {
- sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
- return 0;
- }
-
- /*
- * Spec says that we should clear the power reg before setting
- * a new value. Some controllers don't seem to like this though.
- */
- if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
- sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
-
- /*
- * At least the Marvell CaFe chip gets confused if we set the voltage
- * and set turn on power at the same time, so set the voltage first.
- */
- if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
- sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
-
- pwr |= SDHCI_POWER_ON;
-
- sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
-
- /*
- * Some controllers need an extra 10ms delay of 10ms before they
- * can apply clock after applying power
- */
- if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
- mdelay(10);
-
- return power;
-}
-
-/*****************************************************************************\
- * *
- * MMC callbacks *
- * *
-\*****************************************************************************/
-
-static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct sdhci_host *host;
- bool present;
- unsigned long flags;
-
- host = mmc_priv(mmc);
-
- sdhci_runtime_pm_get(host);
-
- spin_lock_irqsave(&host->lock, flags);
-
- WARN_ON(host->mrq != NULL);
-
-#ifndef SDHCI_USE_LEDS_CLASS
- sdhci_activate_led(host);
-#endif
-
- /*
- * Ensure we don't send the STOP for non-SET_BLOCK_COUNTED
- * requests if Auto-CMD12 is enabled.
- */
- if (!mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) {
- if (mrq->stop) {
- mrq->data->stop = NULL;
- mrq->stop = NULL;
- }
- }
-
- host->mrq = mrq;
-
- /* If polling, assume that the card is always present. */
- if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
- present = true;
- else
- present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
- SDHCI_CARD_PRESENT;
-
- if (!present || host->flags & SDHCI_DEVICE_DEAD) {
- host->mrq->cmd->error = -ENOMEDIUM;
- tasklet_schedule(&host->finish_tasklet);
- } else {
- u32 present_state;
-
- present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
- /*
- * Check if the re-tuning timer has already expired and there
- * is no on-going data transfer. If so, we need to execute
- * tuning procedure before sending command.
- */
- if ((host->flags & SDHCI_NEEDS_RETUNING) &&
- !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) {
- spin_unlock_irqrestore(&host->lock, flags);
- sdhci_execute_tuning(mmc, mrq->cmd->opcode);
- spin_lock_irqsave(&host->lock, flags);
-
- /* Restore original mmc_request structure */
- host->mrq = mrq;
- }
-
- if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23))
- sdhci_send_command(host, mrq->sbc);
- else
- sdhci_send_command(host, mrq->cmd);
- }
-
- mmiowb();
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
-{
- unsigned long flags;
- int vdd_bit = -1;
- u8 ctrl;
-
- spin_lock_irqsave(&host->lock, flags);
-
- if (host->flags & SDHCI_DEVICE_DEAD) {
- spin_unlock_irqrestore(&host->lock, flags);
- if (host->vmmc && ios->power_mode == MMC_POWER_OFF)
- mmc_regulator_set_ocr(host->mmc, host->vmmc, 0);
- return;
- }
-
- /*
- * Reset the chip on each power off.
- * Should clear out any weird states.
- */
- if (ios->power_mode == MMC_POWER_OFF) {
- sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
- sdhci_reinit(host);
- }
-
- sdhci_set_clock(host, ios->clock);
-
- if (ios->power_mode == MMC_POWER_OFF)
- vdd_bit = sdhci_set_power(host, -1);
- else
- vdd_bit = sdhci_set_power(host, ios->vdd);
-
- if (host->vmmc && vdd_bit != -1) {
- spin_unlock_irqrestore(&host->lock, flags);
- mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit);
- spin_lock_irqsave(&host->lock, flags);
- }
-
- if (host->ops->platform_send_init_74_clocks)
- host->ops->platform_send_init_74_clocks(host, ios->power_mode);
-
- /*
- * If your platform has 8-bit width support but is not a v3 controller,
- * or if it requires special setup code, you should implement that in
- * platform_8bit_width().
- */
- if (host->ops->platform_8bit_width)
- host->ops->platform_8bit_width(host, ios->bus_width);
- else {
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
- if (ios->bus_width == MMC_BUS_WIDTH_8) {
- ctrl &= ~SDHCI_CTRL_4BITBUS;
- if (host->version >= SDHCI_SPEC_300)
- ctrl |= SDHCI_CTRL_8BITBUS;
- } else {
- if (host->version >= SDHCI_SPEC_300)
- ctrl &= ~SDHCI_CTRL_8BITBUS;
- if (ios->bus_width == MMC_BUS_WIDTH_4)
- ctrl |= SDHCI_CTRL_4BITBUS;
- else
- ctrl &= ~SDHCI_CTRL_4BITBUS;
- }
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
- }
-
- ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
-
- 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;
-
- if (host->version >= SDHCI_SPEC_300) {
- u16 clk, ctrl_2;
- unsigned int clock;
-
- /* In case of UHS-I modes, set High Speed Enable */
- if ((ios->timing == MMC_TIMING_MMC_HS200) ||
- (ios->timing == MMC_TIMING_UHS_SDR50) ||
- (ios->timing == MMC_TIMING_UHS_SDR104) ||
- (ios->timing == MMC_TIMING_UHS_DDR50) ||
- (ios->timing == MMC_TIMING_UHS_SDR25))
- ctrl |= SDHCI_CTRL_HISPD;
-
- ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- if (!(ctrl_2 & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
- /*
- * We only need to set Driver Strength if the
- * preset value enable is not set.
- */
- ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK;
- if (ios->drv_type == MMC_SET_DRIVER_TYPE_A)
- ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A;
- else if (ios->drv_type == MMC_SET_DRIVER_TYPE_C)
- ctrl_2 |= SDHCI_CTRL_DRV_TYPE_C;
-
- sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
- } else {
- /*
- * According to SDHC Spec v3.00, if the Preset Value
- * Enable in the Host Control 2 register is set, we
- * need to reset SD Clock Enable before changing High
- * Speed Enable to avoid generating clock gliches.
- */
-
- /* Reset SD Clock Enable */
- clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
- clk &= ~SDHCI_CLOCK_CARD_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-
- /* Re-enable SD Clock */
- clock = host->clock;
- host->clock = 0;
- sdhci_set_clock(host, clock);
- }
-
-
- /* Reset SD Clock Enable */
- clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
- clk &= ~SDHCI_CLOCK_CARD_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
- if (host->ops->set_uhs_signaling)
- host->ops->set_uhs_signaling(host, ios->timing);
- else {
- ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- /* Select Bus Speed Mode for host */
- ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
- if (ios->timing == MMC_TIMING_MMC_HS200)
- ctrl_2 |= SDHCI_CTRL_HS_SDR200;
- else if (ios->timing == MMC_TIMING_UHS_SDR12)
- ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
- else if (ios->timing == MMC_TIMING_UHS_SDR25)
- ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
- else if (ios->timing == MMC_TIMING_UHS_SDR50)
- ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
- else if (ios->timing == MMC_TIMING_UHS_SDR104)
- ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
- else if (ios->timing == MMC_TIMING_UHS_DDR50)
- ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
- sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
- }
-
- /* Re-enable SD Clock */
- clock = host->clock;
- host->clock = 0;
- sdhci_set_clock(host, clock);
- } else
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-
- /*
- * Some (ENE) controllers go apeshit on some ios operation,
- * signalling timeout and CRC errors even on CMD0. Resetting
- * it on each ios seems to solve the problem.
- */
- if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
- sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
-
- mmiowb();
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct sdhci_host *host = mmc_priv(mmc);
-
- sdhci_runtime_pm_get(host);
- sdhci_do_set_ios(host, ios);
- sdhci_runtime_pm_put(host);
-}
-
-static int sdhci_check_ro(struct sdhci_host *host)
-{
- unsigned long flags;
- int is_readonly;
-
- spin_lock_irqsave(&host->lock, flags);
-
- if (host->flags & SDHCI_DEVICE_DEAD)
- is_readonly = 0;
- else if (host->ops->get_ro)
- is_readonly = host->ops->get_ro(host);
- else
- is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE)
- & SDHCI_WRITE_PROTECT);
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- /* This quirk needs to be replaced by a callback-function later */
- return host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT ?
- !is_readonly : is_readonly;
-}
-
-#define SAMPLE_COUNT 5
-
-static int sdhci_do_get_ro(struct sdhci_host *host)
-{
- int i, ro_count;
-
- if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT))
- return sdhci_check_ro(host);
-
- ro_count = 0;
- for (i = 0; i < SAMPLE_COUNT; i++) {
- if (sdhci_check_ro(host)) {
- if (++ro_count > SAMPLE_COUNT / 2)
- return 1;
- }
- msleep(30);
- }
- return 0;
-}
-
-static void sdhci_hw_reset(struct mmc_host *mmc)
-{
- struct sdhci_host *host = mmc_priv(mmc);
-
- if (host->ops && host->ops->hw_reset)
- host->ops->hw_reset(host);
-}
-
-static int sdhci_get_ro(struct mmc_host *mmc)
-{
- struct sdhci_host *host = mmc_priv(mmc);
- int ret;
-
- sdhci_runtime_pm_get(host);
- ret = sdhci_do_get_ro(host);
- sdhci_runtime_pm_put(host);
- return ret;
-}
-
-static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
-{
- if (host->flags & SDHCI_DEVICE_DEAD)
- goto out;
-
- if (enable)
- host->flags |= SDHCI_SDIO_IRQ_ENABLED;
- else
- host->flags &= ~SDHCI_SDIO_IRQ_ENABLED;
-
- /* SDIO IRQ will be enabled as appropriate in runtime resume */
- if (host->runtime_suspended)
- goto out;
-
- if (enable)
- sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT);
- else
- sdhci_mask_irqs(host, SDHCI_INT_CARD_INT);
-out:
- mmiowb();
-}
-
-static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
- struct sdhci_host *host = mmc_priv(mmc);
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- sdhci_enable_sdio_irq_nolock(host, enable);
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
- struct mmc_ios *ios)
-{
- u8 pwr;
- u16 clk, ctrl;
- u32 present_state;
-
- /*
- * Signal Voltage Switching is only applicable for Host Controllers
- * v3.00 and above.
- */
- if (host->version < SDHCI_SPEC_300)
- return 0;
-
- /*
- * We first check whether the request is to set signalling voltage
- * to 3.3V. If so, we change the voltage to 3.3V and return quickly.
- */
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
- /* Set 1.8V Signal Enable in the Host Control2 register to 0 */
- ctrl &= ~SDHCI_CTRL_VDD_180;
- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-
- /* Wait for 5ms */
- usleep_range(5000, 5500);
-
- /* 3.3V regulator output should be stable within 5 ms */
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- if (!(ctrl & SDHCI_CTRL_VDD_180))
- return 0;
- else {
- pr_info(DRIVER_NAME ": Switching to 3.3V "
- "signalling voltage failed\n");
- return -EIO;
- }
- } else if (!(ctrl & SDHCI_CTRL_VDD_180) &&
- (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)) {
- /* Stop SDCLK */
- clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
- clk &= ~SDHCI_CLOCK_CARD_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
- /* Check whether DAT[3:0] is 0000 */
- present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
- if (!((present_state & SDHCI_DATA_LVL_MASK) >>
- SDHCI_DATA_LVL_SHIFT)) {
- /*
- * Enable 1.8V Signal Enable in the Host Control2
- * register
- */
- ctrl |= SDHCI_CTRL_VDD_180;
- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-
- /* Wait for 5ms */
- usleep_range(5000, 5500);
-
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- if (ctrl & SDHCI_CTRL_VDD_180) {
- /* Provide SDCLK again and wait for 1ms*/
- clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
- clk |= SDHCI_CLOCK_CARD_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
- usleep_range(1000, 1500);
-
- /*
- * If DAT[3:0] level is 1111b, then the card
- * was successfully switched to 1.8V signaling.
- */
- present_state = sdhci_readl(host,
- SDHCI_PRESENT_STATE);
- if ((present_state & SDHCI_DATA_LVL_MASK) ==
- SDHCI_DATA_LVL_MASK)
- return 0;
- }
- }
-
- /*
- * If we are here, that means the switch to 1.8V signaling
- * failed. We power cycle the card, and retry initialization
- * sequence by setting S18R to 0.
- */
- pwr = sdhci_readb(host, SDHCI_POWER_CONTROL);
- pwr &= ~SDHCI_POWER_ON;
- sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
-
- /* Wait for 1ms as per the spec */
- usleep_range(1000, 1500);
- pwr |= SDHCI_POWER_ON;
- sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
-
- pr_info(DRIVER_NAME ": Switching to 1.8V signalling "
- "voltage failed, retrying with S18R set to 0\n");
- return -EAGAIN;
- } else
- /* No signal voltage switch required */
- return 0;
-}
-
-static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
- struct mmc_ios *ios)
-{
- struct sdhci_host *host = mmc_priv(mmc);
- int err;
-
- if (host->version < SDHCI_SPEC_300)
- return 0;
- sdhci_runtime_pm_get(host);
- err = sdhci_do_start_signal_voltage_switch(host, ios);
- sdhci_runtime_pm_put(host);
- return err;
-}
-
-static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
-{
- struct sdhci_host *host;
- u16 ctrl;
- u32 ier;
- int tuning_loop_counter = MAX_TUNING_LOOP;
- unsigned long timeout;
- int err = 0;
- bool requires_tuning_nonuhs = false;
-
- host = mmc_priv(mmc);
-
- sdhci_runtime_pm_get(host);
- disable_irq(host->irq);
- spin_lock(&host->lock);
-
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-
- /*
- * The Host Controller needs tuning only in case of SDR104 mode
- * and for SDR50 mode when Use Tuning for SDR50 is set in the
- * Capabilities register.
- * If the Host Controller supports the HS200 mode then the
- * tuning function has to be executed.
- */
- if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) &&
- (host->flags & SDHCI_SDR50_NEEDS_TUNING ||
- host->flags & SDHCI_HS200_NEEDS_TUNING))
- requires_tuning_nonuhs = true;
-
- if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) ||
- requires_tuning_nonuhs)
- ctrl |= SDHCI_CTRL_EXEC_TUNING;
- else {
- spin_unlock(&host->lock);
- enable_irq(host->irq);
- sdhci_runtime_pm_put(host);
- return 0;
- }
-
- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-
- /*
- * As per the Host Controller spec v3.00, tuning command
- * generates Buffer Read Ready interrupt, so enable that.
- *
- * Note: The spec clearly says that when tuning sequence
- * is being performed, the controller does not generate
- * interrupts other than Buffer Read Ready interrupt. But
- * to make sure we don't hit a controller bug, we _only_
- * enable Buffer Read Ready interrupt here.
- */
- ier = sdhci_readl(host, SDHCI_INT_ENABLE);
- sdhci_clear_set_irqs(host, ier, SDHCI_INT_DATA_AVAIL);
-
- /*
- * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
- * of loops reaches 40 times or a timeout of 150ms occurs.
- */
- timeout = 150;
- do {
- struct mmc_command cmd = {0};
- struct mmc_request mrq = {NULL};
-
- if (!tuning_loop_counter && !timeout)
- break;
-
- cmd.opcode = opcode;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
- cmd.retries = 0;
- cmd.data = NULL;
- cmd.error = 0;
-
- mrq.cmd = &cmd;
- host->mrq = &mrq;
-
- /*
- * In response to CMD19, the card sends 64 bytes of tuning
- * block to the Host Controller. So we set the block size
- * to 64 here.
- */
- if (cmd.opcode == MMC_SEND_TUNING_BLOCK_HS200) {
- if (mmc->ios.bus_width == MMC_BUS_WIDTH_8)
- sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 128),
- SDHCI_BLOCK_SIZE);
- else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4)
- sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64),
- SDHCI_BLOCK_SIZE);
- } else {
- sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64),
- SDHCI_BLOCK_SIZE);
- }
-
- /*
- * The tuning block is sent by the card to the host controller.
- * So we set the TRNS_READ bit in the Transfer Mode register.
- * This also takes care of setting DMA Enable and Multi Block
- * Select in the same register to 0.
- */
- sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
-
- sdhci_send_command(host, &cmd);
-
- host->cmd = NULL;
- host->mrq = NULL;
-
- spin_unlock(&host->lock);
- enable_irq(host->irq);
-
- /* Wait for Buffer Read Ready interrupt */
- wait_event_interruptible_timeout(host->buf_ready_int,
- (host->tuning_done == 1),
- msecs_to_jiffies(50));
- disable_irq(host->irq);
- spin_lock(&host->lock);
-
- if (!host->tuning_done) {
- pr_info(DRIVER_NAME ": Timeout waiting for "
- "Buffer Read Ready interrupt during tuning "
- "procedure, falling back to fixed sampling "
- "clock\n");
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- ctrl &= ~SDHCI_CTRL_TUNED_CLK;
- ctrl &= ~SDHCI_CTRL_EXEC_TUNING;
- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-
- err = -EIO;
- goto out;
- }
-
- host->tuning_done = 0;
-
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- tuning_loop_counter--;
- timeout--;
- mdelay(1);
- } while (ctrl & SDHCI_CTRL_EXEC_TUNING);
-
- /*
- * The Host Driver has exhausted the maximum number of loops allowed,
- * so use fixed sampling frequency.
- */
- if (!tuning_loop_counter || !timeout) {
- ctrl &= ~SDHCI_CTRL_TUNED_CLK;
- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
- } else {
- if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
- pr_info(DRIVER_NAME ": Tuning procedure"
- " failed, falling back to fixed sampling"
- " clock\n");
- err = -EIO;
- }
- }
-
-out:
- /*
- * If this is the very first time we are here, we start the retuning
- * timer. Since only during the first time, SDHCI_NEEDS_RETUNING
- * flag won't be set, we check this condition before actually starting
- * the timer.
- */
- if (!(host->flags & SDHCI_NEEDS_RETUNING) && host->tuning_count &&
- (host->tuning_mode == SDHCI_TUNING_MODE_1)) {
- mod_timer(&host->tuning_timer, jiffies +
- host->tuning_count * HZ);
- /* Tuning mode 1 limits the maximum data length to 4MB */
- mmc->max_blk_count = (4 * 1024 * 1024) / mmc->max_blk_size;
- } else {
- host->flags &= ~SDHCI_NEEDS_RETUNING;
- /* Reload the new initial value for timer */
- if (host->tuning_mode == SDHCI_TUNING_MODE_1)
- mod_timer(&host->tuning_timer, jiffies +
- host->tuning_count * HZ);
- }
-
- /*
- * In case tuning fails, host controllers which support re-tuning can
- * try tuning again at a later time, when the re-tuning timer expires.
- * So for these controllers, we return 0. Since there might be other
- * controllers who do not have this capability, we return error for
- * them.
- */
- if (err && host->tuning_count &&
- host->tuning_mode == SDHCI_TUNING_MODE_1)
- err = 0;
-
- sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier);
- spin_unlock(&host->lock);
- enable_irq(host->irq);
- sdhci_runtime_pm_put(host);
-
- return err;
-}
-
-static void sdhci_do_enable_preset_value(struct sdhci_host *host, bool enable)
-{
- u16 ctrl;
- unsigned long flags;
-
- /* Host Controller v3.00 defines preset value registers */
- if (host->version < SDHCI_SPEC_300)
- return;
-
- spin_lock_irqsave(&host->lock, flags);
-
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-
- /*
- * We only enable or disable Preset Value if they are not already
- * enabled or disabled respectively. Otherwise, we bail out.
- */
- if (enable && !(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
- ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE;
- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
- host->flags |= SDHCI_PV_ENABLED;
- } else if (!enable && (ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
- ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
- host->flags &= ~SDHCI_PV_ENABLED;
- }
-
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable)
-{
- struct sdhci_host *host = mmc_priv(mmc);
-
- sdhci_runtime_pm_get(host);
- sdhci_do_enable_preset_value(host, enable);
- sdhci_runtime_pm_put(host);
-}
-
-static const struct mmc_host_ops sdhci_ops = {
- .request = sdhci_request,
- .set_ios = sdhci_set_ios,
- .get_ro = sdhci_get_ro,
- .hw_reset = sdhci_hw_reset,
- .enable_sdio_irq = sdhci_enable_sdio_irq,
- .start_signal_voltage_switch = sdhci_start_signal_voltage_switch,
- .execute_tuning = sdhci_execute_tuning,
- .enable_preset_value = sdhci_enable_preset_value,
-};
-
-/*****************************************************************************\
- * *
- * Tasklets *
- * *
-\*****************************************************************************/
-
-static void sdhci_tasklet_card(unsigned long param)
-{
- struct sdhci_host *host;
- unsigned long flags;
-
- host = (struct sdhci_host*)param;
-
- spin_lock_irqsave(&host->lock, flags);
-
- /* Check host->mrq first in case we are runtime suspended */
- if (host->mrq &&
- !(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
- pr_err("%s: Card removed during transfer!\n",
- mmc_hostname(host->mmc));
- pr_err("%s: Resetting controller.\n",
- mmc_hostname(host->mmc));
-
- sdhci_reset(host, SDHCI_RESET_CMD);
- sdhci_reset(host, SDHCI_RESET_DATA);
-
- host->mrq->cmd->error = -ENOMEDIUM;
- tasklet_schedule(&host->finish_tasklet);
- }
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- mmc_detect_change(host->mmc, msecs_to_jiffies(200));
-}
-
-static void sdhci_tasklet_finish(unsigned long param)
-{
- struct sdhci_host *host;
- unsigned long flags;
- struct mmc_request *mrq;
-
- host = (struct sdhci_host*)param;
-
- spin_lock_irqsave(&host->lock, flags);
-
- /*
- * If this tasklet gets rescheduled while running, it will
- * be run again afterwards but without any active request.
- */
- if (!host->mrq) {
- spin_unlock_irqrestore(&host->lock, flags);
- return;
- }
-
- del_timer(&host->timer);
-
- mrq = host->mrq;
-
- /*
- * The controller needs a reset of internal state machines
- * upon error conditions.
- */
- if (!(host->flags & SDHCI_DEVICE_DEAD) &&
- ((mrq->cmd && mrq->cmd->error) ||
- (mrq->data && (mrq->data->error ||
- (mrq->data->stop && mrq->data->stop->error))) ||
- (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) {
-
- /* Some controllers need this kick or reset won't work here */
- if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) {
- unsigned int clock;
-
- /* This is to force an update */
- clock = host->clock;
- host->clock = 0;
- sdhci_set_clock(host, clock);
- }
-
- /* Spec says we should do both at the same time, but Ricoh
- controllers do not like that. */
- sdhci_reset(host, SDHCI_RESET_CMD);
- sdhci_reset(host, SDHCI_RESET_DATA);
- }
-
- host->mrq = NULL;
- host->cmd = NULL;
- host->data = NULL;
-
-#ifndef SDHCI_USE_LEDS_CLASS
- sdhci_deactivate_led(host);
-#endif
-
- mmiowb();
- spin_unlock_irqrestore(&host->lock, flags);
-
- mmc_request_done(host->mmc, mrq);
- sdhci_runtime_pm_put(host);
-}
-
-static void sdhci_timeout_timer(unsigned long data)
-{
- struct sdhci_host *host;
- unsigned long flags;
-
- host = (struct sdhci_host*)data;
-
- spin_lock_irqsave(&host->lock, flags);
-
- if (host->mrq) {
- pr_err("%s: Timeout waiting for hardware "
- "interrupt.\n", mmc_hostname(host->mmc));
- sdhci_dumpregs(host);
-
- if (host->data) {
- host->data->error = -ETIMEDOUT;
- sdhci_finish_data(host);
- } else {
- if (host->cmd)
- host->cmd->error = -ETIMEDOUT;
- else
- host->mrq->cmd->error = -ETIMEDOUT;
-
- tasklet_schedule(&host->finish_tasklet);
- }
- }
-
- mmiowb();
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void sdhci_tuning_timer(unsigned long data)
-{
- struct sdhci_host *host;
- unsigned long flags;
-
- host = (struct sdhci_host *)data;
-
- spin_lock_irqsave(&host->lock, flags);
-
- host->flags |= SDHCI_NEEDS_RETUNING;
-
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-/*****************************************************************************\
- * *
- * Interrupt handling *
- * *
-\*****************************************************************************/
-
-static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
-{
- BUG_ON(intmask == 0);
-
- if (!host->cmd) {
- pr_err("%s: Got command interrupt 0x%08x even "
- "though no command operation was in progress.\n",
- mmc_hostname(host->mmc), (unsigned)intmask);
- sdhci_dumpregs(host);
- return;
- }
-
- if (intmask & SDHCI_INT_TIMEOUT)
- host->cmd->error = -ETIMEDOUT;
- else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT |
- SDHCI_INT_INDEX))
- host->cmd->error = -EILSEQ;
-
- if (host->cmd->error) {
- tasklet_schedule(&host->finish_tasklet);
- return;
- }
-
- /*
- * The host can send and interrupt when the busy state has
- * ended, allowing us to wait without wasting CPU cycles.
- * Unfortunately this is overloaded on the "data complete"
- * interrupt, so we need to take some care when handling
- * it.
- *
- * Note: The 1.0 specification is a bit ambiguous about this
- * feature so there might be some problems with older
- * controllers.
- */
- if (host->cmd->flags & MMC_RSP_BUSY) {
- if (host->cmd->data)
- DBG("Cannot wait for busy signal when also "
- "doing a data transfer");
- else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ))
- return;
-
- /* The controller does not support the end-of-busy IRQ,
- * fall through and take the SDHCI_INT_RESPONSE */
- }
-
- if (intmask & SDHCI_INT_RESPONSE)
- sdhci_finish_command(host);
-}
-
-#ifdef CONFIG_MMC_DEBUG
-static void sdhci_show_adma_error(struct sdhci_host *host)
-{
- const char *name = mmc_hostname(host->mmc);
- u8 *desc = host->adma_desc;
- __le32 *dma;
- __le16 *len;
- u8 attr;
-
- sdhci_dumpregs(host);
-
- while (true) {
- dma = (__le32 *)(desc + 4);
- len = (__le16 *)(desc + 2);
- attr = *desc;
-
- DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
- name, desc, le32_to_cpu(*dma), le16_to_cpu(*len), attr);
-
- desc += 8;
-
- if (attr & 2)
- break;
- }
-}
-#else
-static void sdhci_show_adma_error(struct sdhci_host *host) { }
-#endif
-
-static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
-{
- u32 command;
- BUG_ON(intmask == 0);
-
- /* CMD19 generates _only_ Buffer Read Ready interrupt */
- if (intmask & SDHCI_INT_DATA_AVAIL) {
- command = SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND));
- if (command == MMC_SEND_TUNING_BLOCK ||
- command == MMC_SEND_TUNING_BLOCK_HS200) {
- host->tuning_done = 1;
- wake_up(&host->buf_ready_int);
- return;
- }
- }
-
- if (!host->data) {
- /*
- * The "data complete" interrupt is also used to
- * indicate that a busy state has ended. See comment
- * above in sdhci_cmd_irq().
- */
- if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) {
- if (intmask & SDHCI_INT_DATA_END) {
- sdhci_finish_command(host);
- return;
- }
- }
-
- pr_err("%s: Got data interrupt 0x%08x even "
- "though no data operation was in progress.\n",
- mmc_hostname(host->mmc), (unsigned)intmask);
- sdhci_dumpregs(host);
-
- return;
- }
-
- if (intmask & SDHCI_INT_DATA_TIMEOUT)
- host->data->error = -ETIMEDOUT;
- else if (intmask & SDHCI_INT_DATA_END_BIT)
- host->data->error = -EILSEQ;
- else if ((intmask & SDHCI_INT_DATA_CRC) &&
- SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND))
- != MMC_BUS_TEST_R)
- host->data->error = -EILSEQ;
- else if (intmask & SDHCI_INT_ADMA_ERROR) {
- pr_err("%s: ADMA error\n", mmc_hostname(host->mmc));
- sdhci_show_adma_error(host);
- host->data->error = -EIO;
- }
-
- if (host->data->error)
- sdhci_finish_data(host);
- else {
- if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
- sdhci_transfer_pio(host);
-
- /*
- * We currently don't do anything fancy with DMA
- * boundaries, but as we can't disable the feature
- * we need to at least restart the transfer.
- *
- * According to the spec sdhci_readl(host, SDHCI_DMA_ADDRESS)
- * should return a valid address to continue from, but as
- * some controllers are faulty, don't trust them.
- */
- if (intmask & SDHCI_INT_DMA_END) {
- u32 dmastart, dmanow;
- dmastart = sg_dma_address(host->data->sg);
- dmanow = dmastart + host->data->bytes_xfered;
- /*
- * Force update to the next DMA block boundary.
- */
- dmanow = (dmanow &
- ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
- SDHCI_DEFAULT_BOUNDARY_SIZE;
- host->data->bytes_xfered = dmanow - dmastart;
- DBG("%s: DMA base 0x%08x, transferred 0x%06x bytes,"
- " next 0x%08x\n",
- mmc_hostname(host->mmc), dmastart,
- host->data->bytes_xfered, dmanow);
- sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
- }
-
- if (intmask & SDHCI_INT_DATA_END) {
- if (host->cmd) {
- /*
- * Data managed to finish before the
- * command completed. Make sure we do
- * things in the proper order.
- */
- host->data_early = 1;
- } else {
- sdhci_finish_data(host);
- }
- }
- }
-}
-
-static irqreturn_t sdhci_irq(int irq, void *dev_id)
-{
- irqreturn_t result;
- struct sdhci_host *host = dev_id;
- u32 intmask, unexpected = 0;
- int cardint = 0, max_loops = 16;
-
- spin_lock(&host->lock);
-
- if (host->runtime_suspended) {
- spin_unlock(&host->lock);
- pr_warning("%s: got irq while runtime suspended\n",
- mmc_hostname(host->mmc));
- return IRQ_HANDLED;
- }
-
- intmask = sdhci_readl(host, SDHCI_INT_STATUS);
-
- if (!intmask || intmask == 0xffffffff) {
- result = IRQ_NONE;
- goto out;
- }
-
-again:
- DBG("*** %s got interrupt: 0x%08x\n",
- mmc_hostname(host->mmc), intmask);
-
- if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
- u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
- SDHCI_CARD_PRESENT;
-
- /*
- * There is a observation on i.mx esdhc. INSERT bit will be
- * immediately set again when it gets cleared, if a card is
- * inserted. We have to mask the irq to prevent interrupt
- * storm which will freeze the system. And the REMOVE gets
- * the same situation.
- *
- * More testing are needed here to ensure it works for other
- * platforms though.
- */
- sdhci_mask_irqs(host, present ? SDHCI_INT_CARD_INSERT :
- SDHCI_INT_CARD_REMOVE);
- sdhci_unmask_irqs(host, present ? SDHCI_INT_CARD_REMOVE :
- SDHCI_INT_CARD_INSERT);
-
- sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
- SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
- intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
- tasklet_schedule(&host->card_tasklet);
- }
-
- if (intmask & SDHCI_INT_CMD_MASK) {
- sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
- SDHCI_INT_STATUS);
- sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
- }
-
- if (intmask & SDHCI_INT_DATA_MASK) {
- sdhci_writel(host, intmask & SDHCI_INT_DATA_MASK,
- SDHCI_INT_STATUS);
- sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
- }
-
- intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
-
- intmask &= ~SDHCI_INT_ERROR;
-
- if (intmask & SDHCI_INT_BUS_POWER) {
- pr_err("%s: Card is consuming too much power!\n",
- mmc_hostname(host->mmc));
- sdhci_writel(host, SDHCI_INT_BUS_POWER, SDHCI_INT_STATUS);
- }
-
- intmask &= ~SDHCI_INT_BUS_POWER;
-
- if (intmask & SDHCI_INT_CARD_INT)
- cardint = 1;
-
- intmask &= ~SDHCI_INT_CARD_INT;
-
- if (intmask) {
- unexpected |= intmask;
- sdhci_writel(host, intmask, SDHCI_INT_STATUS);
- }
-
- result = IRQ_HANDLED;
-
- intmask = sdhci_readl(host, SDHCI_INT_STATUS);
- if (intmask && --max_loops)
- goto again;
-out:
- spin_unlock(&host->lock);
-
- if (unexpected) {
- pr_err("%s: Unexpected interrupt 0x%08x.\n",
- mmc_hostname(host->mmc), unexpected);
- sdhci_dumpregs(host);
- }
- /*
- * We have to delay this as it calls back into the driver.
- */
- if (cardint)
- mmc_signal_sdio_irq(host->mmc);
-
- return result;
-}
-
-/*****************************************************************************\
- * *
- * Suspend/resume *
- * *
-\*****************************************************************************/
-
-#ifdef CONFIG_PM
-
-int sdhci_suspend_host(struct sdhci_host *host)
-{
- int ret;
- bool has_tuning_timer;
-
- if (host->ops->platform_suspend)
- host->ops->platform_suspend(host);
-
- sdhci_disable_card_detection(host);
-
- /* Disable tuning since we are suspending */
- has_tuning_timer = host->version >= SDHCI_SPEC_300 &&
- host->tuning_count && host->tuning_mode == SDHCI_TUNING_MODE_1;
- if (has_tuning_timer) {
- del_timer_sync(&host->tuning_timer);
- host->flags &= ~SDHCI_NEEDS_RETUNING;
- }
-
- ret = mmc_suspend_host(host->mmc);
- if (ret) {
- if (has_tuning_timer) {
- host->flags |= SDHCI_NEEDS_RETUNING;
- mod_timer(&host->tuning_timer, jiffies +
- host->tuning_count * HZ);
- }
-
- sdhci_enable_card_detection(host);
-
- return ret;
- }
-
- free_irq(host->irq, host);
-
- return ret;
-}
-
-EXPORT_SYMBOL_GPL(sdhci_suspend_host);
-
-int sdhci_resume_host(struct sdhci_host *host)
-{
- int ret;
-
- if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
- if (host->ops->enable_dma)
- host->ops->enable_dma(host);
- }
-
- ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
- mmc_hostname(host->mmc), host);
- if (ret)
- return ret;
-
- if ((host->mmc->pm_flags & MMC_PM_KEEP_POWER) &&
- (host->quirks2 & SDHCI_QUIRK2_HOST_OFF_CARD_ON)) {
- /* Card keeps power but host controller does not */
- sdhci_init(host, 0);
- host->pwr = 0;
- host->clock = 0;
- sdhci_do_set_ios(host, &host->mmc->ios);
- } else {
- sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER));
- mmiowb();
- }
-
- ret = mmc_resume_host(host->mmc);
- sdhci_enable_card_detection(host);
-
- if (host->ops->platform_resume)
- host->ops->platform_resume(host);
-
- /* Set the re-tuning expiration flag */
- if ((host->version >= SDHCI_SPEC_300) && host->tuning_count &&
- (host->tuning_mode == SDHCI_TUNING_MODE_1))
- host->flags |= SDHCI_NEEDS_RETUNING;
-
- return ret;
-}
-
-EXPORT_SYMBOL_GPL(sdhci_resume_host);
-
-void sdhci_enable_irq_wakeups(struct sdhci_host *host)
-{
- u8 val;
- val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL);
- val |= SDHCI_WAKE_ON_INT;
- sdhci_writeb(host, val, SDHCI_WAKE_UP_CONTROL);
-}
-
-EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups);
-
-#endif /* CONFIG_PM */
-
-#ifdef CONFIG_PM_RUNTIME
-
-static int sdhci_runtime_pm_get(struct sdhci_host *host)
-{
- return pm_runtime_get_sync(host->mmc->parent);
-}
-
-static int sdhci_runtime_pm_put(struct sdhci_host *host)
-{
- pm_runtime_mark_last_busy(host->mmc->parent);
- return pm_runtime_put_autosuspend(host->mmc->parent);
-}
-
-int sdhci_runtime_suspend_host(struct sdhci_host *host)
-{
- unsigned long flags;
- int ret = 0;
-
- /* Disable tuning since we are suspending */
- if (host->version >= SDHCI_SPEC_300 &&
- host->tuning_mode == SDHCI_TUNING_MODE_1) {
- del_timer_sync(&host->tuning_timer);
- host->flags &= ~SDHCI_NEEDS_RETUNING;
- }
-
- spin_lock_irqsave(&host->lock, flags);
- sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
- spin_unlock_irqrestore(&host->lock, flags);
-
- synchronize_irq(host->irq);
-
- spin_lock_irqsave(&host->lock, flags);
- host->runtime_suspended = true;
- spin_unlock_irqrestore(&host->lock, flags);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(sdhci_runtime_suspend_host);
-
-int sdhci_runtime_resume_host(struct sdhci_host *host)
-{
- unsigned long flags;
- int ret = 0, host_flags = host->flags;
-
- if (host_flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
- if (host->ops->enable_dma)
- host->ops->enable_dma(host);
- }
-
- sdhci_init(host, 0);
-
- /* Force clock and power re-program */
- host->pwr = 0;
- host->clock = 0;
- sdhci_do_set_ios(host, &host->mmc->ios);
-
- sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios);
- if (host_flags & SDHCI_PV_ENABLED)
- sdhci_do_enable_preset_value(host, true);
-
- /* Set the re-tuning expiration flag */
- if ((host->version >= SDHCI_SPEC_300) && host->tuning_count &&
- (host->tuning_mode == SDHCI_TUNING_MODE_1))
- host->flags |= SDHCI_NEEDS_RETUNING;
-
- spin_lock_irqsave(&host->lock, flags);
-
- host->runtime_suspended = false;
-
- /* Enable SDIO IRQ */
- if ((host->flags & SDHCI_SDIO_IRQ_ENABLED))
- sdhci_enable_sdio_irq_nolock(host, true);
-
- /* Enable Card Detection */
- sdhci_enable_card_detection(host);
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host);
-
-#endif
-
-/*****************************************************************************\
- * *
- * Device allocation/registration *
- * *
-\*****************************************************************************/
-
-struct sdhci_host *sdhci_alloc_host(struct device *dev,
- size_t priv_size)
-{
- struct mmc_host *mmc;
- struct sdhci_host *host;
-
- WARN_ON(dev == NULL);
-
- mmc = mmc_alloc_host(sizeof(struct sdhci_host) + priv_size, dev);
- if (!mmc)
- return ERR_PTR(-ENOMEM);
-
- host = mmc_priv(mmc);
- host->mmc = mmc;
-
- return host;
-}
-
-EXPORT_SYMBOL_GPL(sdhci_alloc_host);
-
-int sdhci_add_host(struct sdhci_host *host)
-{
- struct mmc_host *mmc;
- u32 caps[2];
- u32 max_current_caps;
- unsigned int ocr_avail;
- int ret;
-
- WARN_ON(host == NULL);
- if (host == NULL)
- return -EINVAL;
-
- mmc = host->mmc;
-
- if (debug_quirks)
- host->quirks = debug_quirks;
- if (debug_quirks2)
- host->quirks2 = debug_quirks2;
-
- sdhci_reset(host, SDHCI_RESET_ALL);
-
- 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_300) {
- pr_err("%s: Unknown controller version (%d). "
- "You may experience problems.\n", mmc_hostname(mmc),
- host->version);
- }
-
- caps[0] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
- sdhci_readl(host, SDHCI_CAPABILITIES);
-
- caps[1] = (host->version >= SDHCI_SPEC_300) ?
- sdhci_readl(host, SDHCI_CAPABILITIES_1) : 0;
-
- if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
- host->flags |= SDHCI_USE_SDMA;
- else if (!(caps[0] & SDHCI_CAN_DO_SDMA))
- DBG("Controller doesn't have SDMA capability\n");
- else
- host->flags |= SDHCI_USE_SDMA;
-
- if ((host->quirks & SDHCI_QUIRK_BROKEN_DMA) &&
- (host->flags & SDHCI_USE_SDMA)) {
- DBG("Disabling DMA as it is marked broken\n");
- host->flags &= ~SDHCI_USE_SDMA;
- }
-
- if ((host->version >= SDHCI_SPEC_200) &&
- (caps[0] & SDHCI_CAN_DO_ADMA2))
- host->flags |= SDHCI_USE_ADMA;
-
- if ((host->quirks & SDHCI_QUIRK_BROKEN_ADMA) &&
- (host->flags & SDHCI_USE_ADMA)) {
- DBG("Disabling ADMA as it is marked broken\n");
- host->flags &= ~SDHCI_USE_ADMA;
- }
-
- if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
- if (host->ops->enable_dma) {
- if (host->ops->enable_dma(host)) {
- pr_warning("%s: No suitable DMA "
- "available. Falling back to PIO.\n",
- mmc_hostname(mmc));
- host->flags &=
- ~(SDHCI_USE_SDMA | SDHCI_USE_ADMA);
- }
- }
- }
-
- if (host->flags & SDHCI_USE_ADMA) {
- /*
- * We need to allocate descriptors for all sg entries
- * (128) and potentially one alignment transfer for
- * each of those entries.
- */
- host->adma_desc = kmalloc((128 * 2 + 1) * 4, GFP_KERNEL);
- host->align_buffer = kmalloc(128 * 4, GFP_KERNEL);
- if (!host->adma_desc || !host->align_buffer) {
- kfree(host->adma_desc);
- kfree(host->align_buffer);
- pr_warning("%s: Unable to allocate ADMA "
- "buffers. Falling back to standard DMA.\n",
- mmc_hostname(mmc));
- host->flags &= ~SDHCI_USE_ADMA;
- }
- }
-
- /*
- * If we use DMA, then it's up to the caller to set the DMA
- * mask, but PIO does not need the hw shim so we set a new
- * mask here in that case.
- */
- if (!(host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))) {
- host->dma_mask = DMA_BIT_MASK(64);
- mmc_dev(host->mmc)->dma_mask = &host->dma_mask;
- }
-
- if (host->version >= SDHCI_SPEC_300)
- host->max_clk = (caps[0] & SDHCI_CLOCK_V3_BASE_MASK)
- >> SDHCI_CLOCK_BASE_SHIFT;
- else
- host->max_clk = (caps[0] & 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) {
- if (!host->ops->get_max_clock) {
- pr_err("%s: Hardware doesn't specify base clock "
- "frequency.\n", mmc_hostname(mmc));
- return -ENODEV;
- }
- host->max_clk = host->ops->get_max_clock(host);
- }
-
- /*
- * In case of Host Controller v3.00, find out whether clock
- * multiplier is supported.
- */
- host->clk_mul = (caps[1] & SDHCI_CLOCK_MUL_MASK) >>
- SDHCI_CLOCK_MUL_SHIFT;
-
- /*
- * In case the value in Clock Multiplier is 0, then programmable
- * clock mode is not supported, otherwise the actual clock
- * multiplier is one more than the value of Clock Multiplier
- * in the Capabilities Register.
- */
- if (host->clk_mul)
- host->clk_mul += 1;
-
- /*
- * Set host parameters.
- */
- mmc->ops = &sdhci_ops;
- mmc->f_max = host->max_clk;
- if (host->ops->get_min_clock)
- mmc->f_min = host->ops->get_min_clock(host);
- else if (host->version >= SDHCI_SPEC_300) {
- if (host->clk_mul) {
- mmc->f_min = (host->max_clk * host->clk_mul) / 1024;
- mmc->f_max = host->max_clk * host->clk_mul;
- } else
- mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
- } else
- mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
-
- host->timeout_clk =
- (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
- if (host->timeout_clk == 0) {
- if (host->ops->get_timeout_clock) {
- host->timeout_clk = host->ops->get_timeout_clock(host);
- } else if (!(host->quirks &
- SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
- pr_err("%s: Hardware doesn't specify timeout clock "
- "frequency.\n", mmc_hostname(mmc));
- return -ENODEV;
- }
- }
- if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT)
- host->timeout_clk *= 1000;
-
- if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
- host->timeout_clk = mmc->f_max / 1000;
-
- mmc->max_discard_to = (1 << 27) / host->timeout_clk;
-
- mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
-
- if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
- host->flags |= SDHCI_AUTO_CMD12;
-
- /* Auto-CMD23 stuff only works in ADMA or PIO. */
- if ((host->version >= SDHCI_SPEC_300) &&
- ((host->flags & SDHCI_USE_ADMA) ||
- !(host->flags & SDHCI_USE_SDMA))) {
- host->flags |= SDHCI_AUTO_CMD23;
- DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc));
- } else {
- DBG("%s: Auto-CMD23 unavailable\n", mmc_hostname(mmc));
- }
-
- /*
- * A controller may support 8-bit width, but the board itself
- * might not have the pins brought out. Boards that support
- * 8-bit width must set "mmc->caps |= MMC_CAP_8_BIT_DATA;" in
- * their platform code before calling sdhci_add_host(), and we
- * won't assume 8-bit width for hosts without that CAP.
- */
- if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
- mmc->caps |= MMC_CAP_4_BIT_DATA;
-
- if (caps[0] & SDHCI_CAN_DO_HISPD)
- mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
-
- if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
- mmc_card_is_removable(mmc))
- mmc->caps |= MMC_CAP_NEEDS_POLL;
-
- /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */
- if (caps[1] & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
- SDHCI_SUPPORT_DDR50))
- mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
-
- /* SDR104 supports also implies SDR50 support */
- if (caps[1] & SDHCI_SUPPORT_SDR104)
- mmc->caps |= MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50;
- else if (caps[1] & SDHCI_SUPPORT_SDR50)
- mmc->caps |= MMC_CAP_UHS_SDR50;
-
- if (caps[1] & SDHCI_SUPPORT_DDR50)
- mmc->caps |= MMC_CAP_UHS_DDR50;
-
- /* Does the host need tuning for SDR50? */
- if (caps[1] & SDHCI_USE_SDR50_TUNING)
- host->flags |= SDHCI_SDR50_NEEDS_TUNING;
-
- /* Does the host need tuning for HS200? */
- if (mmc->caps2 & MMC_CAP2_HS200)
- host->flags |= SDHCI_HS200_NEEDS_TUNING;
-
- /* Driver Type(s) (A, C, D) supported by the host */
- if (caps[1] & SDHCI_DRIVER_TYPE_A)
- mmc->caps |= MMC_CAP_DRIVER_TYPE_A;
- if (caps[1] & SDHCI_DRIVER_TYPE_C)
- mmc->caps |= MMC_CAP_DRIVER_TYPE_C;
- if (caps[1] & SDHCI_DRIVER_TYPE_D)
- mmc->caps |= MMC_CAP_DRIVER_TYPE_D;
-
- /*
- * If Power Off Notify capability is enabled by the host,
- * set notify to short power off notify timeout value.
- */
- if (mmc->caps2 & MMC_CAP2_POWEROFF_NOTIFY)
- mmc->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT;
- else
- mmc->power_notify_type = MMC_HOST_PW_NOTIFY_NONE;
-
- /* Initial value for re-tuning timer count */
- host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >>
- SDHCI_RETUNING_TIMER_COUNT_SHIFT;
-
- /*
- * In case Re-tuning Timer is not disabled, the actual value of
- * re-tuning timer will be 2 ^ (n - 1).
- */
- if (host->tuning_count)
- host->tuning_count = 1 << (host->tuning_count - 1);
-
- /* Re-tuning mode supported by the Host Controller */
- host->tuning_mode = (caps[1] & SDHCI_RETUNING_MODE_MASK) >>
- SDHCI_RETUNING_MODE_SHIFT;
-
- ocr_avail = 0;
- /*
- * According to SD Host Controller spec v3.00, if the Host System
- * can afford more than 150mA, Host Driver should set XPC to 1. Also
- * the value is meaningful only if Voltage Support in the Capabilities
- * register is set. The actual current value is 4 times the register
- * value.
- */
- max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT);
-
- if (caps[0] & SDHCI_CAN_VDD_330) {
- int max_current_330;
-
- ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;
-
- max_current_330 = ((max_current_caps &
- SDHCI_MAX_CURRENT_330_MASK) >>
- SDHCI_MAX_CURRENT_330_SHIFT) *
- SDHCI_MAX_CURRENT_MULTIPLIER;
-
- if (max_current_330 > 150)
- mmc->caps |= MMC_CAP_SET_XPC_330;
- }
- if (caps[0] & SDHCI_CAN_VDD_300) {
- int max_current_300;
-
- ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31;
-
- max_current_300 = ((max_current_caps &
- SDHCI_MAX_CURRENT_300_MASK) >>
- SDHCI_MAX_CURRENT_300_SHIFT) *
- SDHCI_MAX_CURRENT_MULTIPLIER;
-
- if (max_current_300 > 150)
- mmc->caps |= MMC_CAP_SET_XPC_300;
- }
- if (caps[0] & SDHCI_CAN_VDD_180) {
- int max_current_180;
-
- ocr_avail |= MMC_VDD_165_195;
-
- max_current_180 = ((max_current_caps &
- SDHCI_MAX_CURRENT_180_MASK) >>
- SDHCI_MAX_CURRENT_180_SHIFT) *
- SDHCI_MAX_CURRENT_MULTIPLIER;
-
- if (max_current_180 > 150)
- mmc->caps |= MMC_CAP_SET_XPC_180;
-
- /* Maximum current capabilities of the host at 1.8V */
- if (max_current_180 >= 800)
- mmc->caps |= MMC_CAP_MAX_CURRENT_800;
- else if (max_current_180 >= 600)
- mmc->caps |= MMC_CAP_MAX_CURRENT_600;
- else if (max_current_180 >= 400)
- mmc->caps |= MMC_CAP_MAX_CURRENT_400;
- else
- mmc->caps |= MMC_CAP_MAX_CURRENT_200;
- }
-
- mmc->ocr_avail = ocr_avail;
- mmc->ocr_avail_sdio = ocr_avail;
- if (host->ocr_avail_sdio)
- mmc->ocr_avail_sdio &= host->ocr_avail_sdio;
- mmc->ocr_avail_sd = ocr_avail;
- if (host->ocr_avail_sd)
- mmc->ocr_avail_sd &= host->ocr_avail_sd;
- else /* normal SD controllers don't support 1.8V */
- mmc->ocr_avail_sd &= ~MMC_VDD_165_195;
- mmc->ocr_avail_mmc = ocr_avail;
- if (host->ocr_avail_mmc)
- mmc->ocr_avail_mmc &= host->ocr_avail_mmc;
-
- if (mmc->ocr_avail == 0) {
- pr_err("%s: Hardware doesn't report any "
- "support voltages.\n", mmc_hostname(mmc));
- return -ENODEV;
- }
-
- spin_lock_init(&host->lock);
-
- /*
- * Maximum number of segments. Depends on if the hardware
- * can do scatter/gather or not.
- */
- if (host->flags & SDHCI_USE_ADMA)
- mmc->max_segs = 128;
- else if (host->flags & SDHCI_USE_SDMA)
- mmc->max_segs = 1;
- else /* PIO */
- mmc->max_segs = 128;
-
- /*
- * Maximum number of sectors in one transfer. Limited by DMA boundary
- * size (512KiB).
- */
- mmc->max_req_size = 524288;
-
- /*
- * Maximum segment size. Could be one segment with the maximum number
- * of bytes. When doing hardware scatter/gather, each entry cannot
- * be larger than 64 KiB though.
- */
- if (host->flags & SDHCI_USE_ADMA) {
- if (host->quirks & SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC)
- mmc->max_seg_size = 65535;
- else
- mmc->max_seg_size = 65536;
- } else {
- mmc->max_seg_size = mmc->max_req_size;
- }
-
- /*
- * Maximum block size. This varies from controller to controller and
- * is specified in the capabilities register.
- */
- if (host->quirks & SDHCI_QUIRK_FORCE_BLK_SZ_2048) {
- mmc->max_blk_size = 2;
- } else {
- mmc->max_blk_size = (caps[0] & SDHCI_MAX_BLOCK_MASK) >>
- SDHCI_MAX_BLOCK_SHIFT;
- if (mmc->max_blk_size >= 3) {
- pr_warning("%s: Invalid maximum block size, "
- "assuming 512 bytes\n", mmc_hostname(mmc));
- mmc->max_blk_size = 0;
- }
- }
-
- mmc->max_blk_size = 512 << mmc->max_blk_size;
-
- /*
- * Maximum block count.
- */
- mmc->max_blk_count = (host->quirks & SDHCI_QUIRK_NO_MULTIBLOCK) ? 1 : 65535;
-
- /*
- * Init tasklets.
- */
- tasklet_init(&host->card_tasklet,
- sdhci_tasklet_card, (unsigned long)host);
- tasklet_init(&host->finish_tasklet,
- sdhci_tasklet_finish, (unsigned long)host);
-
- setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
-
- if (host->version >= SDHCI_SPEC_300) {
- init_waitqueue_head(&host->buf_ready_int);
-
- /* Initialize re-tuning timer */
- init_timer(&host->tuning_timer);
- host->tuning_timer.data = (unsigned long)host;
- host->tuning_timer.function = sdhci_tuning_timer;
- }
-
- ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
- mmc_hostname(mmc), host);
- if (ret)
- goto untasklet;
-
- host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
- if (IS_ERR(host->vmmc)) {
- pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
- host->vmmc = NULL;
- }
-
- sdhci_init(host, 0);
-
-#ifdef CONFIG_MMC_DEBUG
- sdhci_dumpregs(host);
-#endif
-
-#ifdef SDHCI_USE_LEDS_CLASS
- snprintf(host->led_name, sizeof(host->led_name),
- "%s::", mmc_hostname(mmc));
- host->led.name = host->led_name;
- host->led.brightness = LED_OFF;
- host->led.default_trigger = mmc_hostname(mmc);
- host->led.brightness_set = sdhci_led_control;
-
- ret = led_classdev_register(mmc_dev(mmc), &host->led);
- if (ret)
- goto reset;
-#endif
-
- mmiowb();
-
- mmc_add_host(mmc);
-
- pr_info("%s: SDHCI controller on %s [%s] using %s\n",
- mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
- (host->flags & SDHCI_USE_ADMA) ? "ADMA" :
- (host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO");
-
- sdhci_enable_card_detection(host);
-
- return 0;
-
-#ifdef SDHCI_USE_LEDS_CLASS
-reset:
- sdhci_reset(host, SDHCI_RESET_ALL);
- free_irq(host->irq, host);
-#endif
-untasklet:
- tasklet_kill(&host->card_tasklet);
- tasklet_kill(&host->finish_tasklet);
-
- return ret;
-}
-
-EXPORT_SYMBOL_GPL(sdhci_add_host);
-
-void sdhci_remove_host(struct sdhci_host *host, int dead)
-{
- unsigned long flags;
-
- if (dead) {
- spin_lock_irqsave(&host->lock, flags);
-
- host->flags |= SDHCI_DEVICE_DEAD;
-
- if (host->mrq) {
- pr_err("%s: Controller removed during "
- " transfer!\n", mmc_hostname(host->mmc));
-
- host->mrq->cmd->error = -ENOMEDIUM;
- tasklet_schedule(&host->finish_tasklet);
- }
-
- spin_unlock_irqrestore(&host->lock, flags);
- }
-
- sdhci_disable_card_detection(host);
-
- mmc_remove_host(host->mmc);
-
-#ifdef SDHCI_USE_LEDS_CLASS
- led_classdev_unregister(&host->led);
-#endif
-
- if (!dead)
- sdhci_reset(host, SDHCI_RESET_ALL);
-
- free_irq(host->irq, host);
-
- del_timer_sync(&host->timer);
- if (host->version >= SDHCI_SPEC_300)
- del_timer_sync(&host->tuning_timer);
-
- tasklet_kill(&host->card_tasklet);
- tasklet_kill(&host->finish_tasklet);
-
- if (host->vmmc)
- regulator_put(host->vmmc);
-
- kfree(host->adma_desc);
- kfree(host->align_buffer);
-
- host->adma_desc = NULL;
- host->align_buffer = NULL;
-}
-
-EXPORT_SYMBOL_GPL(sdhci_remove_host);
-
-void sdhci_free_host(struct sdhci_host *host)
-{
- mmc_free_host(host->mmc);
-}
-
-EXPORT_SYMBOL_GPL(sdhci_free_host);
-
-/*****************************************************************************\
- * *
- * Driver init/exit *
- * *
-\*****************************************************************************/
-
-static int __init sdhci_drv_init(void)
-{
- pr_info(DRIVER_NAME
- ": Secure Digital Host Controller Interface driver\n");
- pr_info(DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
-
- return 0;
-}
-
-static void __exit sdhci_drv_exit(void)
-{
-}
-
-module_init(sdhci_drv_init);
-module_exit(sdhci_drv_exit);
-
-module_param(debug_quirks, uint, 0444);
-module_param(debug_quirks2, uint, 0444);
-
-MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>");
-MODULE_DESCRIPTION("Secure Digital Host Controller Interface core driver");
-MODULE_LICENSE("GPL");
-
-MODULE_PARM_DESC(debug_quirks, "Force certain quirks.");
-MODULE_PARM_DESC(debug_quirks2, "Force certain other quirks.");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdhci.h b/ANDROID_3.4.5/drivers/mmc/host/sdhci.h
deleted file mode 100644
index f761f23d..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sdhci.h
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * 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
- * 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_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_DMA_ADDRESS 0x00
-#define SDHCI_ARGUMENT2 SDHCI_DMA_ADDRESS
-
-#define SDHCI_BLOCK_SIZE 0x04
-#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
-
-#define SDHCI_BLOCK_COUNT 0x06
-
-#define SDHCI_ARGUMENT 0x08
-
-#define SDHCI_TRANSFER_MODE 0x0C
-#define SDHCI_TRNS_DMA 0x01
-#define SDHCI_TRNS_BLK_CNT_EN 0x02
-#define SDHCI_TRNS_AUTO_CMD12 0x04
-#define SDHCI_TRNS_AUTO_CMD23 0x08
-#define SDHCI_TRNS_READ 0x10
-#define SDHCI_TRNS_MULTI 0x20
-
-#define SDHCI_COMMAND 0x0E
-#define SDHCI_CMD_RESP_MASK 0x03
-#define SDHCI_CMD_CRC 0x08
-#define SDHCI_CMD_INDEX 0x10
-#define SDHCI_CMD_DATA 0x20
-#define SDHCI_CMD_ABORTCMD 0xC0
-
-#define SDHCI_CMD_RESP_NONE 0x00
-#define SDHCI_CMD_RESP_LONG 0x01
-#define SDHCI_CMD_RESP_SHORT 0x02
-#define SDHCI_CMD_RESP_SHORT_BUSY 0x03
-
-#define SDHCI_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff))
-#define SDHCI_GET_CMD(c) ((c>>8) & 0x3f)
-
-#define SDHCI_RESPONSE 0x10
-
-#define SDHCI_BUFFER 0x20
-
-#define SDHCI_PRESENT_STATE 0x24
-#define SDHCI_CMD_INHIBIT 0x00000001
-#define SDHCI_DATA_INHIBIT 0x00000002
-#define SDHCI_DOING_WRITE 0x00000100
-#define SDHCI_DOING_READ 0x00000200
-#define SDHCI_SPACE_AVAILABLE 0x00000400
-#define SDHCI_DATA_AVAILABLE 0x00000800
-#define SDHCI_CARD_PRESENT 0x00010000
-#define SDHCI_WRITE_PROTECT 0x00080000
-#define SDHCI_DATA_LVL_MASK 0x00F00000
-#define SDHCI_DATA_LVL_SHIFT 20
-
-#define SDHCI_HOST_CONTROL 0x28
-#define SDHCI_CTRL_LED 0x01
-#define SDHCI_CTRL_4BITBUS 0x02
-#define SDHCI_CTRL_HISPD 0x04
-#define SDHCI_CTRL_DMA_MASK 0x18
-#define SDHCI_CTRL_SDMA 0x00
-#define SDHCI_CTRL_ADMA1 0x08
-#define SDHCI_CTRL_ADMA32 0x10
-#define SDHCI_CTRL_ADMA64 0x18
-#define SDHCI_CTRL_8BITBUS 0x20
-
-#define SDHCI_POWER_CONTROL 0x29
-#define SDHCI_POWER_ON 0x01
-#define SDHCI_POWER_180 0x0A
-#define SDHCI_POWER_300 0x0C
-#define SDHCI_POWER_330 0x0E
-
-#define SDHCI_BLOCK_GAP_CONTROL 0x2A
-
-#define SDHCI_WAKE_UP_CONTROL 0x2B
-#define SDHCI_WAKE_ON_INT 0x01
-#define SDHCI_WAKE_ON_INSERT 0x02
-#define SDHCI_WAKE_ON_REMOVE 0x04
-
-#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_PROG_CLOCK_MODE 0x0020
-#define SDHCI_CLOCK_CARD_EN 0x0004
-#define SDHCI_CLOCK_INT_STABLE 0x0002
-#define SDHCI_CLOCK_INT_EN 0x0001
-
-#define SDHCI_TIMEOUT_CONTROL 0x2E
-
-#define SDHCI_SOFTWARE_RESET 0x2F
-#define SDHCI_RESET_ALL 0x01
-#define SDHCI_RESET_CMD 0x02
-#define SDHCI_RESET_DATA 0x04
-
-#define SDHCI_INT_STATUS 0x30
-#define SDHCI_INT_ENABLE 0x34
-#define SDHCI_SIGNAL_ENABLE 0x38
-#define SDHCI_INT_RESPONSE 0x00000001
-#define SDHCI_INT_DATA_END 0x00000002
-#define SDHCI_INT_DMA_END 0x00000008
-#define SDHCI_INT_SPACE_AVAIL 0x00000010
-#define SDHCI_INT_DATA_AVAIL 0x00000020
-#define SDHCI_INT_CARD_INSERT 0x00000040
-#define SDHCI_INT_CARD_REMOVE 0x00000080
-#define SDHCI_INT_CARD_INT 0x00000100
-#define SDHCI_INT_ERROR 0x00008000
-#define SDHCI_INT_TIMEOUT 0x00010000
-#define SDHCI_INT_CRC 0x00020000
-#define SDHCI_INT_END_BIT 0x00040000
-#define SDHCI_INT_INDEX 0x00080000
-#define SDHCI_INT_DATA_TIMEOUT 0x00100000
-#define SDHCI_INT_DATA_CRC 0x00200000
-#define SDHCI_INT_DATA_END_BIT 0x00400000
-#define SDHCI_INT_BUS_POWER 0x00800000
-#define SDHCI_INT_ACMD12ERR 0x01000000
-#define SDHCI_INT_ADMA_ERROR 0x02000000
-
-#define SDHCI_INT_NORMAL_MASK 0x00007FFF
-#define SDHCI_INT_ERROR_MASK 0xFFFF8000
-
-#define SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \
- SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)
-#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
- SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
- SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
- SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR)
-#define SDHCI_INT_ALL_MASK ((unsigned int)-1)
-
-#define SDHCI_ACMD12_ERR 0x3C
-
-#define SDHCI_HOST_CONTROL2 0x3E
-#define SDHCI_CTRL_UHS_MASK 0x0007
-#define SDHCI_CTRL_UHS_SDR12 0x0000
-#define SDHCI_CTRL_UHS_SDR25 0x0001
-#define SDHCI_CTRL_UHS_SDR50 0x0002
-#define SDHCI_CTRL_UHS_SDR104 0x0003
-#define SDHCI_CTRL_UHS_DDR50 0x0004
-#define SDHCI_CTRL_HS_SDR200 0x0005 /* reserved value in SDIO spec */
-#define SDHCI_CTRL_VDD_180 0x0008
-#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030
-#define SDHCI_CTRL_DRV_TYPE_B 0x0000
-#define SDHCI_CTRL_DRV_TYPE_A 0x0010
-#define SDHCI_CTRL_DRV_TYPE_C 0x0020
-#define SDHCI_CTRL_DRV_TYPE_D 0x0030
-#define SDHCI_CTRL_EXEC_TUNING 0x0040
-#define SDHCI_CTRL_TUNED_CLK 0x0080
-#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000
-
-#define SDHCI_CAPABILITIES 0x40
-#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F
-#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_CAN_DO_8BIT 0x00040000
-#define SDHCI_CAN_DO_ADMA2 0x00080000
-#define SDHCI_CAN_DO_ADMA1 0x00100000
-#define SDHCI_CAN_DO_HISPD 0x00200000
-#define SDHCI_CAN_DO_SDMA 0x00400000
-#define SDHCI_CAN_VDD_330 0x01000000
-#define SDHCI_CAN_VDD_300 0x02000000
-#define SDHCI_CAN_VDD_180 0x04000000
-#define SDHCI_CAN_64BIT 0x10000000
-
-#define SDHCI_SUPPORT_SDR50 0x00000001
-#define SDHCI_SUPPORT_SDR104 0x00000002
-#define SDHCI_SUPPORT_DDR50 0x00000004
-#define SDHCI_DRIVER_TYPE_A 0x00000010
-#define SDHCI_DRIVER_TYPE_C 0x00000020
-#define SDHCI_DRIVER_TYPE_D 0x00000040
-#define SDHCI_RETUNING_TIMER_COUNT_MASK 0x00000F00
-#define SDHCI_RETUNING_TIMER_COUNT_SHIFT 8
-#define SDHCI_USE_SDR50_TUNING 0x00002000
-#define SDHCI_RETUNING_MODE_MASK 0x0000C000
-#define SDHCI_RETUNING_MODE_SHIFT 14
-#define SDHCI_CLOCK_MUL_MASK 0x00FF0000
-#define SDHCI_CLOCK_MUL_SHIFT 16
-
-#define SDHCI_CAPABILITIES_1 0x44
-
-#define SDHCI_MAX_CURRENT 0x48
-#define SDHCI_MAX_CURRENT_330_MASK 0x0000FF
-#define SDHCI_MAX_CURRENT_330_SHIFT 0
-#define SDHCI_MAX_CURRENT_300_MASK 0x00FF00
-#define SDHCI_MAX_CURRENT_300_SHIFT 8
-#define SDHCI_MAX_CURRENT_180_MASK 0xFF0000
-#define SDHCI_MAX_CURRENT_180_SHIFT 16
-#define SDHCI_MAX_CURRENT_MULTIPLIER 4
-
-/* 4C-4F reserved for more max current */
-
-#define SDHCI_SET_ACMD12_ERROR 0x50
-#define SDHCI_SET_INT_ERROR 0x52
-
-#define SDHCI_ADMA_ERROR 0x54
-
-/* 55-57 reserved */
-
-#define SDHCI_ADMA_ADDRESS 0x58
-
-/* 60-FB reserved */
-
-#define SDHCI_SLOT_INT_STATUS 0xFC
-
-#define SDHCI_HOST_VERSION 0xFE
-#define SDHCI_VENDOR_VER_MASK 0xFF00
-#define SDHCI_VENDOR_VER_SHIFT 8
-#define SDHCI_SPEC_VER_MASK 0x00FF
-#define SDHCI_SPEC_VER_SHIFT 0
-#define SDHCI_SPEC_100 0
-#define SDHCI_SPEC_200 1
-#define SDHCI_SPEC_300 2
-
-/*
- * End of controller registers.
- */
-
-#define SDHCI_MAX_DIV_SPEC_200 256
-#define SDHCI_MAX_DIV_SPEC_300 2046
-
-/*
- * Host SDMA buffer boundary. Valid values from 4K to 512K in powers of 2.
- */
-#define SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024)
-#define SDHCI_DEFAULT_BOUNDARY_ARG (ilog2(SDHCI_DEFAULT_BOUNDARY_SIZE) - 12)
-
-struct sdhci_ops {
-#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
- u32 (*read_l)(struct sdhci_host *host, int reg);
- u16 (*read_w)(struct sdhci_host *host, int reg);
- u8 (*read_b)(struct sdhci_host *host, int reg);
- void (*write_l)(struct sdhci_host *host, u32 val, int reg);
- void (*write_w)(struct sdhci_host *host, u16 val, int reg);
- void (*write_b)(struct sdhci_host *host, u8 val, int reg);
-#endif
-
- void (*set_clock)(struct sdhci_host *host, unsigned int clock);
-
- int (*enable_dma)(struct sdhci_host *host);
- unsigned int (*get_max_clock)(struct sdhci_host *host);
- unsigned int (*get_min_clock)(struct sdhci_host *host);
- unsigned int (*get_timeout_clock)(struct sdhci_host *host);
- int (*platform_8bit_width)(struct sdhci_host *host,
- int width);
- void (*platform_send_init_74_clocks)(struct sdhci_host *host,
- u8 power_mode);
- unsigned int (*get_ro)(struct sdhci_host *host);
- void (*platform_reset_enter)(struct sdhci_host *host, u8 mask);
- void (*platform_reset_exit)(struct sdhci_host *host, u8 mask);
- int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
- void (*hw_reset)(struct sdhci_host *host);
- void (*platform_suspend)(struct sdhci_host *host);
- void (*platform_resume)(struct sdhci_host *host);
-};
-
-#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
-
-static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg)
-{
- if (unlikely(host->ops->write_l))
- host->ops->write_l(host, val, reg);
- else
- writel(val, host->ioaddr + reg);
-}
-
-static inline void sdhci_writew(struct sdhci_host *host, u16 val, int reg)
-{
- if (unlikely(host->ops->write_w))
- host->ops->write_w(host, val, reg);
- else
- writew(val, host->ioaddr + reg);
-}
-
-static inline void sdhci_writeb(struct sdhci_host *host, u8 val, int reg)
-{
- if (unlikely(host->ops->write_b))
- host->ops->write_b(host, val, reg);
- else
- writeb(val, host->ioaddr + reg);
-}
-
-static inline u32 sdhci_readl(struct sdhci_host *host, int reg)
-{
- if (unlikely(host->ops->read_l))
- return host->ops->read_l(host, reg);
- else
- return readl(host->ioaddr + reg);
-}
-
-static inline u16 sdhci_readw(struct sdhci_host *host, int reg)
-{
- if (unlikely(host->ops->read_w))
- return host->ops->read_w(host, reg);
- else
- return readw(host->ioaddr + reg);
-}
-
-static inline u8 sdhci_readb(struct sdhci_host *host, int reg)
-{
- if (unlikely(host->ops->read_b))
- return host->ops->read_b(host, reg);
- else
- return readb(host->ioaddr + reg);
-}
-
-#else
-
-static inline void sdhci_writel(struct sdhci_host *host, u32 val, int reg)
-{
- writel(val, host->ioaddr + reg);
-}
-
-static inline void sdhci_writew(struct sdhci_host *host, u16 val, int reg)
-{
- writew(val, host->ioaddr + reg);
-}
-
-static inline void sdhci_writeb(struct sdhci_host *host, u8 val, int reg)
-{
- writeb(val, host->ioaddr + reg);
-}
-
-static inline u32 sdhci_readl(struct sdhci_host *host, int reg)
-{
- return readl(host->ioaddr + reg);
-}
-
-static inline u16 sdhci_readw(struct sdhci_host *host, int reg)
-{
- return readw(host->ioaddr + reg);
-}
-
-static inline u8 sdhci_readb(struct sdhci_host *host, int reg)
-{
- return readb(host->ioaddr + reg);
-}
-
-#endif /* CONFIG_MMC_SDHCI_IO_ACCESSORS */
-
-extern struct sdhci_host *sdhci_alloc_host(struct device *dev,
- size_t priv_size);
-extern void sdhci_free_host(struct sdhci_host *host);
-
-static inline void *sdhci_priv(struct sdhci_host *host)
-{
- return (void *)host->private;
-}
-
-extern void sdhci_card_detect(struct sdhci_host *host);
-extern int sdhci_add_host(struct sdhci_host *host);
-extern void sdhci_remove_host(struct sdhci_host *host, int dead);
-
-#ifdef CONFIG_PM
-extern int sdhci_suspend_host(struct sdhci_host *host);
-extern int sdhci_resume_host(struct sdhci_host *host);
-extern void sdhci_enable_irq_wakeups(struct sdhci_host *host);
-#endif
-
-#ifdef CONFIG_PM_RUNTIME
-extern int sdhci_runtime_suspend_host(struct sdhci_host *host);
-extern int sdhci_runtime_resume_host(struct sdhci_host *host);
-#endif
-
-#endif /* __SDHCI_HW_H */
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sdricoh_cs.c b/ANDROID_3.4.5/drivers/mmc/host/sdricoh_cs.c
deleted file mode 100644
index 7009f17a..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sdricoh_cs.c
+++ /dev/null
@@ -1,573 +0,0 @@
-/*
- * sdricoh_cs.c - driver for Ricoh Secure Digital Card Readers that can be
- * found on some Ricoh RL5c476 II cardbus bridge
- *
- * Copyright (C) 2006 - 2008 Sascha Sommer <saschasommer@freenet.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, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-/*
-#define DEBUG
-#define VERBOSE_DEBUG
-*/
-#include <linux/delay.h>
-#include <linux/highmem.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/scatterlist.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
-#include <linux/io.h>
-
-#include <linux/mmc/host.h>
-
-#define DRIVER_NAME "sdricoh_cs"
-
-static unsigned int switchlocked;
-
-/* i/o region */
-#define SDRICOH_PCI_REGION 0
-#define SDRICOH_PCI_REGION_SIZE 0x1000
-
-/* registers */
-#define R104_VERSION 0x104
-#define R200_CMD 0x200
-#define R204_CMD_ARG 0x204
-#define R208_DATAIO 0x208
-#define R20C_RESP 0x20c
-#define R21C_STATUS 0x21c
-#define R2E0_INIT 0x2e0
-#define R2E4_STATUS_RESP 0x2e4
-#define R2F0_RESET 0x2f0
-#define R224_MODE 0x224
-#define R226_BLOCKSIZE 0x226
-#define R228_POWER 0x228
-#define R230_DATA 0x230
-
-/* flags for the R21C_STATUS register */
-#define STATUS_CMD_FINISHED 0x00000001
-#define STATUS_TRANSFER_FINISHED 0x00000004
-#define STATUS_CARD_INSERTED 0x00000020
-#define STATUS_CARD_LOCKED 0x00000080
-#define STATUS_CMD_TIMEOUT 0x00400000
-#define STATUS_READY_TO_READ 0x01000000
-#define STATUS_READY_TO_WRITE 0x02000000
-#define STATUS_BUSY 0x40000000
-
-/* timeouts */
-#define INIT_TIMEOUT 100
-#define CMD_TIMEOUT 100000
-#define TRANSFER_TIMEOUT 100000
-#define BUSY_TIMEOUT 32767
-
-/* list of supported pcmcia devices */
-static const struct pcmcia_device_id pcmcia_ids[] = {
- /* vendor and device strings followed by their crc32 hashes */
- PCMCIA_DEVICE_PROD_ID12("RICOH", "Bay1Controller", 0xd9f522ed,
- 0xc3901202),
- PCMCIA_DEVICE_PROD_ID12("RICOH", "Bay Controller", 0xd9f522ed,
- 0xace80909),
- PCMCIA_DEVICE_NULL,
-};
-
-MODULE_DEVICE_TABLE(pcmcia, pcmcia_ids);
-
-/* mmc privdata */
-struct sdricoh_host {
- struct device *dev;
- struct mmc_host *mmc; /* MMC structure */
- unsigned char __iomem *iobase;
- struct pci_dev *pci_dev;
- int app_cmd;
-};
-
-/***************** register i/o helper functions *****************************/
-
-static inline unsigned int sdricoh_readl(struct sdricoh_host *host,
- unsigned int reg)
-{
- unsigned int value = readl(host->iobase + reg);
- dev_vdbg(host->dev, "rl %x 0x%x\n", reg, value);
- return value;
-}
-
-static inline void sdricoh_writel(struct sdricoh_host *host, unsigned int reg,
- unsigned int value)
-{
- writel(value, host->iobase + reg);
- dev_vdbg(host->dev, "wl %x 0x%x\n", reg, value);
-
-}
-
-static inline unsigned int sdricoh_readw(struct sdricoh_host *host,
- unsigned int reg)
-{
- unsigned int value = readw(host->iobase + reg);
- dev_vdbg(host->dev, "rb %x 0x%x\n", reg, value);
- return value;
-}
-
-static inline void sdricoh_writew(struct sdricoh_host *host, unsigned int reg,
- unsigned short value)
-{
- writew(value, host->iobase + reg);
- dev_vdbg(host->dev, "ww %x 0x%x\n", reg, value);
-}
-
-static inline unsigned int sdricoh_readb(struct sdricoh_host *host,
- unsigned int reg)
-{
- unsigned int value = readb(host->iobase + reg);
- dev_vdbg(host->dev, "rb %x 0x%x\n", reg, value);
- return value;
-}
-
-static int sdricoh_query_status(struct sdricoh_host *host, unsigned int wanted,
- unsigned int timeout){
- unsigned int loop;
- unsigned int status = 0;
- struct device *dev = host->dev;
- for (loop = 0; loop < timeout; loop++) {
- status = sdricoh_readl(host, R21C_STATUS);
- sdricoh_writel(host, R2E4_STATUS_RESP, status);
- if (status & wanted)
- break;
- }
-
- if (loop == timeout) {
- dev_err(dev, "query_status: timeout waiting for %x\n", wanted);
- return -ETIMEDOUT;
- }
-
- /* do not do this check in the loop as some commands fail otherwise */
- if (status & 0x7F0000) {
- dev_err(dev, "waiting for status bit %x failed\n", wanted);
- return -EINVAL;
- }
- return 0;
-
-}
-
-static int sdricoh_mmc_cmd(struct sdricoh_host *host, unsigned char opcode,
- unsigned int arg)
-{
- unsigned int status;
- int result = 0;
- unsigned int loop = 0;
- /* reset status reg? */
- sdricoh_writel(host, R21C_STATUS, 0x18);
- /* fill parameters */
- sdricoh_writel(host, R204_CMD_ARG, arg);
- sdricoh_writel(host, R200_CMD, (0x10000 << 8) | opcode);
- /* wait for command completion */
- if (opcode) {
- for (loop = 0; loop < CMD_TIMEOUT; loop++) {
- status = sdricoh_readl(host, R21C_STATUS);
- sdricoh_writel(host, R2E4_STATUS_RESP, status);
- if (status & STATUS_CMD_FINISHED)
- break;
- }
- /* don't check for timeout in the loop it is not always
- reset correctly
- */
- if (loop == CMD_TIMEOUT || status & STATUS_CMD_TIMEOUT)
- result = -ETIMEDOUT;
-
- }
-
- return result;
-
-}
-
-static int sdricoh_reset(struct sdricoh_host *host)
-{
- dev_dbg(host->dev, "reset\n");
- sdricoh_writel(host, R2F0_RESET, 0x10001);
- sdricoh_writel(host, R2E0_INIT, 0x10000);
- if (sdricoh_readl(host, R2E0_INIT) != 0x10000)
- return -EIO;
- sdricoh_writel(host, R2E0_INIT, 0x10007);
-
- sdricoh_writel(host, R224_MODE, 0x2000000);
- sdricoh_writel(host, R228_POWER, 0xe0);
-
-
- /* status register ? */
- sdricoh_writel(host, R21C_STATUS, 0x18);
-
- return 0;
-}
-
-static int sdricoh_blockio(struct sdricoh_host *host, int read,
- u8 *buf, int len)
-{
- int size;
- u32 data = 0;
- /* wait until the data is available */
- if (read) {
- if (sdricoh_query_status(host, STATUS_READY_TO_READ,
- TRANSFER_TIMEOUT))
- return -ETIMEDOUT;
- sdricoh_writel(host, R21C_STATUS, 0x18);
- /* read data */
- while (len) {
- data = sdricoh_readl(host, R230_DATA);
- size = min(len, 4);
- len -= size;
- while (size) {
- *buf = data & 0xFF;
- buf++;
- data >>= 8;
- size--;
- }
- }
- } else {
- if (sdricoh_query_status(host, STATUS_READY_TO_WRITE,
- TRANSFER_TIMEOUT))
- return -ETIMEDOUT;
- sdricoh_writel(host, R21C_STATUS, 0x18);
- /* write data */
- while (len) {
- size = min(len, 4);
- len -= size;
- while (size) {
- data >>= 8;
- data |= (u32)*buf << 24;
- buf++;
- size--;
- }
- sdricoh_writel(host, R230_DATA, data);
- }
- }
-
- if (len)
- return -EIO;
-
- return 0;
-}
-
-static void sdricoh_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct sdricoh_host *host = mmc_priv(mmc);
- struct mmc_command *cmd = mrq->cmd;
- struct mmc_data *data = cmd->data;
- struct device *dev = host->dev;
- unsigned char opcode = cmd->opcode;
- int i;
-
- dev_dbg(dev, "=============================\n");
- dev_dbg(dev, "sdricoh_request opcode=%i\n", opcode);
-
- sdricoh_writel(host, R21C_STATUS, 0x18);
-
- /* MMC_APP_CMDs need some special handling */
- if (host->app_cmd) {
- opcode |= 64;
- host->app_cmd = 0;
- } else if (opcode == 55)
- host->app_cmd = 1;
-
- /* read/write commands seem to require this */
- if (data) {
- sdricoh_writew(host, R226_BLOCKSIZE, data->blksz);
- sdricoh_writel(host, R208_DATAIO, 0);
- }
-
- cmd->error = sdricoh_mmc_cmd(host, opcode, cmd->arg);
-
- /* read response buffer */
- if (cmd->flags & MMC_RSP_PRESENT) {
- if (cmd->flags & MMC_RSP_136) {
- /* CRC is stripped so we need to do some shifting. */
- for (i = 0; i < 4; i++) {
- cmd->resp[i] =
- sdricoh_readl(host,
- R20C_RESP + (3 - i) * 4) << 8;
- if (i != 3)
- cmd->resp[i] |=
- sdricoh_readb(host, R20C_RESP +
- (3 - i) * 4 - 1);
- }
- } else
- cmd->resp[0] = sdricoh_readl(host, R20C_RESP);
- }
-
- /* transfer data */
- if (data && cmd->error == 0) {
- dev_dbg(dev, "transfer: blksz %i blocks %i sg_len %i "
- "sg length %i\n", data->blksz, data->blocks,
- data->sg_len, data->sg->length);
-
- /* enter data reading mode */
- sdricoh_writel(host, R21C_STATUS, 0x837f031e);
- for (i = 0; i < data->blocks; i++) {
- size_t len = data->blksz;
- u8 *buf;
- struct page *page;
- int result;
- page = sg_page(data->sg);
-
- buf = kmap(page) + data->sg->offset + (len * i);
- result =
- sdricoh_blockio(host,
- data->flags & MMC_DATA_READ, buf, len);
- kunmap(page);
- flush_dcache_page(page);
- if (result) {
- dev_err(dev, "sdricoh_request: cmd %i "
- "block transfer failed\n", cmd->opcode);
- cmd->error = result;
- break;
- } else
- data->bytes_xfered += len;
- }
-
- sdricoh_writel(host, R208_DATAIO, 1);
-
- if (sdricoh_query_status(host, STATUS_TRANSFER_FINISHED,
- TRANSFER_TIMEOUT)) {
- dev_err(dev, "sdricoh_request: transfer end error\n");
- cmd->error = -EINVAL;
- }
- }
- /* FIXME check busy flag */
-
- mmc_request_done(mmc, mrq);
- dev_dbg(dev, "=============================\n");
-}
-
-static void sdricoh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct sdricoh_host *host = mmc_priv(mmc);
- dev_dbg(host->dev, "set_ios\n");
-
- if (ios->power_mode == MMC_POWER_ON) {
- sdricoh_writel(host, R228_POWER, 0xc0e0);
-
- if (ios->bus_width == MMC_BUS_WIDTH_4) {
- sdricoh_writel(host, R224_MODE, 0x2000300);
- sdricoh_writel(host, R228_POWER, 0x40e0);
- } else {
- sdricoh_writel(host, R224_MODE, 0x2000340);
- }
-
- } else if (ios->power_mode == MMC_POWER_UP) {
- sdricoh_writel(host, R224_MODE, 0x2000320);
- sdricoh_writel(host, R228_POWER, 0xe0);
- }
-}
-
-static int sdricoh_get_ro(struct mmc_host *mmc)
-{
- struct sdricoh_host *host = mmc_priv(mmc);
- unsigned int status;
-
- status = sdricoh_readl(host, R21C_STATUS);
- sdricoh_writel(host, R2E4_STATUS_RESP, status);
-
- /* some notebooks seem to have the locked flag switched */
- if (switchlocked)
- return !(status & STATUS_CARD_LOCKED);
-
- return (status & STATUS_CARD_LOCKED);
-}
-
-static struct mmc_host_ops sdricoh_ops = {
- .request = sdricoh_request,
- .set_ios = sdricoh_set_ios,
- .get_ro = sdricoh_get_ro,
-};
-
-/* initialize the control and register it to the mmc framework */
-static int sdricoh_init_mmc(struct pci_dev *pci_dev,
- struct pcmcia_device *pcmcia_dev)
-{
- int result = 0;
- void __iomem *iobase = NULL;
- struct mmc_host *mmc = NULL;
- struct sdricoh_host *host = NULL;
- struct device *dev = &pcmcia_dev->dev;
- /* map iomem */
- if (pci_resource_len(pci_dev, SDRICOH_PCI_REGION) !=
- SDRICOH_PCI_REGION_SIZE) {
- dev_dbg(dev, "unexpected pci resource len\n");
- return -ENODEV;
- }
- iobase =
- pci_iomap(pci_dev, SDRICOH_PCI_REGION, SDRICOH_PCI_REGION_SIZE);
- if (!iobase) {
- dev_err(dev, "unable to map iobase\n");
- return -ENODEV;
- }
- /* check version? */
- if (readl(iobase + R104_VERSION) != 0x4000) {
- dev_dbg(dev, "no supported mmc controller found\n");
- result = -ENODEV;
- goto err;
- }
- /* allocate privdata */
- mmc = pcmcia_dev->priv =
- mmc_alloc_host(sizeof(struct sdricoh_host), &pcmcia_dev->dev);
- if (!mmc) {
- dev_err(dev, "mmc_alloc_host failed\n");
- result = -ENOMEM;
- goto err;
- }
- host = mmc_priv(mmc);
-
- host->iobase = iobase;
- host->dev = dev;
- host->pci_dev = pci_dev;
-
- mmc->ops = &sdricoh_ops;
-
- /* FIXME: frequency and voltage handling is done by the controller
- */
- mmc->f_min = 450000;
- mmc->f_max = 24000000;
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps |= MMC_CAP_4_BIT_DATA;
-
- mmc->max_seg_size = 1024 * 512;
- mmc->max_blk_size = 512;
-
- /* reset the controller */
- if (sdricoh_reset(host)) {
- dev_dbg(dev, "could not reset\n");
- result = -EIO;
- goto err;
-
- }
-
- result = mmc_add_host(mmc);
-
- if (!result) {
- dev_dbg(dev, "mmc host registered\n");
- return 0;
- }
-
-err:
- if (iobase)
- pci_iounmap(pci_dev, iobase);
- if (mmc)
- mmc_free_host(mmc);
-
- return result;
-}
-
-/* search for supported mmc controllers */
-static int sdricoh_pcmcia_probe(struct pcmcia_device *pcmcia_dev)
-{
- struct pci_dev *pci_dev = NULL;
-
- dev_info(&pcmcia_dev->dev, "Searching MMC controller for pcmcia device"
- " %s %s ...\n", pcmcia_dev->prod_id[0], pcmcia_dev->prod_id[1]);
-
- /* search pci cardbus bridge that contains the mmc controller */
- /* the io region is already claimed by yenta_socket... */
- while ((pci_dev =
- pci_get_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476,
- pci_dev))) {
- /* try to init the device */
- if (!sdricoh_init_mmc(pci_dev, pcmcia_dev)) {
- dev_info(&pcmcia_dev->dev, "MMC controller found\n");
- return 0;
- }
-
- }
- dev_err(&pcmcia_dev->dev, "No MMC controller was found.\n");
- return -ENODEV;
-}
-
-static void sdricoh_pcmcia_detach(struct pcmcia_device *link)
-{
- struct mmc_host *mmc = link->priv;
-
- dev_dbg(&link->dev, "detach\n");
-
- /* remove mmc host */
- if (mmc) {
- struct sdricoh_host *host = mmc_priv(mmc);
- mmc_remove_host(mmc);
- pci_iounmap(host->pci_dev, host->iobase);
- pci_dev_put(host->pci_dev);
- mmc_free_host(mmc);
- }
- pcmcia_disable_device(link);
-
-}
-
-#ifdef CONFIG_PM
-static int sdricoh_pcmcia_suspend(struct pcmcia_device *link)
-{
- struct mmc_host *mmc = link->priv;
- dev_dbg(&link->dev, "suspend\n");
- mmc_suspend_host(mmc);
- return 0;
-}
-
-static int sdricoh_pcmcia_resume(struct pcmcia_device *link)
-{
- struct mmc_host *mmc = link->priv;
- dev_dbg(&link->dev, "resume\n");
- sdricoh_reset(mmc_priv(mmc));
- mmc_resume_host(mmc);
- return 0;
-}
-#else
-#define sdricoh_pcmcia_suspend NULL
-#define sdricoh_pcmcia_resume NULL
-#endif
-
-static struct pcmcia_driver sdricoh_driver = {
- .name = DRIVER_NAME,
- .probe = sdricoh_pcmcia_probe,
- .remove = sdricoh_pcmcia_detach,
- .id_table = pcmcia_ids,
- .suspend = sdricoh_pcmcia_suspend,
- .resume = sdricoh_pcmcia_resume,
-};
-
-/*****************************************************************************\
- * *
- * Driver init/exit *
- * *
-\*****************************************************************************/
-
-static int __init sdricoh_drv_init(void)
-{
- return pcmcia_register_driver(&sdricoh_driver);
-}
-
-static void __exit sdricoh_drv_exit(void)
-{
- pcmcia_unregister_driver(&sdricoh_driver);
-}
-
-module_init(sdricoh_drv_init);
-module_exit(sdricoh_drv_exit);
-
-module_param(switchlocked, uint, 0444);
-
-MODULE_AUTHOR("Sascha Sommer <saschasommer@freenet.de>");
-MODULE_DESCRIPTION("Ricoh PCMCIA Secure Digital Interface driver");
-MODULE_LICENSE("GPL");
-
-MODULE_PARM_DESC(switchlocked, "Switch the cards locked status."
- "Use this when unlocked cards are shown readonly (default 0)");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sh_mmcif.c b/ANDROID_3.4.5/drivers/mmc/host/sh_mmcif.c
deleted file mode 100644
index 724b35e8..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sh_mmcif.c
+++ /dev/null
@@ -1,1454 +0,0 @@
-/*
- * MMCIF eMMC driver.
- *
- * Copyright (C) 2010 Renesas Solutions Corp.
- * Yusuke Goda <yusuke.goda.sx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License.
- *
- *
- * TODO
- * 1. DMA
- * 2. Power management
- * 3. Handle MMC errors better
- *
- */
-
-/*
- * The MMCIF driver is now processing MMC requests asynchronously, according
- * to the Linux MMC API requirement.
- *
- * The MMCIF driver processes MMC requests in up to 3 stages: command, optional
- * data, and optional stop. To achieve asynchronous processing each of these
- * stages is split into two halves: a top and a bottom half. The top half
- * initialises the hardware, installs a timeout handler to handle completion
- * timeouts, and returns. In case of the command stage this immediately returns
- * control to the caller, leaving all further processing to run asynchronously.
- * All further request processing is performed by the bottom halves.
- *
- * The bottom half further consists of a "hard" IRQ handler, an IRQ handler
- * thread, a DMA completion callback, if DMA is used, a timeout work, and
- * request- and stage-specific handler methods.
- *
- * Each bottom half run begins with either a hardware interrupt, a DMA callback
- * invocation, or a timeout work run. In case of an error or a successful
- * processing completion, the MMC core is informed and the request processing is
- * finished. In case processing has to continue, i.e., if data has to be read
- * from or written to the card, or if a stop command has to be sent, the next
- * top half is called, which performs the necessary hardware handling and
- * reschedules the timeout work. This returns the driver state machine into the
- * bottom half waiting state.
- */
-
-#include <linux/bitops.h>
-#include <linux/clk.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmaengine.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/core.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/sh_mmcif.h>
-#include <linux/pagemap.h>
-#include <linux/platform_device.h>
-#include <linux/pm_qos.h>
-#include <linux/pm_runtime.h>
-#include <linux/spinlock.h>
-#include <linux/module.h>
-
-#define DRIVER_NAME "sh_mmcif"
-#define DRIVER_VERSION "2010-04-28"
-
-/* CE_CMD_SET */
-#define CMD_MASK 0x3f000000
-#define CMD_SET_RTYP_NO ((0 << 23) | (0 << 22))
-#define CMD_SET_RTYP_6B ((0 << 23) | (1 << 22)) /* R1/R1b/R3/R4/R5 */
-#define CMD_SET_RTYP_17B ((1 << 23) | (0 << 22)) /* R2 */
-#define CMD_SET_RBSY (1 << 21) /* R1b */
-#define CMD_SET_CCSEN (1 << 20)
-#define CMD_SET_WDAT (1 << 19) /* 1: on data, 0: no data */
-#define CMD_SET_DWEN (1 << 18) /* 1: write, 0: read */
-#define CMD_SET_CMLTE (1 << 17) /* 1: multi block trans, 0: single */
-#define CMD_SET_CMD12EN (1 << 16) /* 1: CMD12 auto issue */
-#define CMD_SET_RIDXC_INDEX ((0 << 15) | (0 << 14)) /* index check */
-#define CMD_SET_RIDXC_BITS ((0 << 15) | (1 << 14)) /* check bits check */
-#define CMD_SET_RIDXC_NO ((1 << 15) | (0 << 14)) /* no check */
-#define CMD_SET_CRC7C ((0 << 13) | (0 << 12)) /* CRC7 check*/
-#define CMD_SET_CRC7C_BITS ((0 << 13) | (1 << 12)) /* check bits check*/
-#define CMD_SET_CRC7C_INTERNAL ((1 << 13) | (0 << 12)) /* internal CRC7 check*/
-#define CMD_SET_CRC16C (1 << 10) /* 0: CRC16 check*/
-#define CMD_SET_CRCSTE (1 << 8) /* 1: not receive CRC status */
-#define CMD_SET_TBIT (1 << 7) /* 1: tran mission bit "Low" */
-#define CMD_SET_OPDM (1 << 6) /* 1: open/drain */
-#define CMD_SET_CCSH (1 << 5)
-#define CMD_SET_DATW_1 ((0 << 1) | (0 << 0)) /* 1bit */
-#define CMD_SET_DATW_4 ((0 << 1) | (1 << 0)) /* 4bit */
-#define CMD_SET_DATW_8 ((1 << 1) | (0 << 0)) /* 8bit */
-
-/* CE_CMD_CTRL */
-#define CMD_CTRL_BREAK (1 << 0)
-
-/* CE_BLOCK_SET */
-#define BLOCK_SIZE_MASK 0x0000ffff
-
-/* CE_INT */
-#define INT_CCSDE (1 << 29)
-#define INT_CMD12DRE (1 << 26)
-#define INT_CMD12RBE (1 << 25)
-#define INT_CMD12CRE (1 << 24)
-#define INT_DTRANE (1 << 23)
-#define INT_BUFRE (1 << 22)
-#define INT_BUFWEN (1 << 21)
-#define INT_BUFREN (1 << 20)
-#define INT_CCSRCV (1 << 19)
-#define INT_RBSYE (1 << 17)
-#define INT_CRSPE (1 << 16)
-#define INT_CMDVIO (1 << 15)
-#define INT_BUFVIO (1 << 14)
-#define INT_WDATERR (1 << 11)
-#define INT_RDATERR (1 << 10)
-#define INT_RIDXERR (1 << 9)
-#define INT_RSPERR (1 << 8)
-#define INT_CCSTO (1 << 5)
-#define INT_CRCSTO (1 << 4)
-#define INT_WDATTO (1 << 3)
-#define INT_RDATTO (1 << 2)
-#define INT_RBSYTO (1 << 1)
-#define INT_RSPTO (1 << 0)
-#define INT_ERR_STS (INT_CMDVIO | INT_BUFVIO | INT_WDATERR | \
- INT_RDATERR | INT_RIDXERR | INT_RSPERR | \
- INT_CCSTO | INT_CRCSTO | INT_WDATTO | \
- INT_RDATTO | INT_RBSYTO | INT_RSPTO)
-
-/* CE_INT_MASK */
-#define MASK_ALL 0x00000000
-#define MASK_MCCSDE (1 << 29)
-#define MASK_MCMD12DRE (1 << 26)
-#define MASK_MCMD12RBE (1 << 25)
-#define MASK_MCMD12CRE (1 << 24)
-#define MASK_MDTRANE (1 << 23)
-#define MASK_MBUFRE (1 << 22)
-#define MASK_MBUFWEN (1 << 21)
-#define MASK_MBUFREN (1 << 20)
-#define MASK_MCCSRCV (1 << 19)
-#define MASK_MRBSYE (1 << 17)
-#define MASK_MCRSPE (1 << 16)
-#define MASK_MCMDVIO (1 << 15)
-#define MASK_MBUFVIO (1 << 14)
-#define MASK_MWDATERR (1 << 11)
-#define MASK_MRDATERR (1 << 10)
-#define MASK_MRIDXERR (1 << 9)
-#define MASK_MRSPERR (1 << 8)
-#define MASK_MCCSTO (1 << 5)
-#define MASK_MCRCSTO (1 << 4)
-#define MASK_MWDATTO (1 << 3)
-#define MASK_MRDATTO (1 << 2)
-#define MASK_MRBSYTO (1 << 1)
-#define MASK_MRSPTO (1 << 0)
-
-#define MASK_START_CMD (MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | \
- MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | \
- MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO | \
- MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO)
-
-/* CE_HOST_STS1 */
-#define STS1_CMDSEQ (1 << 31)
-
-/* CE_HOST_STS2 */
-#define STS2_CRCSTE (1 << 31)
-#define STS2_CRC16E (1 << 30)
-#define STS2_AC12CRCE (1 << 29)
-#define STS2_RSPCRC7E (1 << 28)
-#define STS2_CRCSTEBE (1 << 27)
-#define STS2_RDATEBE (1 << 26)
-#define STS2_AC12REBE (1 << 25)
-#define STS2_RSPEBE (1 << 24)
-#define STS2_AC12IDXE (1 << 23)
-#define STS2_RSPIDXE (1 << 22)
-#define STS2_CCSTO (1 << 15)
-#define STS2_RDATTO (1 << 14)
-#define STS2_DATBSYTO (1 << 13)
-#define STS2_CRCSTTO (1 << 12)
-#define STS2_AC12BSYTO (1 << 11)
-#define STS2_RSPBSYTO (1 << 10)
-#define STS2_AC12RSPTO (1 << 9)
-#define STS2_RSPTO (1 << 8)
-#define STS2_CRC_ERR (STS2_CRCSTE | STS2_CRC16E | \
- STS2_AC12CRCE | STS2_RSPCRC7E | STS2_CRCSTEBE)
-#define STS2_TIMEOUT_ERR (STS2_CCSTO | STS2_RDATTO | \
- STS2_DATBSYTO | STS2_CRCSTTO | \
- STS2_AC12BSYTO | STS2_RSPBSYTO | \
- STS2_AC12RSPTO | STS2_RSPTO)
-
-#define CLKDEV_EMMC_DATA 52000000 /* 52MHz */
-#define CLKDEV_MMC_DATA 20000000 /* 20MHz */
-#define CLKDEV_INIT 400000 /* 400 KHz */
-
-enum mmcif_state {
- STATE_IDLE,
- STATE_REQUEST,
- STATE_IOS,
-};
-
-enum mmcif_wait_for {
- MMCIF_WAIT_FOR_REQUEST,
- MMCIF_WAIT_FOR_CMD,
- MMCIF_WAIT_FOR_MREAD,
- MMCIF_WAIT_FOR_MWRITE,
- MMCIF_WAIT_FOR_READ,
- MMCIF_WAIT_FOR_WRITE,
- MMCIF_WAIT_FOR_READ_END,
- MMCIF_WAIT_FOR_WRITE_END,
- MMCIF_WAIT_FOR_STOP,
-};
-
-struct sh_mmcif_host {
- struct mmc_host *mmc;
- struct mmc_request *mrq;
- struct platform_device *pd;
- struct sh_dmae_slave dma_slave_tx;
- struct sh_dmae_slave dma_slave_rx;
- struct clk *hclk;
- unsigned int clk;
- int bus_width;
- bool sd_error;
- bool dying;
- long timeout;
- void __iomem *addr;
- u32 *pio_ptr;
- spinlock_t lock; /* protect sh_mmcif_host::state */
- enum mmcif_state state;
- enum mmcif_wait_for wait_for;
- struct delayed_work timeout_work;
- size_t blocksize;
- int sg_idx;
- int sg_blkidx;
- bool power;
- bool card_present;
-
- /* DMA support */
- struct dma_chan *chan_rx;
- struct dma_chan *chan_tx;
- struct completion dma_complete;
- bool dma_active;
-};
-
-static inline void sh_mmcif_bitset(struct sh_mmcif_host *host,
- unsigned int reg, u32 val)
-{
- writel(val | readl(host->addr + reg), host->addr + reg);
-}
-
-static inline void sh_mmcif_bitclr(struct sh_mmcif_host *host,
- unsigned int reg, u32 val)
-{
- writel(~val & readl(host->addr + reg), host->addr + reg);
-}
-
-static void mmcif_dma_complete(void *arg)
-{
- struct sh_mmcif_host *host = arg;
- struct mmc_data *data = host->mrq->data;
-
- dev_dbg(&host->pd->dev, "Command completed\n");
-
- if (WARN(!data, "%s: NULL data in DMA completion!\n",
- dev_name(&host->pd->dev)))
- return;
-
- if (data->flags & MMC_DATA_READ)
- dma_unmap_sg(host->chan_rx->device->dev,
- data->sg, data->sg_len,
- DMA_FROM_DEVICE);
- else
- dma_unmap_sg(host->chan_tx->device->dev,
- data->sg, data->sg_len,
- DMA_TO_DEVICE);
-
- complete(&host->dma_complete);
-}
-
-static void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host)
-{
- struct mmc_data *data = host->mrq->data;
- struct scatterlist *sg = data->sg;
- struct dma_async_tx_descriptor *desc = NULL;
- struct dma_chan *chan = host->chan_rx;
- dma_cookie_t cookie = -EINVAL;
- int ret;
-
- ret = dma_map_sg(chan->device->dev, sg, data->sg_len,
- DMA_FROM_DEVICE);
- if (ret > 0) {
- host->dma_active = true;
- desc = dmaengine_prep_slave_sg(chan, sg, ret,
- DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- }
-
- if (desc) {
- desc->callback = mmcif_dma_complete;
- desc->callback_param = host;
- cookie = dmaengine_submit(desc);
- sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN);
- dma_async_issue_pending(chan);
- }
- dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n",
- __func__, data->sg_len, ret, cookie);
-
- if (!desc) {
- /* DMA failed, fall back to PIO */
- if (ret >= 0)
- ret = -EIO;
- host->chan_rx = NULL;
- host->dma_active = false;
- dma_release_channel(chan);
- /* Free the Tx channel too */
- chan = host->chan_tx;
- if (chan) {
- host->chan_tx = NULL;
- dma_release_channel(chan);
- }
- dev_warn(&host->pd->dev,
- "DMA failed: %d, falling back to PIO\n", ret);
- sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
- }
-
- dev_dbg(&host->pd->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__,
- desc, cookie, data->sg_len);
-}
-
-static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host)
-{
- struct mmc_data *data = host->mrq->data;
- struct scatterlist *sg = data->sg;
- struct dma_async_tx_descriptor *desc = NULL;
- struct dma_chan *chan = host->chan_tx;
- dma_cookie_t cookie = -EINVAL;
- int ret;
-
- ret = dma_map_sg(chan->device->dev, sg, data->sg_len,
- DMA_TO_DEVICE);
- if (ret > 0) {
- host->dma_active = true;
- desc = dmaengine_prep_slave_sg(chan, sg, ret,
- DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- }
-
- if (desc) {
- desc->callback = mmcif_dma_complete;
- desc->callback_param = host;
- cookie = dmaengine_submit(desc);
- sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAWEN);
- dma_async_issue_pending(chan);
- }
- dev_dbg(&host->pd->dev, "%s(): mapped %d -> %d, cookie %d\n",
- __func__, data->sg_len, ret, cookie);
-
- if (!desc) {
- /* DMA failed, fall back to PIO */
- if (ret >= 0)
- ret = -EIO;
- host->chan_tx = NULL;
- host->dma_active = false;
- dma_release_channel(chan);
- /* Free the Rx channel too */
- chan = host->chan_rx;
- if (chan) {
- host->chan_rx = NULL;
- dma_release_channel(chan);
- }
- dev_warn(&host->pd->dev,
- "DMA failed: %d, falling back to PIO\n", ret);
- sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
- }
-
- dev_dbg(&host->pd->dev, "%s(): desc %p, cookie %d\n", __func__,
- desc, cookie);
-}
-
-static bool sh_mmcif_filter(struct dma_chan *chan, void *arg)
-{
- dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg);
- chan->private = arg;
- return true;
-}
-
-static void sh_mmcif_request_dma(struct sh_mmcif_host *host,
- struct sh_mmcif_plat_data *pdata)
-{
- struct sh_dmae_slave *tx, *rx;
- host->dma_active = false;
-
- /* We can only either use DMA for both Tx and Rx or not use it at all */
- if (pdata->dma) {
- dev_warn(&host->pd->dev,
- "Update your platform to use embedded DMA slave IDs\n");
- tx = &pdata->dma->chan_priv_tx;
- rx = &pdata->dma->chan_priv_rx;
- } else {
- tx = &host->dma_slave_tx;
- tx->slave_id = pdata->slave_id_tx;
- rx = &host->dma_slave_rx;
- rx->slave_id = pdata->slave_id_rx;
- }
- if (tx->slave_id > 0 && rx->slave_id > 0) {
- dma_cap_mask_t mask;
-
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
-
- host->chan_tx = dma_request_channel(mask, sh_mmcif_filter, tx);
- dev_dbg(&host->pd->dev, "%s: TX: got channel %p\n", __func__,
- host->chan_tx);
-
- if (!host->chan_tx)
- return;
-
- host->chan_rx = dma_request_channel(mask, sh_mmcif_filter, rx);
- dev_dbg(&host->pd->dev, "%s: RX: got channel %p\n", __func__,
- host->chan_rx);
-
- if (!host->chan_rx) {
- dma_release_channel(host->chan_tx);
- host->chan_tx = NULL;
- return;
- }
-
- init_completion(&host->dma_complete);
- }
-}
-
-static void sh_mmcif_release_dma(struct sh_mmcif_host *host)
-{
- sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
- /* Descriptors are freed automatically */
- if (host->chan_tx) {
- struct dma_chan *chan = host->chan_tx;
- host->chan_tx = NULL;
- dma_release_channel(chan);
- }
- if (host->chan_rx) {
- struct dma_chan *chan = host->chan_rx;
- host->chan_rx = NULL;
- dma_release_channel(chan);
- }
-
- host->dma_active = false;
-}
-
-static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
-{
- struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
-
- sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE);
- sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR);
-
- if (!clk)
- return;
- if (p->sup_pclk && clk == host->clk)
- sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK);
- else
- sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR &
- ((fls(DIV_ROUND_UP(host->clk,
- clk) - 1) - 1) << 16));
-
- sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE);
-}
-
-static void sh_mmcif_sync_reset(struct sh_mmcif_host *host)
-{
- u32 tmp;
-
- tmp = 0x010f0000 & sh_mmcif_readl(host->addr, MMCIF_CE_CLK_CTRL);
-
- sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_ON);
- sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_OFF);
- sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, tmp |
- SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29);
- /* byte swap on */
- sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_ATYP);
-}
-
-static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
-{
- u32 state1, state2;
- int ret, timeout;
-
- host->sd_error = false;
-
- state1 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1);
- state2 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS2);
- dev_dbg(&host->pd->dev, "ERR HOST_STS1 = %08x\n", state1);
- dev_dbg(&host->pd->dev, "ERR HOST_STS2 = %08x\n", state2);
-
- if (state1 & STS1_CMDSEQ) {
- sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK);
- sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK);
- for (timeout = 10000000; timeout; timeout--) {
- if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1)
- & STS1_CMDSEQ))
- break;
- mdelay(1);
- }
- if (!timeout) {
- dev_err(&host->pd->dev,
- "Forced end of command sequence timeout err\n");
- return -EIO;
- }
- sh_mmcif_sync_reset(host);
- dev_dbg(&host->pd->dev, "Forced end of command sequence\n");
- return -EIO;
- }
-
- if (state2 & STS2_CRC_ERR) {
- dev_dbg(&host->pd->dev, ": CRC error\n");
- ret = -EIO;
- } else if (state2 & STS2_TIMEOUT_ERR) {
- dev_dbg(&host->pd->dev, ": Timeout\n");
- ret = -ETIMEDOUT;
- } else {
- dev_dbg(&host->pd->dev, ": End/Index error\n");
- ret = -EIO;
- }
- return ret;
-}
-
-static bool sh_mmcif_next_block(struct sh_mmcif_host *host, u32 *p)
-{
- struct mmc_data *data = host->mrq->data;
-
- host->sg_blkidx += host->blocksize;
-
- /* data->sg->length must be a multiple of host->blocksize? */
- BUG_ON(host->sg_blkidx > data->sg->length);
-
- if (host->sg_blkidx == data->sg->length) {
- host->sg_blkidx = 0;
- if (++host->sg_idx < data->sg_len)
- host->pio_ptr = sg_virt(++data->sg);
- } else {
- host->pio_ptr = p;
- }
-
- if (host->sg_idx == data->sg_len)
- return false;
-
- return true;
-}
-
-static void sh_mmcif_single_read(struct sh_mmcif_host *host,
- struct mmc_request *mrq)
-{
- host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &
- BLOCK_SIZE_MASK) + 3;
-
- host->wait_for = MMCIF_WAIT_FOR_READ;
- schedule_delayed_work(&host->timeout_work, host->timeout);
-
- /* buf read enable */
- sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
-}
-
-static bool sh_mmcif_read_block(struct sh_mmcif_host *host)
-{
- struct mmc_data *data = host->mrq->data;
- u32 *p = sg_virt(data->sg);
- int i;
-
- if (host->sd_error) {
- data->error = sh_mmcif_error_manage(host);
- return false;
- }
-
- for (i = 0; i < host->blocksize / 4; i++)
- *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA);
-
- /* buffer read end */
- sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
- host->wait_for = MMCIF_WAIT_FOR_READ_END;
-
- return true;
-}
-
-static void sh_mmcif_multi_read(struct sh_mmcif_host *host,
- struct mmc_request *mrq)
-{
- struct mmc_data *data = mrq->data;
-
- if (!data->sg_len || !data->sg->length)
- return;
-
- host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &
- BLOCK_SIZE_MASK;
-
- host->wait_for = MMCIF_WAIT_FOR_MREAD;
- host->sg_idx = 0;
- host->sg_blkidx = 0;
- host->pio_ptr = sg_virt(data->sg);
- schedule_delayed_work(&host->timeout_work, host->timeout);
- sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
-}
-
-static bool sh_mmcif_mread_block(struct sh_mmcif_host *host)
-{
- struct mmc_data *data = host->mrq->data;
- u32 *p = host->pio_ptr;
- int i;
-
- if (host->sd_error) {
- data->error = sh_mmcif_error_manage(host);
- return false;
- }
-
- BUG_ON(!data->sg->length);
-
- for (i = 0; i < host->blocksize / 4; i++)
- *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA);
-
- if (!sh_mmcif_next_block(host, p))
- return false;
-
- schedule_delayed_work(&host->timeout_work, host->timeout);
- sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
-
- return true;
-}
-
-static void sh_mmcif_single_write(struct sh_mmcif_host *host,
- struct mmc_request *mrq)
-{
- host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &
- BLOCK_SIZE_MASK) + 3;
-
- host->wait_for = MMCIF_WAIT_FOR_WRITE;
- schedule_delayed_work(&host->timeout_work, host->timeout);
-
- /* buf write enable */
- sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
-}
-
-static bool sh_mmcif_write_block(struct sh_mmcif_host *host)
-{
- struct mmc_data *data = host->mrq->data;
- u32 *p = sg_virt(data->sg);
- int i;
-
- if (host->sd_error) {
- data->error = sh_mmcif_error_manage(host);
- return false;
- }
-
- for (i = 0; i < host->blocksize / 4; i++)
- sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++);
-
- /* buffer write end */
- sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);
- host->wait_for = MMCIF_WAIT_FOR_WRITE_END;
-
- return true;
-}
-
-static void sh_mmcif_multi_write(struct sh_mmcif_host *host,
- struct mmc_request *mrq)
-{
- struct mmc_data *data = mrq->data;
-
- if (!data->sg_len || !data->sg->length)
- return;
-
- host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) &
- BLOCK_SIZE_MASK;
-
- host->wait_for = MMCIF_WAIT_FOR_MWRITE;
- host->sg_idx = 0;
- host->sg_blkidx = 0;
- host->pio_ptr = sg_virt(data->sg);
- schedule_delayed_work(&host->timeout_work, host->timeout);
- sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
-}
-
-static bool sh_mmcif_mwrite_block(struct sh_mmcif_host *host)
-{
- struct mmc_data *data = host->mrq->data;
- u32 *p = host->pio_ptr;
- int i;
-
- if (host->sd_error) {
- data->error = sh_mmcif_error_manage(host);
- return false;
- }
-
- BUG_ON(!data->sg->length);
-
- for (i = 0; i < host->blocksize / 4; i++)
- sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++);
-
- if (!sh_mmcif_next_block(host, p))
- return false;
-
- schedule_delayed_work(&host->timeout_work, host->timeout);
- sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
-
- return true;
-}
-
-static void sh_mmcif_get_response(struct sh_mmcif_host *host,
- struct mmc_command *cmd)
-{
- if (cmd->flags & MMC_RSP_136) {
- cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP3);
- cmd->resp[1] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP2);
- cmd->resp[2] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP1);
- cmd->resp[3] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP0);
- } else
- cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP0);
-}
-
-static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host,
- struct mmc_command *cmd)
-{
- cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP_CMD12);
-}
-
-static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
- struct mmc_request *mrq)
-{
- struct mmc_data *data = mrq->data;
- struct mmc_command *cmd = mrq->cmd;
- u32 opc = cmd->opcode;
- u32 tmp = 0;
-
- /* Response Type check */
- switch (mmc_resp_type(cmd)) {
- case MMC_RSP_NONE:
- tmp |= CMD_SET_RTYP_NO;
- break;
- case MMC_RSP_R1:
- case MMC_RSP_R1B:
- case MMC_RSP_R3:
- tmp |= CMD_SET_RTYP_6B;
- break;
- case MMC_RSP_R2:
- tmp |= CMD_SET_RTYP_17B;
- break;
- default:
- dev_err(&host->pd->dev, "Unsupported response type.\n");
- break;
- }
- switch (opc) {
- /* RBSY */
- case MMC_SWITCH:
- case MMC_STOP_TRANSMISSION:
- case MMC_SET_WRITE_PROT:
- case MMC_CLR_WRITE_PROT:
- case MMC_ERASE:
- tmp |= CMD_SET_RBSY;
- break;
- }
- /* WDAT / DATW */
- if (data) {
- tmp |= CMD_SET_WDAT;
- switch (host->bus_width) {
- case MMC_BUS_WIDTH_1:
- tmp |= CMD_SET_DATW_1;
- break;
- case MMC_BUS_WIDTH_4:
- tmp |= CMD_SET_DATW_4;
- break;
- case MMC_BUS_WIDTH_8:
- tmp |= CMD_SET_DATW_8;
- break;
- default:
- dev_err(&host->pd->dev, "Unsupported bus width.\n");
- break;
- }
- }
- /* DWEN */
- if (opc == MMC_WRITE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK)
- tmp |= CMD_SET_DWEN;
- /* CMLTE/CMD12EN */
- if (opc == MMC_READ_MULTIPLE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) {
- tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN;
- sh_mmcif_bitset(host, MMCIF_CE_BLOCK_SET,
- data->blocks << 16);
- }
- /* RIDXC[1:0] check bits */
- if (opc == MMC_SEND_OP_COND || opc == MMC_ALL_SEND_CID ||
- opc == MMC_SEND_CSD || opc == MMC_SEND_CID)
- tmp |= CMD_SET_RIDXC_BITS;
- /* RCRC7C[1:0] check bits */
- if (opc == MMC_SEND_OP_COND)
- tmp |= CMD_SET_CRC7C_BITS;
- /* RCRC7C[1:0] internal CRC7 */
- if (opc == MMC_ALL_SEND_CID ||
- opc == MMC_SEND_CSD || opc == MMC_SEND_CID)
- tmp |= CMD_SET_CRC7C_INTERNAL;
-
- return (opc << 24) | tmp;
-}
-
-static int sh_mmcif_data_trans(struct sh_mmcif_host *host,
- struct mmc_request *mrq, u32 opc)
-{
- switch (opc) {
- case MMC_READ_MULTIPLE_BLOCK:
- sh_mmcif_multi_read(host, mrq);
- return 0;
- case MMC_WRITE_MULTIPLE_BLOCK:
- sh_mmcif_multi_write(host, mrq);
- return 0;
- case MMC_WRITE_BLOCK:
- sh_mmcif_single_write(host, mrq);
- return 0;
- case MMC_READ_SINGLE_BLOCK:
- case MMC_SEND_EXT_CSD:
- sh_mmcif_single_read(host, mrq);
- return 0;
- default:
- dev_err(&host->pd->dev, "UNSUPPORTED CMD = d'%08d\n", opc);
- return -EINVAL;
- }
-}
-
-static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
- struct mmc_request *mrq)
-{
- struct mmc_command *cmd = mrq->cmd;
- u32 opc = cmd->opcode;
- u32 mask;
-
- switch (opc) {
- /* response busy check */
- case MMC_SWITCH:
- case MMC_STOP_TRANSMISSION:
- case MMC_SET_WRITE_PROT:
- case MMC_CLR_WRITE_PROT:
- case MMC_ERASE:
- mask = MASK_START_CMD | MASK_MRBSYE;
- break;
- default:
- mask = MASK_START_CMD | MASK_MCRSPE;
- break;
- }
-
- if (mrq->data) {
- sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, 0);
- sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET,
- mrq->data->blksz);
- }
- opc = sh_mmcif_set_cmd(host, mrq);
-
- sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0);
- sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask);
- /* set arg */
- sh_mmcif_writel(host->addr, MMCIF_CE_ARG, cmd->arg);
- /* set cmd */
- sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc);
-
- host->wait_for = MMCIF_WAIT_FOR_CMD;
- schedule_delayed_work(&host->timeout_work, host->timeout);
-}
-
-static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
- struct mmc_request *mrq)
-{
- switch (mrq->cmd->opcode) {
- case MMC_READ_MULTIPLE_BLOCK:
- sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE);
- break;
- case MMC_WRITE_MULTIPLE_BLOCK:
- sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE);
- break;
- default:
- dev_err(&host->pd->dev, "unsupported stop cmd\n");
- mrq->stop->error = sh_mmcif_error_manage(host);
- return;
- }
-
- host->wait_for = MMCIF_WAIT_FOR_STOP;
- schedule_delayed_work(&host->timeout_work, host->timeout);
-}
-
-static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct sh_mmcif_host *host = mmc_priv(mmc);
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- if (host->state != STATE_IDLE) {
- spin_unlock_irqrestore(&host->lock, flags);
- mrq->cmd->error = -EAGAIN;
- mmc_request_done(mmc, mrq);
- return;
- }
-
- host->state = STATE_REQUEST;
- spin_unlock_irqrestore(&host->lock, flags);
-
- switch (mrq->cmd->opcode) {
- /* MMCIF does not support SD/SDIO command */
- case SD_IO_SEND_OP_COND:
- case MMC_APP_CMD:
- host->state = STATE_IDLE;
- mrq->cmd->error = -ETIMEDOUT;
- mmc_request_done(mmc, mrq);
- return;
- case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
- if (!mrq->data) {
- /* send_if_cond cmd (not support) */
- host->state = STATE_IDLE;
- mrq->cmd->error = -ETIMEDOUT;
- mmc_request_done(mmc, mrq);
- return;
- }
- break;
- default:
- break;
- }
-
- host->mrq = mrq;
-
- sh_mmcif_start_cmd(host, mrq);
-}
-
-static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct sh_mmcif_host *host = mmc_priv(mmc);
- struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- if (host->state != STATE_IDLE) {
- spin_unlock_irqrestore(&host->lock, flags);
- return;
- }
-
- host->state = STATE_IOS;
- spin_unlock_irqrestore(&host->lock, flags);
-
- if (ios->power_mode == MMC_POWER_UP) {
- if (!host->card_present) {
- /* See if we also get DMA */
- sh_mmcif_request_dma(host, host->pd->dev.platform_data);
- host->card_present = true;
- }
- } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) {
- /* clock stop */
- sh_mmcif_clock_control(host, 0);
- if (ios->power_mode == MMC_POWER_OFF) {
- if (host->card_present) {
- sh_mmcif_release_dma(host);
- host->card_present = false;
- }
- }
- if (host->power) {
- pm_runtime_put(&host->pd->dev);
- host->power = false;
- if (p->down_pwr && ios->power_mode == MMC_POWER_OFF)
- p->down_pwr(host->pd);
- }
- host->state = STATE_IDLE;
- return;
- }
-
- if (ios->clock) {
- if (!host->power) {
- if (p->set_pwr)
- p->set_pwr(host->pd, ios->power_mode);
- pm_runtime_get_sync(&host->pd->dev);
- host->power = true;
- sh_mmcif_sync_reset(host);
- }
- sh_mmcif_clock_control(host, ios->clock);
- }
-
- host->bus_width = ios->bus_width;
- host->state = STATE_IDLE;
-}
-
-static int sh_mmcif_get_cd(struct mmc_host *mmc)
-{
- struct sh_mmcif_host *host = mmc_priv(mmc);
- struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
-
- if (!p->get_cd)
- return -ENOSYS;
- else
- return p->get_cd(host->pd);
-}
-
-static struct mmc_host_ops sh_mmcif_ops = {
- .request = sh_mmcif_request,
- .set_ios = sh_mmcif_set_ios,
- .get_cd = sh_mmcif_get_cd,
-};
-
-static bool sh_mmcif_end_cmd(struct sh_mmcif_host *host)
-{
- struct mmc_command *cmd = host->mrq->cmd;
- struct mmc_data *data = host->mrq->data;
- long time;
-
- if (host->sd_error) {
- switch (cmd->opcode) {
- case MMC_ALL_SEND_CID:
- case MMC_SELECT_CARD:
- case MMC_APP_CMD:
- cmd->error = -ETIMEDOUT;
- host->sd_error = false;
- break;
- default:
- cmd->error = sh_mmcif_error_manage(host);
- dev_dbg(&host->pd->dev, "Cmd(d'%d) error %d\n",
- cmd->opcode, cmd->error);
- break;
- }
- return false;
- }
- if (!(cmd->flags & MMC_RSP_PRESENT)) {
- cmd->error = 0;
- return false;
- }
-
- sh_mmcif_get_response(host, cmd);
-
- if (!data)
- return false;
-
- if (data->flags & MMC_DATA_READ) {
- if (host->chan_rx)
- sh_mmcif_start_dma_rx(host);
- } else {
- if (host->chan_tx)
- sh_mmcif_start_dma_tx(host);
- }
-
- if (!host->dma_active) {
- data->error = sh_mmcif_data_trans(host, host->mrq, cmd->opcode);
- if (!data->error)
- return true;
- return false;
- }
-
- /* Running in the IRQ thread, can sleep */
- time = wait_for_completion_interruptible_timeout(&host->dma_complete,
- host->timeout);
- if (host->sd_error) {
- dev_err(host->mmc->parent,
- "Error IRQ while waiting for DMA completion!\n");
- /* Woken up by an error IRQ: abort DMA */
- if (data->flags & MMC_DATA_READ)
- dmaengine_terminate_all(host->chan_rx);
- else
- dmaengine_terminate_all(host->chan_tx);
- data->error = sh_mmcif_error_manage(host);
- } else if (!time) {
- data->error = -ETIMEDOUT;
- } else if (time < 0) {
- data->error = time;
- }
- sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC,
- BUF_ACC_DMAREN | BUF_ACC_DMAWEN);
- host->dma_active = false;
-
- if (data->error)
- data->bytes_xfered = 0;
-
- return false;
-}
-
-static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
-{
- struct sh_mmcif_host *host = dev_id;
- struct mmc_request *mrq = host->mrq;
- struct mmc_data *data = mrq->data;
-
- cancel_delayed_work_sync(&host->timeout_work);
-
- /*
- * All handlers return true, if processing continues, and false, if the
- * request has to be completed - successfully or not
- */
- switch (host->wait_for) {
- case MMCIF_WAIT_FOR_REQUEST:
- /* We're too late, the timeout has already kicked in */
- return IRQ_HANDLED;
- case MMCIF_WAIT_FOR_CMD:
- if (sh_mmcif_end_cmd(host))
- /* Wait for data */
- return IRQ_HANDLED;
- break;
- case MMCIF_WAIT_FOR_MREAD:
- if (sh_mmcif_mread_block(host))
- /* Wait for more data */
- return IRQ_HANDLED;
- break;
- case MMCIF_WAIT_FOR_READ:
- if (sh_mmcif_read_block(host))
- /* Wait for data end */
- return IRQ_HANDLED;
- break;
- case MMCIF_WAIT_FOR_MWRITE:
- if (sh_mmcif_mwrite_block(host))
- /* Wait data to write */
- return IRQ_HANDLED;
- break;
- case MMCIF_WAIT_FOR_WRITE:
- if (sh_mmcif_write_block(host))
- /* Wait for data end */
- return IRQ_HANDLED;
- break;
- case MMCIF_WAIT_FOR_STOP:
- if (host->sd_error) {
- mrq->stop->error = sh_mmcif_error_manage(host);
- break;
- }
- sh_mmcif_get_cmd12response(host, mrq->stop);
- mrq->stop->error = 0;
- break;
- case MMCIF_WAIT_FOR_READ_END:
- case MMCIF_WAIT_FOR_WRITE_END:
- if (host->sd_error)
- data->error = sh_mmcif_error_manage(host);
- break;
- default:
- BUG();
- }
-
- if (host->wait_for != MMCIF_WAIT_FOR_STOP) {
- if (!mrq->cmd->error && data && !data->error)
- data->bytes_xfered =
- data->blocks * data->blksz;
-
- if (mrq->stop && !mrq->cmd->error && (!data || !data->error)) {
- sh_mmcif_stop_cmd(host, mrq);
- if (!mrq->stop->error)
- return IRQ_HANDLED;
- }
- }
-
- host->wait_for = MMCIF_WAIT_FOR_REQUEST;
- host->state = STATE_IDLE;
- host->mrq = NULL;
- mmc_request_done(host->mmc, mrq);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
-{
- struct sh_mmcif_host *host = dev_id;
- u32 state;
- int err = 0;
-
- state = sh_mmcif_readl(host->addr, MMCIF_CE_INT);
-
- if (state & INT_ERR_STS) {
- /* error interrupts - process first */
- sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
- sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
- err = 1;
- } else if (state & INT_RBSYE) {
- sh_mmcif_writel(host->addr, MMCIF_CE_INT,
- ~(INT_RBSYE | INT_CRSPE));
- sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MRBSYE);
- } else if (state & INT_CRSPE) {
- sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_CRSPE);
- sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCRSPE);
- } else if (state & INT_BUFREN) {
- sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFREN);
- sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
- } else if (state & INT_BUFWEN) {
- sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFWEN);
- sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
- } else if (state & INT_CMD12DRE) {
- sh_mmcif_writel(host->addr, MMCIF_CE_INT,
- ~(INT_CMD12DRE | INT_CMD12RBE |
- INT_CMD12CRE | INT_BUFRE));
- sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE);
- } else if (state & INT_BUFRE) {
- sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFRE);
- sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
- } else if (state & INT_DTRANE) {
- sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_DTRANE);
- sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);
- } else if (state & INT_CMD12RBE) {
- sh_mmcif_writel(host->addr, MMCIF_CE_INT,
- ~(INT_CMD12RBE | INT_CMD12CRE));
- sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE);
- } else {
- dev_dbg(&host->pd->dev, "Unsupported interrupt: 0x%x\n", state);
- sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
- sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
- err = 1;
- }
- if (err) {
- host->sd_error = true;
- dev_dbg(&host->pd->dev, "int err state = %08x\n", state);
- }
- if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) {
- if (!host->dma_active)
- return IRQ_WAKE_THREAD;
- else if (host->sd_error)
- mmcif_dma_complete(host);
- } else {
- dev_dbg(&host->pd->dev, "Unexpected IRQ 0x%x\n", state);
- }
-
- return IRQ_HANDLED;
-}
-
-static void mmcif_timeout_work(struct work_struct *work)
-{
- struct delayed_work *d = container_of(work, struct delayed_work, work);
- struct sh_mmcif_host *host = container_of(d, struct sh_mmcif_host, timeout_work);
- struct mmc_request *mrq = host->mrq;
-
- if (host->dying)
- /* Don't run after mmc_remove_host() */
- return;
-
- /*
- * Handle races with cancel_delayed_work(), unless
- * cancel_delayed_work_sync() is used
- */
- switch (host->wait_for) {
- case MMCIF_WAIT_FOR_CMD:
- mrq->cmd->error = sh_mmcif_error_manage(host);
- break;
- case MMCIF_WAIT_FOR_STOP:
- mrq->stop->error = sh_mmcif_error_manage(host);
- break;
- case MMCIF_WAIT_FOR_MREAD:
- case MMCIF_WAIT_FOR_MWRITE:
- case MMCIF_WAIT_FOR_READ:
- case MMCIF_WAIT_FOR_WRITE:
- case MMCIF_WAIT_FOR_READ_END:
- case MMCIF_WAIT_FOR_WRITE_END:
- mrq->data->error = sh_mmcif_error_manage(host);
- break;
- default:
- BUG();
- }
-
- host->state = STATE_IDLE;
- host->wait_for = MMCIF_WAIT_FOR_REQUEST;
- host->mrq = NULL;
- mmc_request_done(host->mmc, mrq);
-}
-
-static int __devinit sh_mmcif_probe(struct platform_device *pdev)
-{
- int ret = 0, irq[2];
- struct mmc_host *mmc;
- struct sh_mmcif_host *host;
- struct sh_mmcif_plat_data *pd;
- struct resource *res;
- void __iomem *reg;
- char clk_name[8];
-
- irq[0] = platform_get_irq(pdev, 0);
- irq[1] = platform_get_irq(pdev, 1);
- if (irq[0] < 0 || irq[1] < 0) {
- dev_err(&pdev->dev, "Get irq error\n");
- return -ENXIO;
- }
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "platform_get_resource error.\n");
- return -ENXIO;
- }
- reg = ioremap(res->start, resource_size(res));
- if (!reg) {
- dev_err(&pdev->dev, "ioremap error.\n");
- return -ENOMEM;
- }
- pd = pdev->dev.platform_data;
- if (!pd) {
- dev_err(&pdev->dev, "sh_mmcif plat data error.\n");
- ret = -ENXIO;
- goto clean_up;
- }
- mmc = mmc_alloc_host(sizeof(struct sh_mmcif_host), &pdev->dev);
- if (!mmc) {
- ret = -ENOMEM;
- goto clean_up;
- }
- host = mmc_priv(mmc);
- host->mmc = mmc;
- host->addr = reg;
- host->timeout = 1000;
-
- snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id);
- host->hclk = clk_get(&pdev->dev, clk_name);
- if (IS_ERR(host->hclk)) {
- dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
- ret = PTR_ERR(host->hclk);
- goto clean_up1;
- }
- clk_enable(host->hclk);
- host->clk = clk_get_rate(host->hclk);
- host->pd = pdev;
-
- spin_lock_init(&host->lock);
-
- mmc->ops = &sh_mmcif_ops;
- mmc->f_max = host->clk / 2;
- mmc->f_min = host->clk / 512;
- if (pd->ocr)
- mmc->ocr_avail = pd->ocr;
- mmc->caps = MMC_CAP_MMC_HIGHSPEED;
- if (pd->caps)
- mmc->caps |= pd->caps;
- mmc->max_segs = 32;
- mmc->max_blk_size = 512;
- mmc->max_req_size = PAGE_CACHE_SIZE * mmc->max_segs;
- mmc->max_blk_count = mmc->max_req_size / mmc->max_blk_size;
- mmc->max_seg_size = mmc->max_req_size;
-
- sh_mmcif_sync_reset(host);
- platform_set_drvdata(pdev, host);
-
- pm_runtime_enable(&pdev->dev);
- host->power = false;
-
- ret = pm_runtime_resume(&pdev->dev);
- if (ret < 0)
- goto clean_up2;
-
- INIT_DELAYED_WORK(&host->timeout_work, mmcif_timeout_work);
-
- sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
-
- ret = request_threaded_irq(irq[0], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:error", host);
- if (ret) {
- dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n");
- goto clean_up3;
- }
- ret = request_threaded_irq(irq[1], sh_mmcif_intr, sh_mmcif_irqt, 0, "sh_mmc:int", host);
- if (ret) {
- dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n");
- goto clean_up4;
- }
-
- ret = mmc_add_host(mmc);
- if (ret < 0)
- goto clean_up5;
-
- dev_pm_qos_expose_latency_limit(&pdev->dev, 100);
-
- dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION);
- dev_dbg(&pdev->dev, "chip ver H'%04x\n",
- sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff);
- return ret;
-
-clean_up5:
- free_irq(irq[1], host);
-clean_up4:
- free_irq(irq[0], host);
-clean_up3:
- pm_runtime_suspend(&pdev->dev);
-clean_up2:
- pm_runtime_disable(&pdev->dev);
- clk_disable(host->hclk);
-clean_up1:
- mmc_free_host(mmc);
-clean_up:
- if (reg)
- iounmap(reg);
- return ret;
-}
-
-static int __devexit sh_mmcif_remove(struct platform_device *pdev)
-{
- struct sh_mmcif_host *host = platform_get_drvdata(pdev);
- int irq[2];
-
- host->dying = true;
- pm_runtime_get_sync(&pdev->dev);
-
- dev_pm_qos_hide_latency_limit(&pdev->dev);
-
- mmc_remove_host(host->mmc);
- sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
-
- /*
- * FIXME: cancel_delayed_work(_sync)() and free_irq() race with the
- * mmc_remove_host() call above. But swapping order doesn't help either
- * (a query on the linux-mmc mailing list didn't bring any replies).
- */
- cancel_delayed_work_sync(&host->timeout_work);
-
- if (host->addr)
- iounmap(host->addr);
-
- irq[0] = platform_get_irq(pdev, 0);
- irq[1] = platform_get_irq(pdev, 1);
-
- free_irq(irq[0], host);
- free_irq(irq[1], host);
-
- platform_set_drvdata(pdev, NULL);
-
- clk_disable(host->hclk);
- mmc_free_host(host->mmc);
- pm_runtime_put_sync(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int sh_mmcif_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct sh_mmcif_host *host = platform_get_drvdata(pdev);
- int ret = mmc_suspend_host(host->mmc);
-
- if (!ret) {
- sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
- clk_disable(host->hclk);
- }
-
- return ret;
-}
-
-static int sh_mmcif_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct sh_mmcif_host *host = platform_get_drvdata(pdev);
-
- clk_enable(host->hclk);
-
- return mmc_resume_host(host->mmc);
-}
-#else
-#define sh_mmcif_suspend NULL
-#define sh_mmcif_resume NULL
-#endif /* CONFIG_PM */
-
-static const struct dev_pm_ops sh_mmcif_dev_pm_ops = {
- .suspend = sh_mmcif_suspend,
- .resume = sh_mmcif_resume,
-};
-
-static struct platform_driver sh_mmcif_driver = {
- .probe = sh_mmcif_probe,
- .remove = sh_mmcif_remove,
- .driver = {
- .name = DRIVER_NAME,
- .pm = &sh_mmcif_dev_pm_ops,
- },
-};
-
-module_platform_driver(sh_mmcif_driver);
-
-MODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRIVER_NAME);
-MODULE_AUTHOR("Yusuke Goda <yusuke.goda.sx@renesas.com>");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/sh_mobile_sdhi.c b/ANDROID_3.4.5/drivers/mmc/host/sh_mobile_sdhi.c
deleted file mode 100644
index 934b68e9..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/sh_mobile_sdhi.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * SuperH Mobile SDHI
- *
- * Copyright (C) 2009 Magnus Damm
- *
- * 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.
- *
- * Based on "Compaq ASIC3 support":
- *
- * Copyright 2001 Compaq Computer Corporation.
- * Copyright 2004-2005 Phil Blundell
- * Copyright 2007-2008 OpenedHand Ltd.
- *
- * Authors: Phil Blundell <pb@handhelds.org>,
- * Samuel Ortiz <sameo@openedhand.com>
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/sh_mobile_sdhi.h>
-#include <linux/mfd/tmio.h>
-#include <linux/sh_dma.h>
-#include <linux/delay.h>
-
-#include "tmio_mmc.h"
-
-struct sh_mobile_sdhi {
- struct clk *clk;
- struct tmio_mmc_data mmc_data;
- struct sh_dmae_slave param_tx;
- struct sh_dmae_slave param_rx;
- struct tmio_mmc_dma dma_priv;
-};
-
-static void sh_mobile_sdhi_set_pwr(struct platform_device *pdev, int state)
-{
- struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
-
- if (p && p->set_pwr)
- p->set_pwr(pdev, state);
-}
-
-static int sh_mobile_sdhi_get_cd(struct platform_device *pdev)
-{
- struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
-
- if (p && p->get_cd)
- return p->get_cd(pdev);
- else
- return -ENOSYS;
-}
-
-static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host)
-{
- int timeout = 1000;
-
- while (--timeout && !(sd_ctrl_read16(host, CTL_STATUS2) & (1 << 13)))
- udelay(1);
-
- if (!timeout) {
- dev_warn(host->pdata->dev, "timeout waiting for SD bus idle\n");
- return -EBUSY;
- }
-
- return 0;
-}
-
-static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
-{
- switch (addr)
- {
- case CTL_SD_CMD:
- case CTL_STOP_INTERNAL_ACTION:
- case CTL_XFER_BLK_COUNT:
- case CTL_SD_CARD_CLK_CTL:
- case CTL_SD_XFER_LEN:
- case CTL_SD_MEM_CARD_OPT:
- case CTL_TRANSACTION_CTL:
- case CTL_DMA_ENABLE:
- return sh_mobile_sdhi_wait_idle(host);
- }
-
- return 0;
-}
-
-static void sh_mobile_sdhi_cd_wakeup(const struct platform_device *pdev)
-{
- mmc_detect_change(dev_get_drvdata(&pdev->dev), msecs_to_jiffies(100));
-}
-
-static const struct sh_mobile_sdhi_ops sdhi_ops = {
- .cd_wakeup = sh_mobile_sdhi_cd_wakeup,
-};
-
-static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
-{
- struct sh_mobile_sdhi *priv;
- struct tmio_mmc_data *mmc_data;
- struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
- struct tmio_mmc_host *host;
- char clk_name[8];
- int irq, ret, i = 0;
- bool multiplexed_isr = true;
-
- priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL);
- if (priv == NULL) {
- dev_err(&pdev->dev, "kzalloc failed\n");
- return -ENOMEM;
- }
-
- mmc_data = &priv->mmc_data;
- p->pdata = mmc_data;
-
- if (p->init) {
- ret = p->init(pdev, &sdhi_ops);
- if (ret)
- goto einit;
- }
-
- snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
- priv->clk = clk_get(&pdev->dev, clk_name);
- if (IS_ERR(priv->clk)) {
- dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
- ret = PTR_ERR(priv->clk);
- goto eclkget;
- }
-
- mmc_data->hclk = clk_get_rate(priv->clk);
- mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
- mmc_data->get_cd = sh_mobile_sdhi_get_cd;
- mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED;
- if (p) {
- mmc_data->flags = p->tmio_flags;
- if (mmc_data->flags & TMIO_MMC_HAS_IDLE_WAIT)
- mmc_data->write16_hook = sh_mobile_sdhi_write16_hook;
- mmc_data->ocr_mask = p->tmio_ocr_mask;
- mmc_data->capabilities |= p->tmio_caps;
- mmc_data->cd_gpio = p->cd_gpio;
-
- if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) {
- priv->param_tx.slave_id = p->dma_slave_tx;
- priv->param_rx.slave_id = p->dma_slave_rx;
- priv->dma_priv.chan_priv_tx = &priv->param_tx;
- priv->dma_priv.chan_priv_rx = &priv->param_rx;
- priv->dma_priv.alignment_shift = 1; /* 2-byte alignment */
- mmc_data->dma = &priv->dma_priv;
- }
- }
-
- /*
- * All SDHI blocks support 2-byte and larger block sizes in 4-bit
- * bus width mode.
- */
- mmc_data->flags |= TMIO_MMC_BLKSZ_2BYTES;
-
- /*
- * All SDHI blocks support SDIO IRQ signalling.
- */
- mmc_data->flags |= TMIO_MMC_SDIO_IRQ;
-
- ret = tmio_mmc_host_probe(&host, pdev, mmc_data);
- if (ret < 0)
- goto eprobe;
-
- /*
- * Allow one or more specific (named) ISRs or
- * one or more multiplexed (un-named) ISRs.
- */
-
- irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_CARD_DETECT);
- if (irq >= 0) {
- multiplexed_isr = false;
- ret = request_irq(irq, tmio_mmc_card_detect_irq, 0,
- dev_name(&pdev->dev), host);
- if (ret)
- goto eirq_card_detect;
- }
-
- irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDIO);
- if (irq >= 0) {
- multiplexed_isr = false;
- ret = request_irq(irq, tmio_mmc_sdio_irq, 0,
- dev_name(&pdev->dev), host);
- if (ret)
- goto eirq_sdio;
- }
-
- irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDCARD);
- if (irq >= 0) {
- multiplexed_isr = false;
- ret = request_irq(irq, tmio_mmc_sdcard_irq, 0,
- dev_name(&pdev->dev), host);
- if (ret)
- goto eirq_sdcard;
- } else if (!multiplexed_isr) {
- dev_err(&pdev->dev,
- "Principal SD-card IRQ is missing among named interrupts\n");
- ret = irq;
- goto eirq_sdcard;
- }
-
- if (multiplexed_isr) {
- while (1) {
- irq = platform_get_irq(pdev, i);
- if (irq < 0)
- break;
- i++;
- ret = request_irq(irq, tmio_mmc_irq, 0,
- dev_name(&pdev->dev), host);
- if (ret)
- goto eirq_multiplexed;
- }
-
- /* There must be at least one IRQ source */
- if (!i)
- goto eirq_multiplexed;
- }
-
- dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n",
- mmc_hostname(host->mmc), (unsigned long)
- (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start),
- mmc_data->hclk / 1000000);
-
- return ret;
-
-eirq_multiplexed:
- while (i--) {
- irq = platform_get_irq(pdev, i);
- free_irq(irq, host);
- }
-eirq_sdcard:
- irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDIO);
- if (irq >= 0)
- free_irq(irq, host);
-eirq_sdio:
- irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_CARD_DETECT);
- if (irq >= 0)
- free_irq(irq, host);
-eirq_card_detect:
- tmio_mmc_host_remove(host);
-eprobe:
- clk_put(priv->clk);
-eclkget:
- if (p->cleanup)
- p->cleanup(pdev);
-einit:
- kfree(priv);
- return ret;
-}
-
-static int sh_mobile_sdhi_remove(struct platform_device *pdev)
-{
- struct mmc_host *mmc = platform_get_drvdata(pdev);
- struct tmio_mmc_host *host = mmc_priv(mmc);
- struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
- struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
- int i = 0, irq;
-
- p->pdata = NULL;
-
- tmio_mmc_host_remove(host);
-
- while (1) {
- irq = platform_get_irq(pdev, i++);
- if (irq < 0)
- break;
- free_irq(irq, host);
- }
-
- clk_put(priv->clk);
-
- if (p->cleanup)
- p->cleanup(pdev);
-
- kfree(priv);
-
- return 0;
-}
-
-static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
- .suspend = tmio_mmc_host_suspend,
- .resume = tmio_mmc_host_resume,
- .runtime_suspend = tmio_mmc_host_runtime_suspend,
- .runtime_resume = tmio_mmc_host_runtime_resume,
-};
-
-static struct platform_driver sh_mobile_sdhi_driver = {
- .driver = {
- .name = "sh_mobile_sdhi",
- .owner = THIS_MODULE,
- .pm = &tmio_mmc_dev_pm_ops,
- },
- .probe = sh_mobile_sdhi_probe,
- .remove = __devexit_p(sh_mobile_sdhi_remove),
-};
-
-module_platform_driver(sh_mobile_sdhi_driver);
-
-MODULE_DESCRIPTION("SuperH Mobile SDHI driver");
-MODULE_AUTHOR("Magnus Damm");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:sh_mobile_sdhi");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/tifm_sd.c b/ANDROID_3.4.5/drivers/mmc/host/tifm_sd.c
deleted file mode 100644
index 43d96282..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/tifm_sd.c
+++ /dev/null
@@ -1,1093 +0,0 @@
-/*
- * tifm_sd.c - TI FlashMedia driver
- *
- * Copyright (C) 2006 Alex Dubov <oakad@yahoo.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.
- *
- * Special thanks to Brad Campbell for extensive testing of this driver.
- *
- */
-
-
-#include <linux/tifm.h>
-#include <linux/mmc/host.h>
-#include <linux/highmem.h>
-#include <linux/scatterlist.h>
-#include <linux/module.h>
-#include <asm/io.h>
-
-#define DRIVER_NAME "tifm_sd"
-#define DRIVER_VERSION "0.8"
-
-static bool no_dma = 0;
-static bool fixed_timeout = 0;
-module_param(no_dma, bool, 0644);
-module_param(fixed_timeout, bool, 0644);
-
-/* Constants here are mostly from OMAP5912 datasheet */
-#define TIFM_MMCSD_RESET 0x0002
-#define TIFM_MMCSD_CLKMASK 0x03ff
-#define TIFM_MMCSD_POWER 0x0800
-#define TIFM_MMCSD_4BBUS 0x8000
-#define TIFM_MMCSD_RXDE 0x8000 /* rx dma enable */
-#define TIFM_MMCSD_TXDE 0x0080 /* tx dma enable */
-#define TIFM_MMCSD_BUFINT 0x0c00 /* set bits: AE, AF */
-#define TIFM_MMCSD_DPE 0x0020 /* data timeout counted in kilocycles */
-#define TIFM_MMCSD_INAB 0x0080 /* abort / initialize command */
-#define TIFM_MMCSD_READ 0x8000
-
-#define TIFM_MMCSD_ERRMASK 0x01e0 /* set bits: CCRC, CTO, DCRC, DTO */
-#define TIFM_MMCSD_EOC 0x0001 /* end of command phase */
-#define TIFM_MMCSD_CD 0x0002 /* card detect */
-#define TIFM_MMCSD_CB 0x0004 /* card enter busy state */
-#define TIFM_MMCSD_BRS 0x0008 /* block received/sent */
-#define TIFM_MMCSD_EOFB 0x0010 /* card exit busy state */
-#define TIFM_MMCSD_DTO 0x0020 /* data time-out */
-#define TIFM_MMCSD_DCRC 0x0040 /* data crc error */
-#define TIFM_MMCSD_CTO 0x0080 /* command time-out */
-#define TIFM_MMCSD_CCRC 0x0100 /* command crc error */
-#define TIFM_MMCSD_AF 0x0400 /* fifo almost full */
-#define TIFM_MMCSD_AE 0x0800 /* fifo almost empty */
-#define TIFM_MMCSD_OCRB 0x1000 /* OCR busy */
-#define TIFM_MMCSD_CIRQ 0x2000 /* card irq (cmd40/sdio) */
-#define TIFM_MMCSD_CERR 0x4000 /* card status error */
-
-#define TIFM_MMCSD_ODTO 0x0040 /* open drain / extended timeout */
-#define TIFM_MMCSD_CARD_RO 0x0200 /* card is read-only */
-
-#define TIFM_MMCSD_FIFO_SIZE 0x0020
-
-#define TIFM_MMCSD_RSP_R0 0x0000
-#define TIFM_MMCSD_RSP_R1 0x0100
-#define TIFM_MMCSD_RSP_R2 0x0200
-#define TIFM_MMCSD_RSP_R3 0x0300
-#define TIFM_MMCSD_RSP_R4 0x0400
-#define TIFM_MMCSD_RSP_R5 0x0500
-#define TIFM_MMCSD_RSP_R6 0x0600
-
-#define TIFM_MMCSD_RSP_BUSY 0x0800
-
-#define TIFM_MMCSD_CMD_BC 0x0000
-#define TIFM_MMCSD_CMD_BCR 0x1000
-#define TIFM_MMCSD_CMD_AC 0x2000
-#define TIFM_MMCSD_CMD_ADTC 0x3000
-
-#define TIFM_MMCSD_MAX_BLOCK_SIZE 0x0800UL
-
-enum {
- CMD_READY = 0x0001,
- FIFO_READY = 0x0002,
- BRS_READY = 0x0004,
- SCMD_ACTIVE = 0x0008,
- SCMD_READY = 0x0010,
- CARD_BUSY = 0x0020,
- DATA_CARRY = 0x0040
-};
-
-struct tifm_sd {
- struct tifm_dev *dev;
-
- unsigned short eject:1,
- open_drain:1,
- no_dma:1;
- unsigned short cmd_flags;
-
- unsigned int clk_freq;
- unsigned int clk_div;
- unsigned long timeout_jiffies;
-
- struct tasklet_struct finish_tasklet;
- struct timer_list timer;
- struct mmc_request *req;
-
- int sg_len;
- int sg_pos;
- unsigned int block_pos;
- struct scatterlist bounce_buf;
- unsigned char bounce_buf_data[TIFM_MMCSD_MAX_BLOCK_SIZE];
-};
-
-/* for some reason, host won't respond correctly to readw/writew */
-static void tifm_sd_read_fifo(struct tifm_sd *host, struct page *pg,
- unsigned int off, unsigned int cnt)
-{
- struct tifm_dev *sock = host->dev;
- unsigned char *buf;
- unsigned int pos = 0, val;
-
- buf = kmap_atomic(pg) + off;
- if (host->cmd_flags & DATA_CARRY) {
- buf[pos++] = host->bounce_buf_data[0];
- host->cmd_flags &= ~DATA_CARRY;
- }
-
- while (pos < cnt) {
- val = readl(sock->addr + SOCK_MMCSD_DATA);
- buf[pos++] = val & 0xff;
- if (pos == cnt) {
- host->bounce_buf_data[0] = (val >> 8) & 0xff;
- host->cmd_flags |= DATA_CARRY;
- break;
- }
- buf[pos++] = (val >> 8) & 0xff;
- }
- kunmap_atomic(buf - off);
-}
-
-static void tifm_sd_write_fifo(struct tifm_sd *host, struct page *pg,
- unsigned int off, unsigned int cnt)
-{
- struct tifm_dev *sock = host->dev;
- unsigned char *buf;
- unsigned int pos = 0, val;
-
- buf = kmap_atomic(pg) + off;
- if (host->cmd_flags & DATA_CARRY) {
- val = host->bounce_buf_data[0] | ((buf[pos++] << 8) & 0xff00);
- writel(val, sock->addr + SOCK_MMCSD_DATA);
- host->cmd_flags &= ~DATA_CARRY;
- }
-
- while (pos < cnt) {
- val = buf[pos++];
- if (pos == cnt) {
- host->bounce_buf_data[0] = val & 0xff;
- host->cmd_flags |= DATA_CARRY;
- break;
- }
- val |= (buf[pos++] << 8) & 0xff00;
- writel(val, sock->addr + SOCK_MMCSD_DATA);
- }
- kunmap_atomic(buf - off);
-}
-
-static void tifm_sd_transfer_data(struct tifm_sd *host)
-{
- struct mmc_data *r_data = host->req->cmd->data;
- struct scatterlist *sg = r_data->sg;
- unsigned int off, cnt, t_size = TIFM_MMCSD_FIFO_SIZE * 2;
- unsigned int p_off, p_cnt;
- struct page *pg;
-
- if (host->sg_pos == host->sg_len)
- return;
- while (t_size) {
- cnt = sg[host->sg_pos].length - host->block_pos;
- if (!cnt) {
- host->block_pos = 0;
- host->sg_pos++;
- if (host->sg_pos == host->sg_len) {
- if ((r_data->flags & MMC_DATA_WRITE)
- && (host->cmd_flags & DATA_CARRY))
- writel(host->bounce_buf_data[0],
- host->dev->addr
- + SOCK_MMCSD_DATA);
-
- return;
- }
- cnt = sg[host->sg_pos].length;
- }
- off = sg[host->sg_pos].offset + host->block_pos;
-
- pg = nth_page(sg_page(&sg[host->sg_pos]), off >> PAGE_SHIFT);
- p_off = offset_in_page(off);
- p_cnt = PAGE_SIZE - p_off;
- p_cnt = min(p_cnt, cnt);
- p_cnt = min(p_cnt, t_size);
-
- if (r_data->flags & MMC_DATA_READ)
- tifm_sd_read_fifo(host, pg, p_off, p_cnt);
- else if (r_data->flags & MMC_DATA_WRITE)
- tifm_sd_write_fifo(host, pg, p_off, p_cnt);
-
- t_size -= p_cnt;
- host->block_pos += p_cnt;
- }
-}
-
-static void tifm_sd_copy_page(struct page *dst, unsigned int dst_off,
- struct page *src, unsigned int src_off,
- unsigned int count)
-{
- unsigned char *src_buf = kmap_atomic(src) + src_off;
- unsigned char *dst_buf = kmap_atomic(dst) + dst_off;
-
- memcpy(dst_buf, src_buf, count);
-
- kunmap_atomic(dst_buf - dst_off);
- kunmap_atomic(src_buf - src_off);
-}
-
-static void tifm_sd_bounce_block(struct tifm_sd *host, struct mmc_data *r_data)
-{
- struct scatterlist *sg = r_data->sg;
- unsigned int t_size = r_data->blksz;
- unsigned int off, cnt;
- unsigned int p_off, p_cnt;
- struct page *pg;
-
- dev_dbg(&host->dev->dev, "bouncing block\n");
- while (t_size) {
- cnt = sg[host->sg_pos].length - host->block_pos;
- if (!cnt) {
- host->block_pos = 0;
- host->sg_pos++;
- if (host->sg_pos == host->sg_len)
- return;
- cnt = sg[host->sg_pos].length;
- }
- off = sg[host->sg_pos].offset + host->block_pos;
-
- pg = nth_page(sg_page(&sg[host->sg_pos]), off >> PAGE_SHIFT);
- p_off = offset_in_page(off);
- p_cnt = PAGE_SIZE - p_off;
- p_cnt = min(p_cnt, cnt);
- p_cnt = min(p_cnt, t_size);
-
- if (r_data->flags & MMC_DATA_WRITE)
- tifm_sd_copy_page(sg_page(&host->bounce_buf),
- r_data->blksz - t_size,
- pg, p_off, p_cnt);
- else if (r_data->flags & MMC_DATA_READ)
- tifm_sd_copy_page(pg, p_off, sg_page(&host->bounce_buf),
- r_data->blksz - t_size, p_cnt);
-
- t_size -= p_cnt;
- host->block_pos += p_cnt;
- }
-}
-
-static int tifm_sd_set_dma_data(struct tifm_sd *host, struct mmc_data *r_data)
-{
- struct tifm_dev *sock = host->dev;
- unsigned int t_size = TIFM_DMA_TSIZE * r_data->blksz;
- unsigned int dma_len, dma_blk_cnt, dma_off;
- struct scatterlist *sg = NULL;
- unsigned long flags;
-
- if (host->sg_pos == host->sg_len)
- return 1;
-
- if (host->cmd_flags & DATA_CARRY) {
- host->cmd_flags &= ~DATA_CARRY;
- local_irq_save(flags);
- tifm_sd_bounce_block(host, r_data);
- local_irq_restore(flags);
- if (host->sg_pos == host->sg_len)
- return 1;
- }
-
- dma_len = sg_dma_len(&r_data->sg[host->sg_pos]) - host->block_pos;
- if (!dma_len) {
- host->block_pos = 0;
- host->sg_pos++;
- if (host->sg_pos == host->sg_len)
- return 1;
- dma_len = sg_dma_len(&r_data->sg[host->sg_pos]);
- }
-
- if (dma_len < t_size) {
- dma_blk_cnt = dma_len / r_data->blksz;
- dma_off = host->block_pos;
- host->block_pos += dma_blk_cnt * r_data->blksz;
- } else {
- dma_blk_cnt = TIFM_DMA_TSIZE;
- dma_off = host->block_pos;
- host->block_pos += t_size;
- }
-
- if (dma_blk_cnt)
- sg = &r_data->sg[host->sg_pos];
- else if (dma_len) {
- if (r_data->flags & MMC_DATA_WRITE) {
- local_irq_save(flags);
- tifm_sd_bounce_block(host, r_data);
- local_irq_restore(flags);
- } else
- host->cmd_flags |= DATA_CARRY;
-
- sg = &host->bounce_buf;
- dma_off = 0;
- dma_blk_cnt = 1;
- } else
- return 1;
-
- dev_dbg(&sock->dev, "setting dma for %d blocks\n", dma_blk_cnt);
- writel(sg_dma_address(sg) + dma_off, sock->addr + SOCK_DMA_ADDRESS);
- if (r_data->flags & MMC_DATA_WRITE)
- writel((dma_blk_cnt << 8) | TIFM_DMA_TX | TIFM_DMA_EN,
- sock->addr + SOCK_DMA_CONTROL);
- else
- writel((dma_blk_cnt << 8) | TIFM_DMA_EN,
- sock->addr + SOCK_DMA_CONTROL);
-
- return 0;
-}
-
-static unsigned int tifm_sd_op_flags(struct mmc_command *cmd)
-{
- unsigned int rc = 0;
-
- switch (mmc_resp_type(cmd)) {
- case MMC_RSP_NONE:
- rc |= TIFM_MMCSD_RSP_R0;
- break;
- case MMC_RSP_R1B:
- rc |= TIFM_MMCSD_RSP_BUSY; // deliberate fall-through
- case MMC_RSP_R1:
- rc |= TIFM_MMCSD_RSP_R1;
- break;
- case MMC_RSP_R2:
- rc |= TIFM_MMCSD_RSP_R2;
- break;
- case MMC_RSP_R3:
- rc |= TIFM_MMCSD_RSP_R3;
- break;
- default:
- BUG();
- }
-
- switch (mmc_cmd_type(cmd)) {
- case MMC_CMD_BC:
- rc |= TIFM_MMCSD_CMD_BC;
- break;
- case MMC_CMD_BCR:
- rc |= TIFM_MMCSD_CMD_BCR;
- break;
- case MMC_CMD_AC:
- rc |= TIFM_MMCSD_CMD_AC;
- break;
- case MMC_CMD_ADTC:
- rc |= TIFM_MMCSD_CMD_ADTC;
- break;
- default:
- BUG();
- }
- return rc;
-}
-
-static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd)
-{
- struct tifm_dev *sock = host->dev;
- unsigned int cmd_mask = tifm_sd_op_flags(cmd);
-
- if (host->open_drain)
- cmd_mask |= TIFM_MMCSD_ODTO;
-
- if (cmd->data && (cmd->data->flags & MMC_DATA_READ))
- cmd_mask |= TIFM_MMCSD_READ;
-
- dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n",
- cmd->opcode, cmd->arg, cmd_mask);
-
- writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH);
- writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW);
- writel(cmd->opcode | cmd_mask, sock->addr + SOCK_MMCSD_COMMAND);
-}
-
-static void tifm_sd_fetch_resp(struct mmc_command *cmd, struct tifm_dev *sock)
-{
- cmd->resp[0] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x1c) << 16)
- | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x18);
- cmd->resp[1] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x14) << 16)
- | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x10);
- cmd->resp[2] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x0c) << 16)
- | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x08);
- cmd->resp[3] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x04) << 16)
- | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x00);
-}
-
-static void tifm_sd_check_status(struct tifm_sd *host)
-{
- struct tifm_dev *sock = host->dev;
- struct mmc_command *cmd = host->req->cmd;
-
- if (cmd->error)
- goto finish_request;
-
- if (!(host->cmd_flags & CMD_READY))
- return;
-
- if (cmd->data) {
- if (cmd->data->error) {
- if ((host->cmd_flags & SCMD_ACTIVE)
- && !(host->cmd_flags & SCMD_READY))
- return;
-
- goto finish_request;
- }
-
- if (!(host->cmd_flags & BRS_READY))
- return;
-
- if (!(host->no_dma || (host->cmd_flags & FIFO_READY)))
- return;
-
- if (cmd->data->flags & MMC_DATA_WRITE) {
- if (host->req->stop) {
- if (!(host->cmd_flags & SCMD_ACTIVE)) {
- host->cmd_flags |= SCMD_ACTIVE;
- writel(TIFM_MMCSD_EOFB
- | readl(sock->addr
- + SOCK_MMCSD_INT_ENABLE),
- sock->addr
- + SOCK_MMCSD_INT_ENABLE);
- tifm_sd_exec(host, host->req->stop);
- return;
- } else {
- if (!(host->cmd_flags & SCMD_READY)
- || (host->cmd_flags & CARD_BUSY))
- return;
- writel((~TIFM_MMCSD_EOFB)
- & readl(sock->addr
- + SOCK_MMCSD_INT_ENABLE),
- sock->addr
- + SOCK_MMCSD_INT_ENABLE);
- }
- } else {
- if (host->cmd_flags & CARD_BUSY)
- return;
- writel((~TIFM_MMCSD_EOFB)
- & readl(sock->addr
- + SOCK_MMCSD_INT_ENABLE),
- sock->addr + SOCK_MMCSD_INT_ENABLE);
- }
- } else {
- if (host->req->stop) {
- if (!(host->cmd_flags & SCMD_ACTIVE)) {
- host->cmd_flags |= SCMD_ACTIVE;
- tifm_sd_exec(host, host->req->stop);
- return;
- } else {
- if (!(host->cmd_flags & SCMD_READY))
- return;
- }
- }
- }
- }
-finish_request:
- tasklet_schedule(&host->finish_tasklet);
-}
-
-/* Called from interrupt handler */
-static void tifm_sd_data_event(struct tifm_dev *sock)
-{
- struct tifm_sd *host;
- unsigned int fifo_status = 0;
- struct mmc_data *r_data = NULL;
-
- spin_lock(&sock->lock);
- host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
- fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
- dev_dbg(&sock->dev, "data event: fifo_status %x, flags %x\n",
- fifo_status, host->cmd_flags);
-
- if (host->req) {
- r_data = host->req->cmd->data;
-
- if (r_data && (fifo_status & TIFM_FIFO_READY)) {
- if (tifm_sd_set_dma_data(host, r_data)) {
- host->cmd_flags |= FIFO_READY;
- tifm_sd_check_status(host);
- }
- }
- }
-
- writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS);
- spin_unlock(&sock->lock);
-}
-
-/* Called from interrupt handler */
-static void tifm_sd_card_event(struct tifm_dev *sock)
-{
- struct tifm_sd *host;
- unsigned int host_status = 0;
- int cmd_error = 0;
- struct mmc_command *cmd = NULL;
- unsigned long flags;
-
- spin_lock(&sock->lock);
- host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
- host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
- dev_dbg(&sock->dev, "host event: host_status %x, flags %x\n",
- host_status, host->cmd_flags);
-
- if (host->req) {
- cmd = host->req->cmd;
-
- if (host_status & TIFM_MMCSD_ERRMASK) {
- writel(host_status & TIFM_MMCSD_ERRMASK,
- sock->addr + SOCK_MMCSD_STATUS);
- if (host_status & TIFM_MMCSD_CTO)
- cmd_error = -ETIMEDOUT;
- else if (host_status & TIFM_MMCSD_CCRC)
- cmd_error = -EILSEQ;
-
- if (cmd->data) {
- if (host_status & TIFM_MMCSD_DTO)
- cmd->data->error = -ETIMEDOUT;
- else if (host_status & TIFM_MMCSD_DCRC)
- cmd->data->error = -EILSEQ;
- }
-
- writel(TIFM_FIFO_INT_SETALL,
- sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
- writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL);
-
- if (host->req->stop) {
- if (host->cmd_flags & SCMD_ACTIVE) {
- host->req->stop->error = cmd_error;
- host->cmd_flags |= SCMD_READY;
- } else {
- cmd->error = cmd_error;
- host->cmd_flags |= SCMD_ACTIVE;
- tifm_sd_exec(host, host->req->stop);
- goto done;
- }
- } else
- cmd->error = cmd_error;
- } else {
- if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) {
- if (!(host->cmd_flags & CMD_READY)) {
- host->cmd_flags |= CMD_READY;
- tifm_sd_fetch_resp(cmd, sock);
- } else if (host->cmd_flags & SCMD_ACTIVE) {
- host->cmd_flags |= SCMD_READY;
- tifm_sd_fetch_resp(host->req->stop,
- sock);
- }
- }
- if (host_status & TIFM_MMCSD_BRS)
- host->cmd_flags |= BRS_READY;
- }
-
- if (host->no_dma && cmd->data) {
- if (host_status & TIFM_MMCSD_AE)
- writel(host_status & TIFM_MMCSD_AE,
- sock->addr + SOCK_MMCSD_STATUS);
-
- if (host_status & (TIFM_MMCSD_AE | TIFM_MMCSD_AF
- | TIFM_MMCSD_BRS)) {
- local_irq_save(flags);
- tifm_sd_transfer_data(host);
- local_irq_restore(flags);
- host_status &= ~TIFM_MMCSD_AE;
- }
- }
-
- if (host_status & TIFM_MMCSD_EOFB)
- host->cmd_flags &= ~CARD_BUSY;
- else if (host_status & TIFM_MMCSD_CB)
- host->cmd_flags |= CARD_BUSY;
-
- tifm_sd_check_status(host);
- }
-done:
- writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
- spin_unlock(&sock->lock);
-}
-
-static void tifm_sd_set_data_timeout(struct tifm_sd *host,
- struct mmc_data *data)
-{
- struct tifm_dev *sock = host->dev;
- unsigned int data_timeout = data->timeout_clks;
-
- if (fixed_timeout)
- return;
-
- data_timeout += data->timeout_ns /
- ((1000000000UL / host->clk_freq) * host->clk_div);
-
- if (data_timeout < 0xffff) {
- writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
- writel((~TIFM_MMCSD_DPE)
- & readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
- sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
- } else {
- data_timeout = (data_timeout >> 10) + 1;
- if (data_timeout > 0xffff)
- data_timeout = 0; /* set to unlimited */
- writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
- writel(TIFM_MMCSD_DPE
- | readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
- sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
- }
-}
-
-static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct tifm_sd *host = mmc_priv(mmc);
- struct tifm_dev *sock = host->dev;
- unsigned long flags;
- struct mmc_data *r_data = mrq->cmd->data;
-
- spin_lock_irqsave(&sock->lock, flags);
- if (host->eject) {
- mrq->cmd->error = -ENOMEDIUM;
- goto err_out;
- }
-
- if (host->req) {
- pr_err("%s : unfinished request detected\n",
- dev_name(&sock->dev));
- mrq->cmd->error = -ETIMEDOUT;
- goto err_out;
- }
-
- host->cmd_flags = 0;
- host->block_pos = 0;
- host->sg_pos = 0;
-
- if (mrq->data && !is_power_of_2(mrq->data->blksz))
- host->no_dma = 1;
- else
- host->no_dma = no_dma ? 1 : 0;
-
- if (r_data) {
- tifm_sd_set_data_timeout(host, r_data);
-
- if ((r_data->flags & MMC_DATA_WRITE) && !mrq->stop)
- writel(TIFM_MMCSD_EOFB
- | readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
- sock->addr + SOCK_MMCSD_INT_ENABLE);
-
- if (host->no_dma) {
- writel(TIFM_MMCSD_BUFINT
- | readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
- sock->addr + SOCK_MMCSD_INT_ENABLE);
- writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8)
- | (TIFM_MMCSD_FIFO_SIZE - 1),
- sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
-
- host->sg_len = r_data->sg_len;
- } else {
- sg_init_one(&host->bounce_buf, host->bounce_buf_data,
- r_data->blksz);
-
- if(1 != tifm_map_sg(sock, &host->bounce_buf, 1,
- r_data->flags & MMC_DATA_WRITE
- ? PCI_DMA_TODEVICE
- : PCI_DMA_FROMDEVICE)) {
- pr_err("%s : scatterlist map failed\n",
- dev_name(&sock->dev));
- mrq->cmd->error = -ENOMEM;
- goto err_out;
- }
- host->sg_len = tifm_map_sg(sock, r_data->sg,
- r_data->sg_len,
- r_data->flags
- & MMC_DATA_WRITE
- ? PCI_DMA_TODEVICE
- : PCI_DMA_FROMDEVICE);
- if (host->sg_len < 1) {
- pr_err("%s : scatterlist map failed\n",
- dev_name(&sock->dev));
- tifm_unmap_sg(sock, &host->bounce_buf, 1,
- r_data->flags & MMC_DATA_WRITE
- ? PCI_DMA_TODEVICE
- : PCI_DMA_FROMDEVICE);
- mrq->cmd->error = -ENOMEM;
- goto err_out;
- }
-
- writel(TIFM_FIFO_INT_SETALL,
- sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
- writel(ilog2(r_data->blksz) - 2,
- sock->addr + SOCK_FIFO_PAGE_SIZE);
- writel(TIFM_FIFO_ENABLE,
- sock->addr + SOCK_FIFO_CONTROL);
- writel(TIFM_FIFO_INTMASK,
- sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
-
- if (r_data->flags & MMC_DATA_WRITE)
- writel(TIFM_MMCSD_TXDE,
- sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
- else
- writel(TIFM_MMCSD_RXDE,
- sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
-
- tifm_sd_set_dma_data(host, r_data);
- }
-
- writel(r_data->blocks - 1,
- sock->addr + SOCK_MMCSD_NUM_BLOCKS);
- writel(r_data->blksz - 1,
- sock->addr + SOCK_MMCSD_BLOCK_LEN);
- }
-
- host->req = mrq;
- mod_timer(&host->timer, jiffies + host->timeout_jiffies);
- writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
- tifm_sd_exec(host, mrq->cmd);
- spin_unlock_irqrestore(&sock->lock, flags);
- return;
-
-err_out:
- spin_unlock_irqrestore(&sock->lock, flags);
- mmc_request_done(mmc, mrq);
-}
-
-static void tifm_sd_end_cmd(unsigned long data)
-{
- struct tifm_sd *host = (struct tifm_sd*)data;
- struct tifm_dev *sock = host->dev;
- struct mmc_host *mmc = tifm_get_drvdata(sock);
- struct mmc_request *mrq;
- struct mmc_data *r_data = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&sock->lock, flags);
-
- del_timer(&host->timer);
- mrq = host->req;
- host->req = NULL;
-
- if (!mrq) {
- pr_err(" %s : no request to complete?\n",
- dev_name(&sock->dev));
- spin_unlock_irqrestore(&sock->lock, flags);
- return;
- }
-
- r_data = mrq->cmd->data;
- if (r_data) {
- if (host->no_dma) {
- writel((~TIFM_MMCSD_BUFINT)
- & readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
- sock->addr + SOCK_MMCSD_INT_ENABLE);
- } else {
- tifm_unmap_sg(sock, &host->bounce_buf, 1,
- (r_data->flags & MMC_DATA_WRITE)
- ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
- tifm_unmap_sg(sock, r_data->sg, r_data->sg_len,
- (r_data->flags & MMC_DATA_WRITE)
- ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
- }
-
- r_data->bytes_xfered = r_data->blocks
- - readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
- r_data->bytes_xfered *= r_data->blksz;
- r_data->bytes_xfered += r_data->blksz
- - readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
- }
-
- writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
-
- spin_unlock_irqrestore(&sock->lock, flags);
- mmc_request_done(mmc, mrq);
-}
-
-static void tifm_sd_abort(unsigned long data)
-{
- struct tifm_sd *host = (struct tifm_sd*)data;
-
- pr_err("%s : card failed to respond for a long period of time "
- "(%x, %x)\n",
- dev_name(&host->dev->dev), host->req->cmd->opcode, host->cmd_flags);
-
- tifm_eject(host->dev);
-}
-
-static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct tifm_sd *host = mmc_priv(mmc);
- struct tifm_dev *sock = host->dev;
- unsigned int clk_div1, clk_div2;
- unsigned long flags;
-
- spin_lock_irqsave(&sock->lock, flags);
-
- dev_dbg(&sock->dev, "ios: clock = %u, vdd = %x, bus_mode = %x, "
- "chip_select = %x, power_mode = %x, bus_width = %x\n",
- ios->clock, ios->vdd, ios->bus_mode, ios->chip_select,
- ios->power_mode, ios->bus_width);
-
- if (ios->bus_width == MMC_BUS_WIDTH_4) {
- writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG),
- sock->addr + SOCK_MMCSD_CONFIG);
- } else {
- writel((~TIFM_MMCSD_4BBUS)
- & readl(sock->addr + SOCK_MMCSD_CONFIG),
- sock->addr + SOCK_MMCSD_CONFIG);
- }
-
- if (ios->clock) {
- clk_div1 = 20000000 / ios->clock;
- if (!clk_div1)
- clk_div1 = 1;
-
- clk_div2 = 24000000 / ios->clock;
- if (!clk_div2)
- clk_div2 = 1;
-
- if ((20000000 / clk_div1) > ios->clock)
- clk_div1++;
- if ((24000000 / clk_div2) > ios->clock)
- clk_div2++;
- if ((20000000 / clk_div1) > (24000000 / clk_div2)) {
- host->clk_freq = 20000000;
- host->clk_div = clk_div1;
- writel((~TIFM_CTRL_FAST_CLK)
- & readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
- } else {
- host->clk_freq = 24000000;
- host->clk_div = clk_div2;
- writel(TIFM_CTRL_FAST_CLK
- | readl(sock->addr + SOCK_CONTROL),
- sock->addr + SOCK_CONTROL);
- }
- } else {
- host->clk_div = 0;
- }
- host->clk_div &= TIFM_MMCSD_CLKMASK;
- writel(host->clk_div
- | ((~TIFM_MMCSD_CLKMASK)
- & readl(sock->addr + SOCK_MMCSD_CONFIG)),
- sock->addr + SOCK_MMCSD_CONFIG);
-
- host->open_drain = (ios->bus_mode == MMC_BUSMODE_OPENDRAIN);
-
- /* chip_select : maybe later */
- //vdd
- //power is set before probe / after remove
-
- spin_unlock_irqrestore(&sock->lock, flags);
-}
-
-static int tifm_sd_ro(struct mmc_host *mmc)
-{
- int rc = 0;
- struct tifm_sd *host = mmc_priv(mmc);
- struct tifm_dev *sock = host->dev;
- unsigned long flags;
-
- spin_lock_irqsave(&sock->lock, flags);
- if (TIFM_MMCSD_CARD_RO & readl(sock->addr + SOCK_PRESENT_STATE))
- rc = 1;
- spin_unlock_irqrestore(&sock->lock, flags);
- return rc;
-}
-
-static const struct mmc_host_ops tifm_sd_ops = {
- .request = tifm_sd_request,
- .set_ios = tifm_sd_ios,
- .get_ro = tifm_sd_ro
-};
-
-static int tifm_sd_initialize_host(struct tifm_sd *host)
-{
- int rc;
- unsigned int host_status = 0;
- struct tifm_dev *sock = host->dev;
-
- writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
- mmiowb();
- host->clk_div = 61;
- host->clk_freq = 20000000;
- writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
- writel(host->clk_div | TIFM_MMCSD_POWER,
- sock->addr + SOCK_MMCSD_CONFIG);
-
- /* wait up to 0.51 sec for reset */
- for (rc = 32; rc <= 256; rc <<= 1) {
- if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
- rc = 0;
- break;
- }
- msleep(rc);
- }
-
- if (rc) {
- pr_err("%s : controller failed to reset\n",
- dev_name(&sock->dev));
- return -ENODEV;
- }
-
- writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
- writel(host->clk_div | TIFM_MMCSD_POWER,
- sock->addr + SOCK_MMCSD_CONFIG);
- writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
-
- // command timeout fixed to 64 clocks for now
- writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO);
- writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
-
- for (rc = 16; rc <= 64; rc <<= 1) {
- host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
- writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
- if (!(host_status & TIFM_MMCSD_ERRMASK)
- && (host_status & TIFM_MMCSD_EOC)) {
- rc = 0;
- break;
- }
- msleep(rc);
- }
-
- if (rc) {
- pr_err("%s : card not ready - probe failed on initialization\n",
- dev_name(&sock->dev));
- return -ENODEV;
- }
-
- writel(TIFM_MMCSD_CERR | TIFM_MMCSD_BRS | TIFM_MMCSD_EOC
- | TIFM_MMCSD_ERRMASK,
- sock->addr + SOCK_MMCSD_INT_ENABLE);
- mmiowb();
-
- return 0;
-}
-
-static int tifm_sd_probe(struct tifm_dev *sock)
-{
- struct mmc_host *mmc;
- struct tifm_sd *host;
- int rc = -EIO;
-
- if (!(TIFM_SOCK_STATE_OCCUPIED
- & readl(sock->addr + SOCK_PRESENT_STATE))) {
- pr_warning("%s : card gone, unexpectedly\n",
- dev_name(&sock->dev));
- return rc;
- }
-
- mmc = mmc_alloc_host(sizeof(struct tifm_sd), &sock->dev);
- if (!mmc)
- return -ENOMEM;
-
- host = mmc_priv(mmc);
- tifm_set_drvdata(sock, mmc);
- host->dev = sock;
- host->timeout_jiffies = msecs_to_jiffies(1000);
-
- tasklet_init(&host->finish_tasklet, tifm_sd_end_cmd,
- (unsigned long)host);
- setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host);
-
- mmc->ops = &tifm_sd_ops;
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps = MMC_CAP_4_BIT_DATA;
- mmc->f_min = 20000000 / 60;
- mmc->f_max = 24000000;
-
- mmc->max_blk_count = 2048;
- 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;
-
- sock->card_event = tifm_sd_card_event;
- sock->data_event = tifm_sd_data_event;
- rc = tifm_sd_initialize_host(host);
-
- if (!rc)
- rc = mmc_add_host(mmc);
- if (!rc)
- return 0;
-
- mmc_free_host(mmc);
- return rc;
-}
-
-static void tifm_sd_remove(struct tifm_dev *sock)
-{
- struct mmc_host *mmc = tifm_get_drvdata(sock);
- struct tifm_sd *host = mmc_priv(mmc);
- unsigned long flags;
-
- spin_lock_irqsave(&sock->lock, flags);
- host->eject = 1;
- writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
- mmiowb();
- spin_unlock_irqrestore(&sock->lock, flags);
-
- tasklet_kill(&host->finish_tasklet);
-
- spin_lock_irqsave(&sock->lock, flags);
- if (host->req) {
- writel(TIFM_FIFO_INT_SETALL,
- sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
- writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
- host->req->cmd->error = -ENOMEDIUM;
- if (host->req->stop)
- host->req->stop->error = -ENOMEDIUM;
- tasklet_schedule(&host->finish_tasklet);
- }
- spin_unlock_irqrestore(&sock->lock, flags);
- mmc_remove_host(mmc);
- dev_dbg(&sock->dev, "after remove\n");
-
- mmc_free_host(mmc);
-}
-
-#ifdef CONFIG_PM
-
-static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
-{
- return mmc_suspend_host(tifm_get_drvdata(sock));
-}
-
-static int tifm_sd_resume(struct tifm_dev *sock)
-{
- struct mmc_host *mmc = tifm_get_drvdata(sock);
- struct tifm_sd *host = mmc_priv(mmc);
- int rc;
-
- rc = tifm_sd_initialize_host(host);
- dev_dbg(&sock->dev, "resume initialize %d\n", rc);
-
- if (rc)
- host->eject = 1;
- else
- rc = mmc_resume_host(mmc);
-
- return rc;
-}
-
-#else
-
-#define tifm_sd_suspend NULL
-#define tifm_sd_resume NULL
-
-#endif /* CONFIG_PM */
-
-static struct tifm_device_id tifm_sd_id_tbl[] = {
- { TIFM_TYPE_SD }, { }
-};
-
-static struct tifm_driver tifm_sd_driver = {
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE
- },
- .id_table = tifm_sd_id_tbl,
- .probe = tifm_sd_probe,
- .remove = tifm_sd_remove,
- .suspend = tifm_sd_suspend,
- .resume = tifm_sd_resume
-};
-
-static int __init tifm_sd_init(void)
-{
- return tifm_register_driver(&tifm_sd_driver);
-}
-
-static void __exit tifm_sd_exit(void)
-{
- tifm_unregister_driver(&tifm_sd_driver);
-}
-
-MODULE_AUTHOR("Alex Dubov");
-MODULE_DESCRIPTION("TI FlashMedia SD driver");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(tifm, tifm_sd_id_tbl);
-MODULE_VERSION(DRIVER_VERSION);
-
-module_init(tifm_sd_init);
-module_exit(tifm_sd_exit);
diff --git a/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc.c b/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc.c
deleted file mode 100644
index 113ce6c9..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * linux/drivers/mmc/host/tmio_mmc.c
- *
- * Copyright (C) 2007 Ian Molton
- * Copyright (C) 2004 Ian Molton
- *
- * 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.
- *
- * Driver for the MMC / SD / SDIO cell found in:
- *
- * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3
- */
-
-#include <linux/device.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/tmio.h>
-#include <linux/mmc/host.h>
-#include <linux/module.h>
-#include <linux/pagemap.h>
-#include <linux/scatterlist.h>
-
-#include "tmio_mmc.h"
-
-#ifdef CONFIG_PM
-static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
-{
- const struct mfd_cell *cell = mfd_get_cell(dev);
- int ret;
-
- ret = tmio_mmc_host_suspend(&dev->dev);
-
- /* Tell MFD core it can disable us now.*/
- if (!ret && cell->disable)
- cell->disable(dev);
-
- return ret;
-}
-
-static int tmio_mmc_resume(struct platform_device *dev)
-{
- const struct mfd_cell *cell = mfd_get_cell(dev);
- int ret = 0;
-
- /* Tell the MFD core we are ready to be enabled */
- if (cell->resume)
- ret = cell->resume(dev);
-
- if (!ret)
- ret = tmio_mmc_host_resume(&dev->dev);
-
- return ret;
-}
-#else
-#define tmio_mmc_suspend NULL
-#define tmio_mmc_resume NULL
-#endif
-
-static int __devinit tmio_mmc_probe(struct platform_device *pdev)
-{
- const struct mfd_cell *cell = mfd_get_cell(pdev);
- struct tmio_mmc_data *pdata;
- struct tmio_mmc_host *host;
- int ret = -EINVAL, irq;
-
- if (pdev->num_resources != 2)
- goto out;
-
- pdata = pdev->dev.platform_data;
- if (!pdata || !pdata->hclk)
- goto out;
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- ret = irq;
- goto out;
- }
-
- /* Tell the MFD core we are ready to be enabled */
- if (cell->enable) {
- ret = cell->enable(pdev);
- if (ret)
- goto out;
- }
-
- ret = tmio_mmc_host_probe(&host, pdev, pdata);
- if (ret)
- goto cell_disable;
-
- ret = request_irq(irq, tmio_mmc_irq, IRQF_TRIGGER_FALLING,
- dev_name(&pdev->dev), host);
- if (ret)
- goto host_remove;
-
- pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
- (unsigned long)host->ctl, irq);
-
- return 0;
-
-host_remove:
- tmio_mmc_host_remove(host);
-cell_disable:
- if (cell->disable)
- cell->disable(pdev);
-out:
- return ret;
-}
-
-static int __devexit tmio_mmc_remove(struct platform_device *pdev)
-{
- const struct mfd_cell *cell = mfd_get_cell(pdev);
- struct mmc_host *mmc = platform_get_drvdata(pdev);
-
- platform_set_drvdata(pdev, NULL);
-
- if (mmc) {
- struct tmio_mmc_host *host = mmc_priv(mmc);
- free_irq(platform_get_irq(pdev, 0), host);
- tmio_mmc_host_remove(host);
- if (cell->disable)
- cell->disable(pdev);
- }
-
- return 0;
-}
-
-/* ------------------- device registration ----------------------- */
-
-static struct platform_driver tmio_mmc_driver = {
- .driver = {
- .name = "tmio-mmc",
- .owner = THIS_MODULE,
- },
- .probe = tmio_mmc_probe,
- .remove = __devexit_p(tmio_mmc_remove),
- .suspend = tmio_mmc_suspend,
- .resume = tmio_mmc_resume,
-};
-
-module_platform_driver(tmio_mmc_driver);
-
-MODULE_DESCRIPTION("Toshiba TMIO SD/MMC driver");
-MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:tmio-mmc");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc.h b/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc.h
deleted file mode 100644
index d857f5c6..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc.h
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * linux/drivers/mmc/host/tmio_mmc.h
- *
- * Copyright (C) 2007 Ian Molton
- * Copyright (C) 2004 Ian Molton
- *
- * 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.
- *
- * Driver for the MMC / SD / SDIO cell found in:
- *
- * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3
- */
-
-#ifndef TMIO_MMC_H
-#define TMIO_MMC_H
-
-#include <linux/highmem.h>
-#include <linux/mmc/tmio.h>
-#include <linux/mutex.h>
-#include <linux/pagemap.h>
-#include <linux/scatterlist.h>
-#include <linux/spinlock.h>
-
-/* Definitions for values the CTRL_SDIO_STATUS register can take. */
-#define TMIO_SDIO_STAT_IOIRQ 0x0001
-#define TMIO_SDIO_STAT_EXPUB52 0x4000
-#define TMIO_SDIO_STAT_EXWT 0x8000
-#define TMIO_SDIO_MASK_ALL 0xc007
-
-/* Define some IRQ masks */
-/* This is the mask used at reset by the chip */
-#define TMIO_MASK_ALL 0x837f031d
-#define TMIO_MASK_READOP (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND)
-#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND)
-#define TMIO_MASK_CMD (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \
- TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT)
-#define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD)
-
-struct tmio_mmc_data;
-
-struct tmio_mmc_host {
- void __iomem *ctl;
- unsigned long bus_shift;
- struct mmc_command *cmd;
- struct mmc_request *mrq;
- struct mmc_data *data;
- struct mmc_host *mmc;
-
- /* Controller power state */
- bool power;
-
- /* Callbacks for clock / power control */
- void (*set_pwr)(struct platform_device *host, int state);
- void (*set_clk_div)(struct platform_device *host, int state);
-
- /* pio related stuff */
- struct scatterlist *sg_ptr;
- struct scatterlist *sg_orig;
- unsigned int sg_len;
- unsigned int sg_off;
-
- struct platform_device *pdev;
- struct tmio_mmc_data *pdata;
-
- /* DMA support */
- bool force_pio;
- struct dma_chan *chan_rx;
- struct dma_chan *chan_tx;
- struct tasklet_struct dma_complete;
- struct tasklet_struct dma_issue;
- struct scatterlist bounce_sg;
- u8 *bounce_buf;
-
- /* Track lost interrupts */
- struct delayed_work delayed_reset_work;
- struct work_struct done;
-
- /* Cache IRQ mask */
- u32 sdcard_irq_mask;
- u32 sdio_irq_mask;
-
- spinlock_t lock; /* protect host private data */
- unsigned long last_req_ts;
- struct mutex ios_lock; /* protect set_ios() context */
- bool native_hotplug;
-};
-
-int tmio_mmc_host_probe(struct tmio_mmc_host **host,
- struct platform_device *pdev,
- struct tmio_mmc_data *pdata);
-void tmio_mmc_host_remove(struct tmio_mmc_host *host);
-void tmio_mmc_do_data_irq(struct tmio_mmc_host *host);
-
-void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
-void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
-irqreturn_t tmio_mmc_irq(int irq, void *devid);
-irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid);
-irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid);
-irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid);
-
-static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg,
- unsigned long *flags)
-{
- local_irq_save(*flags);
- return kmap_atomic(sg_page(sg)) + sg->offset;
-}
-
-static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg,
- unsigned long *flags, void *virt)
-{
- kunmap_atomic(virt - sg->offset);
- local_irq_restore(*flags);
-}
-
-#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
-void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data);
-void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable);
-void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata);
-void tmio_mmc_release_dma(struct tmio_mmc_host *host);
-void tmio_mmc_abort_dma(struct tmio_mmc_host *host);
-#else
-static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host,
- struct mmc_data *data)
-{
-}
-
-static inline void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
-{
-}
-
-static inline void tmio_mmc_request_dma(struct tmio_mmc_host *host,
- struct tmio_mmc_data *pdata)
-{
- host->chan_tx = NULL;
- host->chan_rx = NULL;
-}
-
-static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host)
-{
-}
-
-static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
-{
-}
-#endif
-
-#ifdef CONFIG_PM
-int tmio_mmc_host_suspend(struct device *dev);
-int tmio_mmc_host_resume(struct device *dev);
-#else
-#define tmio_mmc_host_suspend NULL
-#define tmio_mmc_host_resume NULL
-#endif
-
-int tmio_mmc_host_runtime_suspend(struct device *dev);
-int tmio_mmc_host_runtime_resume(struct device *dev);
-
-static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr)
-{
- return readw(host->ctl + (addr << host->bus_shift));
-}
-
-static inline void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr,
- u16 *buf, int count)
-{
- readsw(host->ctl + (addr << host->bus_shift), buf, count);
-}
-
-static inline u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr)
-{
- return readw(host->ctl + (addr << host->bus_shift)) |
- readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16;
-}
-
-static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val)
-{
- /* If there is a hook and it returns non-zero then there
- * is an error and the write should be skipped
- */
- if (host->pdata->write16_hook && host->pdata->write16_hook(host, addr))
- return;
- writew(val, host->ctl + (addr << host->bus_shift));
-}
-
-static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr,
- u16 *buf, int count)
-{
- writesw(host->ctl + (addr << host->bus_shift), buf, count);
-}
-
-static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val)
-{
- writew(val, host->ctl + (addr << host->bus_shift));
- writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift));
-}
-
-
-#endif
diff --git a/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc_dma.c b/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc_dma.c
deleted file mode 100644
index fff92860..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc_dma.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * linux/drivers/mmc/tmio_mmc_dma.c
- *
- * Copyright (C) 2010-2011 Guennadi Liakhovetski
- *
- * 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.
- *
- * DMA function for TMIO MMC implementations
- */
-
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/dmaengine.h>
-#include <linux/mfd/tmio.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/tmio.h>
-#include <linux/pagemap.h>
-#include <linux/scatterlist.h>
-
-#include "tmio_mmc.h"
-
-#define TMIO_MMC_MIN_DMA_LEN 8
-
-void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
-{
- if (!host->chan_tx || !host->chan_rx)
- return;
-
-#if defined(CONFIG_SUPERH) || defined(CONFIG_ARCH_SHMOBILE)
- /* Switch DMA mode on or off - SuperH specific? */
- sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0);
-#endif
-}
-
-void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
-{
- tmio_mmc_enable_dma(host, false);
-
- if (host->chan_rx)
- dmaengine_terminate_all(host->chan_rx);
- if (host->chan_tx)
- dmaengine_terminate_all(host->chan_tx);
-
- tmio_mmc_enable_dma(host, true);
-}
-
-static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
-{
- struct scatterlist *sg = host->sg_ptr, *sg_tmp;
- struct dma_async_tx_descriptor *desc = NULL;
- struct dma_chan *chan = host->chan_rx;
- struct tmio_mmc_data *pdata = host->pdata;
- dma_cookie_t cookie;
- int ret, i;
- bool aligned = true, multiple = true;
- unsigned int align = (1 << pdata->dma->alignment_shift) - 1;
-
- for_each_sg(sg, sg_tmp, host->sg_len, i) {
- if (sg_tmp->offset & align)
- aligned = false;
- if (sg_tmp->length & align) {
- multiple = false;
- break;
- }
- }
-
- if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE ||
- (align & PAGE_MASK))) || !multiple) {
- ret = -EINVAL;
- goto pio;
- }
-
- if (sg->length < TMIO_MMC_MIN_DMA_LEN) {
- host->force_pio = true;
- return;
- }
-
- tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_RXRDY);
-
- /* The only sg element can be unaligned, use our bounce buffer then */
- if (!aligned) {
- sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
- host->sg_ptr = &host->bounce_sg;
- sg = host->sg_ptr;
- }
-
- ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE);
- if (ret > 0)
- desc = dmaengine_prep_slave_sg(chan, sg, ret,
- DMA_DEV_TO_MEM, DMA_CTRL_ACK);
-
- if (desc) {
- cookie = dmaengine_submit(desc);
- if (cookie < 0) {
- desc = NULL;
- ret = cookie;
- }
- }
- dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n",
- __func__, host->sg_len, ret, cookie, host->mrq);
-
-pio:
- if (!desc) {
- /* DMA failed, fall back to PIO */
- if (ret >= 0)
- ret = -EIO;
- host->chan_rx = NULL;
- dma_release_channel(chan);
- /* Free the Tx channel too */
- chan = host->chan_tx;
- if (chan) {
- host->chan_tx = NULL;
- dma_release_channel(chan);
- }
- dev_warn(&host->pdev->dev,
- "DMA failed: %d, falling back to PIO\n", ret);
- tmio_mmc_enable_dma(host, false);
- }
-
- dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__,
- desc, cookie, host->sg_len);
-}
-
-static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
-{
- struct scatterlist *sg = host->sg_ptr, *sg_tmp;
- struct dma_async_tx_descriptor *desc = NULL;
- struct dma_chan *chan = host->chan_tx;
- struct tmio_mmc_data *pdata = host->pdata;
- dma_cookie_t cookie;
- int ret, i;
- bool aligned = true, multiple = true;
- unsigned int align = (1 << pdata->dma->alignment_shift) - 1;
-
- for_each_sg(sg, sg_tmp, host->sg_len, i) {
- if (sg_tmp->offset & align)
- aligned = false;
- if (sg_tmp->length & align) {
- multiple = false;
- break;
- }
- }
-
- if ((!aligned && (host->sg_len > 1 || sg->length > PAGE_CACHE_SIZE ||
- (align & PAGE_MASK))) || !multiple) {
- ret = -EINVAL;
- goto pio;
- }
-
- if (sg->length < TMIO_MMC_MIN_DMA_LEN) {
- host->force_pio = true;
- return;
- }
-
- tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_TXRQ);
-
- /* The only sg element can be unaligned, use our bounce buffer then */
- if (!aligned) {
- unsigned long flags;
- void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags);
- sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
- memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length);
- tmio_mmc_kunmap_atomic(sg, &flags, sg_vaddr);
- host->sg_ptr = &host->bounce_sg;
- sg = host->sg_ptr;
- }
-
- ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE);
- if (ret > 0)
- desc = dmaengine_prep_slave_sg(chan, sg, ret,
- DMA_MEM_TO_DEV, DMA_CTRL_ACK);
-
- if (desc) {
- cookie = dmaengine_submit(desc);
- if (cookie < 0) {
- desc = NULL;
- ret = cookie;
- }
- }
- dev_dbg(&host->pdev->dev, "%s(): mapped %d -> %d, cookie %d, rq %p\n",
- __func__, host->sg_len, ret, cookie, host->mrq);
-
-pio:
- if (!desc) {
- /* DMA failed, fall back to PIO */
- if (ret >= 0)
- ret = -EIO;
- host->chan_tx = NULL;
- dma_release_channel(chan);
- /* Free the Rx channel too */
- chan = host->chan_rx;
- if (chan) {
- host->chan_rx = NULL;
- dma_release_channel(chan);
- }
- dev_warn(&host->pdev->dev,
- "DMA failed: %d, falling back to PIO\n", ret);
- tmio_mmc_enable_dma(host, false);
- }
-
- dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d\n", __func__,
- desc, cookie);
-}
-
-void tmio_mmc_start_dma(struct tmio_mmc_host *host,
- struct mmc_data *data)
-{
- if (data->flags & MMC_DATA_READ) {
- if (host->chan_rx)
- tmio_mmc_start_dma_rx(host);
- } else {
- if (host->chan_tx)
- tmio_mmc_start_dma_tx(host);
- }
-}
-
-static void tmio_mmc_issue_tasklet_fn(unsigned long priv)
-{
- struct tmio_mmc_host *host = (struct tmio_mmc_host *)priv;
- struct dma_chan *chan = NULL;
-
- spin_lock_irq(&host->lock);
-
- if (host && host->data) {
- if (host->data->flags & MMC_DATA_READ)
- chan = host->chan_rx;
- else
- chan = host->chan_tx;
- }
-
- spin_unlock_irq(&host->lock);
-
- tmio_mmc_enable_mmc_irqs(host, TMIO_STAT_DATAEND);
-
- if (chan)
- dma_async_issue_pending(chan);
-}
-
-static void tmio_mmc_tasklet_fn(unsigned long arg)
-{
- struct tmio_mmc_host *host = (struct tmio_mmc_host *)arg;
-
- spin_lock_irq(&host->lock);
-
- if (!host->data)
- goto out;
-
- if (host->data->flags & MMC_DATA_READ)
- dma_unmap_sg(host->chan_rx->device->dev,
- host->sg_ptr, host->sg_len,
- DMA_FROM_DEVICE);
- else
- dma_unmap_sg(host->chan_tx->device->dev,
- host->sg_ptr, host->sg_len,
- DMA_TO_DEVICE);
-
- tmio_mmc_do_data_irq(host);
-out:
- spin_unlock_irq(&host->lock);
-}
-
-/* It might be necessary to make filter MFD specific */
-static bool tmio_mmc_filter(struct dma_chan *chan, void *arg)
-{
- dev_dbg(chan->device->dev, "%s: slave data %p\n", __func__, arg);
- chan->private = arg;
- return true;
-}
-
-void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata)
-{
- /* We can only either use DMA for both Tx and Rx or not use it at all */
- if (!pdata->dma)
- return;
-
- if (!host->chan_tx && !host->chan_rx) {
- dma_cap_mask_t mask;
-
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
-
- host->chan_tx = dma_request_channel(mask, tmio_mmc_filter,
- pdata->dma->chan_priv_tx);
- dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__,
- host->chan_tx);
-
- if (!host->chan_tx)
- return;
-
- host->chan_rx = dma_request_channel(mask, tmio_mmc_filter,
- pdata->dma->chan_priv_rx);
- dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__,
- host->chan_rx);
-
- if (!host->chan_rx)
- goto ereqrx;
-
- host->bounce_buf = (u8 *)__get_free_page(GFP_KERNEL | GFP_DMA);
- if (!host->bounce_buf)
- goto ebouncebuf;
-
- tasklet_init(&host->dma_complete, tmio_mmc_tasklet_fn, (unsigned long)host);
- tasklet_init(&host->dma_issue, tmio_mmc_issue_tasklet_fn, (unsigned long)host);
- }
-
- tmio_mmc_enable_dma(host, true);
-
- return;
-
-ebouncebuf:
- dma_release_channel(host->chan_rx);
- host->chan_rx = NULL;
-ereqrx:
- dma_release_channel(host->chan_tx);
- host->chan_tx = NULL;
-}
-
-void tmio_mmc_release_dma(struct tmio_mmc_host *host)
-{
- if (host->chan_tx) {
- struct dma_chan *chan = host->chan_tx;
- host->chan_tx = NULL;
- dma_release_channel(chan);
- }
- if (host->chan_rx) {
- struct dma_chan *chan = host->chan_rx;
- host->chan_rx = NULL;
- dma_release_channel(chan);
- }
- if (host->bounce_buf) {
- free_pages((unsigned long)host->bounce_buf, 0);
- host->bounce_buf = NULL;
- }
-}
diff --git a/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc_pio.c b/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc_pio.c
deleted file mode 100644
index 9a7996ad..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/tmio_mmc_pio.c
+++ /dev/null
@@ -1,1078 +0,0 @@
-/*
- * linux/drivers/mmc/host/tmio_mmc_pio.c
- *
- * Copyright (C) 2011 Guennadi Liakhovetski
- * Copyright (C) 2007 Ian Molton
- * Copyright (C) 2004 Ian Molton
- *
- * 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.
- *
- * Driver for the MMC / SD / SDIO IP found in:
- *
- * TC6393XB, TC6391XB, TC6387XB, T7L66XB, ASIC3, SH-Mobile SoCs
- *
- * This driver draws mainly on scattered spec sheets, Reverse engineering
- * of the toshiba e800 SD driver and some parts of the 2.4 ASIC3 driver (4 bit
- * support). (Further 4 bit support from a later datasheet).
- *
- * TODO:
- * Investigate using a workqueue for PIO transfers
- * Eliminate FIXMEs
- * SDIO support
- * Better Power management
- * Handle MMC errors better
- * double buffer support
- *
- */
-
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/highmem.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/mfd/tmio.h>
-#include <linux/mmc/cd-gpio.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/tmio.h>
-#include <linux/module.h>
-#include <linux/pagemap.h>
-#include <linux/platform_device.h>
-#include <linux/pm_qos.h>
-#include <linux/pm_runtime.h>
-#include <linux/scatterlist.h>
-#include <linux/spinlock.h>
-#include <linux/workqueue.h>
-
-#include "tmio_mmc.h"
-
-void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i)
-{
- host->sdcard_irq_mask &= ~(i & TMIO_MASK_IRQ);
- sd_ctrl_write32(host, CTL_IRQ_MASK, host->sdcard_irq_mask);
-}
-
-void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i)
-{
- host->sdcard_irq_mask |= (i & TMIO_MASK_IRQ);
- sd_ctrl_write32(host, CTL_IRQ_MASK, host->sdcard_irq_mask);
-}
-
-static void tmio_mmc_ack_mmc_irqs(struct tmio_mmc_host *host, u32 i)
-{
- sd_ctrl_write32(host, CTL_STATUS, ~i);
-}
-
-static void tmio_mmc_init_sg(struct tmio_mmc_host *host, struct mmc_data *data)
-{
- host->sg_len = data->sg_len;
- host->sg_ptr = data->sg;
- host->sg_orig = data->sg;
- host->sg_off = 0;
-}
-
-static int tmio_mmc_next_sg(struct tmio_mmc_host *host)
-{
- host->sg_ptr = sg_next(host->sg_ptr);
- host->sg_off = 0;
- return --host->sg_len;
-}
-
-#ifdef CONFIG_MMC_DEBUG
-
-#define STATUS_TO_TEXT(a, status, i) \
- do { \
- if (status & TMIO_STAT_##a) { \
- if (i++) \
- printk(" | "); \
- printk(#a); \
- } \
- } while (0)
-
-static void pr_debug_status(u32 status)
-{
- int i = 0;
- pr_debug("status: %08x = ", status);
- STATUS_TO_TEXT(CARD_REMOVE, status, i);
- STATUS_TO_TEXT(CARD_INSERT, status, i);
- STATUS_TO_TEXT(SIGSTATE, status, i);
- STATUS_TO_TEXT(WRPROTECT, status, i);
- STATUS_TO_TEXT(CARD_REMOVE_A, status, i);
- STATUS_TO_TEXT(CARD_INSERT_A, status, i);
- STATUS_TO_TEXT(SIGSTATE_A, status, i);
- STATUS_TO_TEXT(CMD_IDX_ERR, status, i);
- STATUS_TO_TEXT(STOPBIT_ERR, status, i);
- STATUS_TO_TEXT(ILL_FUNC, status, i);
- STATUS_TO_TEXT(CMD_BUSY, status, i);
- STATUS_TO_TEXT(CMDRESPEND, status, i);
- STATUS_TO_TEXT(DATAEND, status, i);
- STATUS_TO_TEXT(CRCFAIL, status, i);
- STATUS_TO_TEXT(DATATIMEOUT, status, i);
- STATUS_TO_TEXT(CMDTIMEOUT, status, i);
- STATUS_TO_TEXT(RXOVERFLOW, status, i);
- STATUS_TO_TEXT(TXUNDERRUN, status, i);
- STATUS_TO_TEXT(RXRDY, status, i);
- STATUS_TO_TEXT(TXRQ, status, i);
- STATUS_TO_TEXT(ILL_ACCESS, status, i);
- printk("\n");
-}
-
-#else
-#define pr_debug_status(s) do { } while (0)
-#endif
-
-static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
- struct tmio_mmc_host *host = mmc_priv(mmc);
-
- if (enable) {
- host->sdio_irq_mask = TMIO_SDIO_MASK_ALL &
- ~TMIO_SDIO_STAT_IOIRQ;
- sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
- sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
- } else {
- host->sdio_irq_mask = TMIO_SDIO_MASK_ALL;
- sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
- sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000);
- }
-}
-
-static void tmio_mmc_set_clock(struct tmio_mmc_host *host, int new_clock)
-{
- u32 clk = 0, clock;
-
- if (new_clock) {
- for (clock = host->mmc->f_min, clk = 0x80000080;
- new_clock >= (clock<<1); clk >>= 1)
- clock <<= 1;
- clk |= 0x100;
- }
-
- if (host->set_clk_div)
- host->set_clk_div(host->pdev, (clk>>22) & 1);
-
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & 0x1ff);
-}
-
-static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
-{
- struct resource *res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0);
-
- /* implicit BUG_ON(!res) */
- if (resource_size(res) > 0x100) {
- sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000);
- msleep(10);
- }
-
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~0x0100 &
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
- msleep(10);
-}
-
-static void tmio_mmc_clk_start(struct tmio_mmc_host *host)
-{
- struct resource *res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0);
-
- sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, 0x0100 |
- sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
- msleep(10);
-
- /* implicit BUG_ON(!res) */
- if (resource_size(res) > 0x100) {
- sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100);
- msleep(10);
- }
-}
-
-static void tmio_mmc_reset(struct tmio_mmc_host *host)
-{
- struct resource *res = platform_get_resource(host->pdev, IORESOURCE_MEM, 0);
-
- /* FIXME - should we set stop clock reg here */
- sd_ctrl_write16(host, CTL_RESET_SD, 0x0000);
- /* implicit BUG_ON(!res) */
- if (resource_size(res) > 0x100)
- sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0000);
- msleep(10);
- sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
- if (resource_size(res) > 0x100)
- sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001);
- msleep(10);
-}
-
-static void tmio_mmc_reset_work(struct work_struct *work)
-{
- struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host,
- delayed_reset_work.work);
- struct mmc_request *mrq;
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
- mrq = host->mrq;
-
- /*
- * is request already finished? Since we use a non-blocking
- * cancel_delayed_work(), it can happen, that a .set_ios() call preempts
- * us, so, have to check for IS_ERR(host->mrq)
- */
- if (IS_ERR_OR_NULL(mrq)
- || time_is_after_jiffies(host->last_req_ts +
- msecs_to_jiffies(2000))) {
- spin_unlock_irqrestore(&host->lock, flags);
- return;
- }
-
- dev_warn(&host->pdev->dev,
- "timeout waiting for hardware interrupt (CMD%u)\n",
- mrq->cmd->opcode);
-
- if (host->data)
- host->data->error = -ETIMEDOUT;
- else if (host->cmd)
- host->cmd->error = -ETIMEDOUT;
- else
- mrq->cmd->error = -ETIMEDOUT;
-
- host->cmd = NULL;
- host->data = NULL;
- host->force_pio = false;
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- tmio_mmc_reset(host);
-
- /* Ready for new calls */
- host->mrq = NULL;
-
- tmio_mmc_abort_dma(host);
- mmc_request_done(host->mmc, mrq);
-}
-
-/* called with host->lock held, interrupts disabled */
-static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
-{
- struct mmc_request *mrq;
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
-
- mrq = host->mrq;
- if (IS_ERR_OR_NULL(mrq)) {
- spin_unlock_irqrestore(&host->lock, flags);
- return;
- }
-
- host->cmd = NULL;
- host->data = NULL;
- host->force_pio = false;
-
- cancel_delayed_work(&host->delayed_reset_work);
-
- host->mrq = NULL;
- spin_unlock_irqrestore(&host->lock, flags);
-
- if (mrq->cmd->error || (mrq->data && mrq->data->error))
- tmio_mmc_abort_dma(host);
-
- mmc_request_done(host->mmc, mrq);
-}
-
-static void tmio_mmc_done_work(struct work_struct *work)
-{
- struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host,
- done);
- tmio_mmc_finish_request(host);
-}
-
-/* These are the bitmasks the tmio chip requires to implement the MMC response
- * types. Note that R1 and R6 are the same in this scheme. */
-#define APP_CMD 0x0040
-#define RESP_NONE 0x0300
-#define RESP_R1 0x0400
-#define RESP_R1B 0x0500
-#define RESP_R2 0x0600
-#define RESP_R3 0x0700
-#define DATA_PRESENT 0x0800
-#define TRANSFER_READ 0x1000
-#define TRANSFER_MULTI 0x2000
-#define SECURITY_CMD 0x4000
-
-static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd)
-{
- struct mmc_data *data = host->data;
- int c = cmd->opcode;
- u32 irq_mask = TMIO_MASK_CMD;
-
- /* Command 12 is handled by hardware */
- if (cmd->opcode == 12 && !cmd->arg) {
- sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x001);
- return 0;
- }
-
- switch (mmc_resp_type(cmd)) {
- case MMC_RSP_NONE: c |= RESP_NONE; break;
- case MMC_RSP_R1: c |= RESP_R1; break;
- case MMC_RSP_R1B: c |= RESP_R1B; break;
- case MMC_RSP_R2: c |= RESP_R2; break;
- case MMC_RSP_R3: c |= RESP_R3; break;
- default:
- pr_debug("Unknown response type %d\n", mmc_resp_type(cmd));
- return -EINVAL;
- }
-
- host->cmd = cmd;
-
-/* FIXME - this seems to be ok commented out but the spec suggest this bit
- * should be set when issuing app commands.
- * if(cmd->flags & MMC_FLAG_ACMD)
- * c |= APP_CMD;
- */
- if (data) {
- c |= DATA_PRESENT;
- if (data->blocks > 1) {
- sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x100);
- c |= TRANSFER_MULTI;
- }
- if (data->flags & MMC_DATA_READ)
- c |= TRANSFER_READ;
- }
-
- if (!host->native_hotplug)
- irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
- tmio_mmc_enable_mmc_irqs(host, irq_mask);
-
- /* Fire off the command */
- sd_ctrl_write32(host, CTL_ARG_REG, cmd->arg);
- sd_ctrl_write16(host, CTL_SD_CMD, c);
-
- return 0;
-}
-
-/*
- * This chip always returns (at least?) as much data as you ask for.
- * I'm unsure what happens if you ask for less than a block. This should be
- * looked into to ensure that a funny length read doesn't hose the controller.
- */
-static void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
-{
- struct mmc_data *data = host->data;
- void *sg_virt;
- unsigned short *buf;
- unsigned int count;
- unsigned long flags;
-
- if ((host->chan_tx || host->chan_rx) && !host->force_pio) {
- pr_err("PIO IRQ in DMA mode!\n");
- return;
- } else if (!data) {
- pr_debug("Spurious PIO IRQ\n");
- return;
- }
-
- sg_virt = tmio_mmc_kmap_atomic(host->sg_ptr, &flags);
- buf = (unsigned short *)(sg_virt + host->sg_off);
-
- count = host->sg_ptr->length - host->sg_off;
- if (count > data->blksz)
- count = data->blksz;
-
- pr_debug("count: %08x offset: %08x flags %08x\n",
- count, host->sg_off, data->flags);
-
- /* Transfer the data */
- if (data->flags & MMC_DATA_READ)
- sd_ctrl_read16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1);
- else
- sd_ctrl_write16_rep(host, CTL_SD_DATA_PORT, buf, count >> 1);
-
- host->sg_off += count;
-
- tmio_mmc_kunmap_atomic(host->sg_ptr, &flags, sg_virt);
-
- if (host->sg_off == host->sg_ptr->length)
- tmio_mmc_next_sg(host);
-
- return;
-}
-
-static void tmio_mmc_check_bounce_buffer(struct tmio_mmc_host *host)
-{
- if (host->sg_ptr == &host->bounce_sg) {
- unsigned long flags;
- void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig, &flags);
- memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length);
- tmio_mmc_kunmap_atomic(host->sg_orig, &flags, sg_vaddr);
- }
-}
-
-/* needs to be called with host->lock held */
-void tmio_mmc_do_data_irq(struct tmio_mmc_host *host)
-{
- struct mmc_data *data = host->data;
- struct mmc_command *stop;
-
- host->data = NULL;
-
- if (!data) {
- dev_warn(&host->pdev->dev, "Spurious data end IRQ\n");
- return;
- }
- stop = data->stop;
-
- /* FIXME - return correct transfer count on errors */
- if (!data->error)
- data->bytes_xfered = data->blocks * data->blksz;
- else
- data->bytes_xfered = 0;
-
- pr_debug("Completed data request\n");
-
- /*
- * FIXME: other drivers allow an optional stop command of any given type
- * which we dont do, as the chip can auto generate them.
- * Perhaps we can be smarter about when to use auto CMD12 and
- * only issue the auto request when we know this is the desired
- * stop command, allowing fallback to the stop command the
- * upper layers expect. For now, we do what works.
- */
-
- if (data->flags & MMC_DATA_READ) {
- if (host->chan_rx && !host->force_pio)
- tmio_mmc_check_bounce_buffer(host);
- dev_dbg(&host->pdev->dev, "Complete Rx request %p\n",
- host->mrq);
- } else {
- dev_dbg(&host->pdev->dev, "Complete Tx request %p\n",
- host->mrq);
- }
-
- if (stop) {
- if (stop->opcode == 12 && !stop->arg)
- sd_ctrl_write16(host, CTL_STOP_INTERNAL_ACTION, 0x000);
- else
- BUG();
- }
-
- schedule_work(&host->done);
-}
-
-static void tmio_mmc_data_irq(struct tmio_mmc_host *host)
-{
- struct mmc_data *data;
- spin_lock(&host->lock);
- data = host->data;
-
- if (!data)
- goto out;
-
- if (host->chan_tx && (data->flags & MMC_DATA_WRITE) && !host->force_pio) {
- /*
- * Has all data been written out yet? Testing on SuperH showed,
- * that in most cases the first interrupt comes already with the
- * BUSY status bit clear, but on some operations, like mount or
- * in the beginning of a write / sync / umount, there is one
- * DATAEND interrupt with the BUSY bit set, in this cases
- * waiting for one more interrupt fixes the problem.
- */
- if (!(sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_CMD_BUSY)) {
- tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND);
- tasklet_schedule(&host->dma_complete);
- }
- } else if (host->chan_rx && (data->flags & MMC_DATA_READ) && !host->force_pio) {
- tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_DATAEND);
- tasklet_schedule(&host->dma_complete);
- } else {
- tmio_mmc_do_data_irq(host);
- tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_READOP | TMIO_MASK_WRITEOP);
- }
-out:
- spin_unlock(&host->lock);
-}
-
-static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host,
- unsigned int stat)
-{
- struct mmc_command *cmd = host->cmd;
- int i, addr;
-
- spin_lock(&host->lock);
-
- if (!host->cmd) {
- pr_debug("Spurious CMD irq\n");
- goto out;
- }
-
- host->cmd = NULL;
-
- /* This controller is sicker than the PXA one. Not only do we need to
- * drop the top 8 bits of the first response word, we also need to
- * modify the order of the response for short response command types.
- */
-
- for (i = 3, addr = CTL_RESPONSE ; i >= 0 ; i--, addr += 4)
- cmd->resp[i] = sd_ctrl_read32(host, addr);
-
- if (cmd->flags & MMC_RSP_136) {
- cmd->resp[0] = (cmd->resp[0] << 8) | (cmd->resp[1] >> 24);
- cmd->resp[1] = (cmd->resp[1] << 8) | (cmd->resp[2] >> 24);
- cmd->resp[2] = (cmd->resp[2] << 8) | (cmd->resp[3] >> 24);
- cmd->resp[3] <<= 8;
- } else if (cmd->flags & MMC_RSP_R3) {
- cmd->resp[0] = cmd->resp[3];
- }
-
- if (stat & TMIO_STAT_CMDTIMEOUT)
- cmd->error = -ETIMEDOUT;
- else if (stat & TMIO_STAT_CRCFAIL && cmd->flags & MMC_RSP_CRC)
- cmd->error = -EILSEQ;
-
- /* If there is data to handle we enable data IRQs here, and
- * we will ultimatley finish the request in the data_end handler.
- * If theres no data or we encountered an error, finish now.
- */
- if (host->data && !cmd->error) {
- if (host->data->flags & MMC_DATA_READ) {
- if (host->force_pio || !host->chan_rx)
- tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_READOP);
- else
- tasklet_schedule(&host->dma_issue);
- } else {
- if (host->force_pio || !host->chan_tx)
- tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_WRITEOP);
- else
- tasklet_schedule(&host->dma_issue);
- }
- } else {
- schedule_work(&host->done);
- }
-
-out:
- spin_unlock(&host->lock);
-}
-
-static void tmio_mmc_card_irq_status(struct tmio_mmc_host *host,
- int *ireg, int *status)
-{
- *status = sd_ctrl_read32(host, CTL_STATUS);
- *ireg = *status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask;
-
- pr_debug_status(*status);
- pr_debug_status(*ireg);
-}
-
-static bool __tmio_mmc_card_detect_irq(struct tmio_mmc_host *host,
- int ireg, int status)
-{
- struct mmc_host *mmc = host->mmc;
-
- /* Card insert / remove attempts */
- if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) {
- tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_CARD_INSERT |
- TMIO_STAT_CARD_REMOVE);
- if ((((ireg & TMIO_STAT_CARD_REMOVE) && mmc->card) ||
- ((ireg & TMIO_STAT_CARD_INSERT) && !mmc->card)) &&
- !work_pending(&mmc->detect.work))
- mmc_detect_change(host->mmc, msecs_to_jiffies(100));
- return true;
- }
-
- return false;
-}
-
-irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid)
-{
- unsigned int ireg, status;
- struct tmio_mmc_host *host = devid;
-
- tmio_mmc_card_irq_status(host, &ireg, &status);
- __tmio_mmc_card_detect_irq(host, ireg, status);
-
- return IRQ_HANDLED;
-}
-EXPORT_SYMBOL(tmio_mmc_card_detect_irq);
-
-static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host,
- int ireg, int status)
-{
- /* Command completion */
- if (ireg & (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT)) {
- tmio_mmc_ack_mmc_irqs(host,
- TMIO_STAT_CMDRESPEND |
- TMIO_STAT_CMDTIMEOUT);
- tmio_mmc_cmd_irq(host, status);
- return true;
- }
-
- /* Data transfer */
- if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) {
- tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ);
- tmio_mmc_pio_irq(host);
- return true;
- }
-
- /* Data transfer completion */
- if (ireg & TMIO_STAT_DATAEND) {
- tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_DATAEND);
- tmio_mmc_data_irq(host);
- return true;
- }
-
- return false;
-}
-
-irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid)
-{
- unsigned int ireg, status;
- struct tmio_mmc_host *host = devid;
-
- tmio_mmc_card_irq_status(host, &ireg, &status);
- __tmio_mmc_sdcard_irq(host, ireg, status);
-
- return IRQ_HANDLED;
-}
-EXPORT_SYMBOL(tmio_mmc_sdcard_irq);
-
-irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid)
-{
- struct tmio_mmc_host *host = devid;
- struct mmc_host *mmc = host->mmc;
- struct tmio_mmc_data *pdata = host->pdata;
- unsigned int ireg, status;
-
- if (!(pdata->flags & TMIO_MMC_SDIO_IRQ))
- return IRQ_HANDLED;
-
- status = sd_ctrl_read16(host, CTL_SDIO_STATUS);
- ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdcard_irq_mask;
-
- sd_ctrl_write16(host, CTL_SDIO_STATUS, status & ~TMIO_SDIO_MASK_ALL);
-
- if (mmc->caps & MMC_CAP_SDIO_IRQ && ireg & TMIO_SDIO_STAT_IOIRQ)
- mmc_signal_sdio_irq(mmc);
-
- return IRQ_HANDLED;
-}
-EXPORT_SYMBOL(tmio_mmc_sdio_irq);
-
-irqreturn_t tmio_mmc_irq(int irq, void *devid)
-{
- struct tmio_mmc_host *host = devid;
- unsigned int ireg, status;
-
- pr_debug("MMC IRQ begin\n");
-
- tmio_mmc_card_irq_status(host, &ireg, &status);
- if (__tmio_mmc_card_detect_irq(host, ireg, status))
- return IRQ_HANDLED;
- if (__tmio_mmc_sdcard_irq(host, ireg, status))
- return IRQ_HANDLED;
-
- tmio_mmc_sdio_irq(irq, devid);
-
- return IRQ_HANDLED;
-}
-EXPORT_SYMBOL(tmio_mmc_irq);
-
-static int tmio_mmc_start_data(struct tmio_mmc_host *host,
- struct mmc_data *data)
-{
- struct tmio_mmc_data *pdata = host->pdata;
-
- pr_debug("setup data transfer: blocksize %08x nr_blocks %d\n",
- data->blksz, data->blocks);
-
- /* Some hardware cannot perform 2 byte requests in 4 bit mode */
- if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_4) {
- int blksz_2bytes = pdata->flags & TMIO_MMC_BLKSZ_2BYTES;
-
- if (data->blksz < 2 || (data->blksz < 4 && !blksz_2bytes)) {
- pr_err("%s: %d byte block unsupported in 4 bit mode\n",
- mmc_hostname(host->mmc), data->blksz);
- return -EINVAL;
- }
- }
-
- tmio_mmc_init_sg(host, data);
- host->data = data;
-
- /* Set transfer length / blocksize */
- sd_ctrl_write16(host, CTL_SD_XFER_LEN, data->blksz);
- sd_ctrl_write16(host, CTL_XFER_BLK_COUNT, data->blocks);
-
- tmio_mmc_start_dma(host, data);
-
- return 0;
-}
-
-/* Process requests from the MMC layer */
-static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct tmio_mmc_host *host = mmc_priv(mmc);
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&host->lock, flags);
-
- if (host->mrq) {
- pr_debug("request not null\n");
- if (IS_ERR(host->mrq)) {
- spin_unlock_irqrestore(&host->lock, flags);
- mrq->cmd->error = -EAGAIN;
- mmc_request_done(mmc, mrq);
- return;
- }
- }
-
- host->last_req_ts = jiffies;
- wmb();
- host->mrq = mrq;
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- if (mrq->data) {
- ret = tmio_mmc_start_data(host, mrq->data);
- if (ret)
- goto fail;
- }
-
- ret = tmio_mmc_start_command(host, mrq->cmd);
- if (!ret) {
- schedule_delayed_work(&host->delayed_reset_work,
- msecs_to_jiffies(2000));
- return;
- }
-
-fail:
- host->force_pio = false;
- host->mrq = NULL;
- mrq->cmd->error = ret;
- mmc_request_done(mmc, mrq);
-}
-
-/* Set MMC clock / power.
- * Note: This controller uses a simple divider scheme therefore it cannot
- * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as
- * MMC wont run that fast, it has to be clocked at 12MHz which is the next
- * slowest setting.
- */
-static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct tmio_mmc_host *host = mmc_priv(mmc);
- struct device *dev = &host->pdev->dev;
- unsigned long flags;
-
- mutex_lock(&host->ios_lock);
-
- spin_lock_irqsave(&host->lock, flags);
- if (host->mrq) {
- if (IS_ERR(host->mrq)) {
- dev_dbg(dev,
- "%s.%d: concurrent .set_ios(), clk %u, mode %u\n",
- current->comm, task_pid_nr(current),
- ios->clock, ios->power_mode);
- host->mrq = ERR_PTR(-EINTR);
- } else {
- dev_dbg(dev,
- "%s.%d: CMD%u active since %lu, now %lu!\n",
- current->comm, task_pid_nr(current),
- host->mrq->cmd->opcode, host->last_req_ts, jiffies);
- }
- spin_unlock_irqrestore(&host->lock, flags);
-
- mutex_unlock(&host->ios_lock);
- return;
- }
-
- host->mrq = ERR_PTR(-EBUSY);
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- /*
- * host->power toggles between false and true in both cases - either
- * or not the controller can be runtime-suspended during inactivity.
- * But if the controller has to be kept on, the runtime-pm usage_count
- * is kept positive, so no suspending actually takes place.
- */
- if (ios->power_mode == MMC_POWER_ON && ios->clock) {
- if (!host->power) {
- pm_runtime_get_sync(dev);
- host->power = true;
- }
- tmio_mmc_set_clock(host, ios->clock);
- /* power up SD bus */
- if (host->set_pwr)
- host->set_pwr(host->pdev, 1);
- /* start bus clock */
- tmio_mmc_clk_start(host);
- } else if (ios->power_mode != MMC_POWER_UP) {
- if (host->set_pwr && ios->power_mode == MMC_POWER_OFF)
- host->set_pwr(host->pdev, 0);
- if (host->power) {
- host->power = false;
- pm_runtime_put(dev);
- }
- tmio_mmc_clk_stop(host);
- }
-
- switch (ios->bus_width) {
- case MMC_BUS_WIDTH_1:
- sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x80e0);
- break;
- case MMC_BUS_WIDTH_4:
- sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, 0x00e0);
- break;
- }
-
- /* Let things settle. delay taken from winCE driver */
- udelay(140);
- if (PTR_ERR(host->mrq) == -EINTR)
- dev_dbg(&host->pdev->dev,
- "%s.%d: IOS interrupted: clk %u, mode %u",
- current->comm, task_pid_nr(current),
- ios->clock, ios->power_mode);
- host->mrq = NULL;
-
- mutex_unlock(&host->ios_lock);
-}
-
-static int tmio_mmc_get_ro(struct mmc_host *mmc)
-{
- struct tmio_mmc_host *host = mmc_priv(mmc);
- struct tmio_mmc_data *pdata = host->pdata;
-
- return !((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) ||
- (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT));
-}
-
-static int tmio_mmc_get_cd(struct mmc_host *mmc)
-{
- struct tmio_mmc_host *host = mmc_priv(mmc);
- struct tmio_mmc_data *pdata = host->pdata;
-
- if (!pdata->get_cd)
- return -ENOSYS;
- else
- return pdata->get_cd(host->pdev);
-}
-
-static const struct mmc_host_ops tmio_mmc_ops = {
- .request = tmio_mmc_request,
- .set_ios = tmio_mmc_set_ios,
- .get_ro = tmio_mmc_get_ro,
- .get_cd = tmio_mmc_get_cd,
- .enable_sdio_irq = tmio_mmc_enable_sdio_irq,
-};
-
-int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
- struct platform_device *pdev,
- struct tmio_mmc_data *pdata)
-{
- struct tmio_mmc_host *_host;
- struct mmc_host *mmc;
- struct resource *res_ctl;
- int ret;
- u32 irq_mask = TMIO_MASK_CMD;
-
- res_ctl = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res_ctl)
- return -EINVAL;
-
- mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &pdev->dev);
- if (!mmc)
- return -ENOMEM;
-
- pdata->dev = &pdev->dev;
- _host = mmc_priv(mmc);
- _host->pdata = pdata;
- _host->mmc = mmc;
- _host->pdev = pdev;
- platform_set_drvdata(pdev, mmc);
-
- _host->set_pwr = pdata->set_pwr;
- _host->set_clk_div = pdata->set_clk_div;
-
- /* SD control register space size is 0x200, 0x400 for bus_shift=1 */
- _host->bus_shift = resource_size(res_ctl) >> 10;
-
- _host->ctl = ioremap(res_ctl->start, resource_size(res_ctl));
- if (!_host->ctl) {
- ret = -ENOMEM;
- goto host_free;
- }
-
- mmc->ops = &tmio_mmc_ops;
- mmc->caps = MMC_CAP_4_BIT_DATA | pdata->capabilities;
- mmc->f_max = pdata->hclk;
- mmc->f_min = mmc->f_max / 512;
- mmc->max_segs = 32;
- mmc->max_blk_size = 512;
- mmc->max_blk_count = (PAGE_CACHE_SIZE / mmc->max_blk_size) *
- mmc->max_segs;
- mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
- mmc->max_seg_size = mmc->max_req_size;
- if (pdata->ocr_mask)
- mmc->ocr_avail = pdata->ocr_mask;
- else
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-
- _host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD ||
- mmc->caps & MMC_CAP_NEEDS_POLL ||
- mmc->caps & MMC_CAP_NONREMOVABLE);
-
- _host->power = false;
- pm_runtime_enable(&pdev->dev);
- ret = pm_runtime_resume(&pdev->dev);
- if (ret < 0)
- goto pm_disable;
-
- /*
- * There are 4 different scenarios for the card detection:
- * 1) an external gpio irq handles the cd (best for power savings)
- * 2) internal sdhi irq handles the cd
- * 3) a worker thread polls the sdhi - indicated by MMC_CAP_NEEDS_POLL
- * 4) the medium is non-removable - indicated by MMC_CAP_NONREMOVABLE
- *
- * While we increment the runtime PM counter for all scenarios when
- * the mmc core activates us by calling an appropriate set_ios(), we
- * must additionally ensure that in case 2) the tmio mmc hardware stays
- * additionally ensure that in case 2) the tmio mmc hardware stays
- * powered on during runtime for the card detection to work.
- */
- if (_host->native_hotplug)
- pm_runtime_get_noresume(&pdev->dev);
-
- tmio_mmc_clk_stop(_host);
- tmio_mmc_reset(_host);
-
- _host->sdcard_irq_mask = sd_ctrl_read32(_host, CTL_IRQ_MASK);
- tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL);
- if (pdata->flags & TMIO_MMC_SDIO_IRQ)
- tmio_mmc_enable_sdio_irq(mmc, 0);
-
- spin_lock_init(&_host->lock);
- mutex_init(&_host->ios_lock);
-
- /* Init delayed work for request timeouts */
- INIT_DELAYED_WORK(&_host->delayed_reset_work, tmio_mmc_reset_work);
- INIT_WORK(&_host->done, tmio_mmc_done_work);
-
- /* See if we also get DMA */
- tmio_mmc_request_dma(_host, pdata);
-
- mmc_add_host(mmc);
-
- dev_pm_qos_expose_latency_limit(&pdev->dev, 100);
-
- /* Unmask the IRQs we want to know about */
- if (!_host->chan_rx)
- irq_mask |= TMIO_MASK_READOP;
- if (!_host->chan_tx)
- irq_mask |= TMIO_MASK_WRITEOP;
- if (!_host->native_hotplug)
- irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT);
-
- tmio_mmc_enable_mmc_irqs(_host, irq_mask);
-
- if (pdata->flags & TMIO_MMC_USE_GPIO_CD) {
- ret = mmc_cd_gpio_request(mmc, pdata->cd_gpio);
- if (ret < 0) {
- tmio_mmc_host_remove(_host);
- return ret;
- }
- }
-
- *host = _host;
-
- return 0;
-
-pm_disable:
- pm_runtime_disable(&pdev->dev);
- iounmap(_host->ctl);
-host_free:
- mmc_free_host(mmc);
-
- return ret;
-}
-EXPORT_SYMBOL(tmio_mmc_host_probe);
-
-void tmio_mmc_host_remove(struct tmio_mmc_host *host)
-{
- struct platform_device *pdev = host->pdev;
- struct tmio_mmc_data *pdata = host->pdata;
- struct mmc_host *mmc = host->mmc;
-
- if (pdata->flags & TMIO_MMC_USE_GPIO_CD)
- /*
- * This means we can miss a card-eject, but this is anyway
- * possible, because of delayed processing of hotplug events.
- */
- mmc_cd_gpio_free(mmc);
-
- if (!host->native_hotplug)
- pm_runtime_get_sync(&pdev->dev);
-
- dev_pm_qos_hide_latency_limit(&pdev->dev);
-
- mmc_remove_host(mmc);
- cancel_work_sync(&host->done);
- cancel_delayed_work_sync(&host->delayed_reset_work);
- tmio_mmc_release_dma(host);
-
- pm_runtime_put_sync(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
-
- iounmap(host->ctl);
- mmc_free_host(mmc);
-}
-EXPORT_SYMBOL(tmio_mmc_host_remove);
-
-#ifdef CONFIG_PM
-int tmio_mmc_host_suspend(struct device *dev)
-{
- struct mmc_host *mmc = dev_get_drvdata(dev);
- struct tmio_mmc_host *host = mmc_priv(mmc);
- int ret = mmc_suspend_host(mmc);
-
- if (!ret)
- tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL);
-
- return ret;
-}
-EXPORT_SYMBOL(tmio_mmc_host_suspend);
-
-int tmio_mmc_host_resume(struct device *dev)
-{
- struct mmc_host *mmc = dev_get_drvdata(dev);
- struct tmio_mmc_host *host = mmc_priv(mmc);
-
- tmio_mmc_reset(host);
- tmio_mmc_enable_dma(host, true);
-
- /* The MMC core will perform the complete set up */
- return mmc_resume_host(mmc);
-}
-EXPORT_SYMBOL(tmio_mmc_host_resume);
-
-#endif /* CONFIG_PM */
-
-int tmio_mmc_host_runtime_suspend(struct device *dev)
-{
- return 0;
-}
-EXPORT_SYMBOL(tmio_mmc_host_runtime_suspend);
-
-int tmio_mmc_host_runtime_resume(struct device *dev)
-{
- struct mmc_host *mmc = dev_get_drvdata(dev);
- struct tmio_mmc_host *host = mmc_priv(mmc);
-
- tmio_mmc_reset(host);
- tmio_mmc_enable_dma(host, true);
-
- return 0;
-}
-EXPORT_SYMBOL(tmio_mmc_host_runtime_resume);
-
-MODULE_LICENSE("GPL v2");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/ushc.c b/ANDROID_3.4.5/drivers/mmc/host/ushc.c
deleted file mode 100644
index c0105a2e..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/ushc.c
+++ /dev/null
@@ -1,569 +0,0 @@
-/*
- * 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/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;
-
- 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) {
- ret = -ENOMEM;
- goto err;
- }
- ushc->int_data = kzalloc(sizeof(struct ushc_int_data), GFP_KERNEL);
- if (ushc->int_data == NULL) {
- ret = -ENOMEM;
- 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) {
- ret = -ENOMEM;
- goto err;
- }
- ushc->cbw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL);
- if (ushc->cbw == NULL) {
- ret = -ENOMEM;
- 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) {
- ret = -ENOMEM;
- goto err;
- }
-
- ushc->csw_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (ushc->csw_urb == NULL) {
- ret = -ENOMEM;
- goto err;
- }
- ushc->csw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL);
- if (ushc->csw == NULL) {
- ret = -ENOMEM;
- 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,
-};
-
-module_usb_driver(ushc_driver);
-
-MODULE_DESCRIPTION("USB SD Host Controller driver");
-MODULE_AUTHOR("David Vrabel <david.vrabel@csr.com>");
-MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/via-sdmmc.c b/ANDROID_3.4.5/drivers/mmc/host/via-sdmmc.c
deleted file mode 100644
index 4b83c43f..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/via-sdmmc.c
+++ /dev/null
@@ -1,1358 +0,0 @@
-/*
- * drivers/mmc/host/via-sdmmc.c - VIA SD/MMC Card Reader driver
- * Copyright (c) 2008, VIA Technologies Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-
-#include <linux/pci.h>
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/highmem.h>
-#include <linux/delay.h>
-
-#include <linux/mmc/host.h>
-
-#define DRV_NAME "via_sdmmc"
-
-#define PCI_DEVICE_ID_VIA_9530 0x9530
-
-#define VIA_CRDR_SDC_OFF 0x200
-#define VIA_CRDR_DDMA_OFF 0x400
-#define VIA_CRDR_PCICTRL_OFF 0x600
-
-#define VIA_CRDR_MIN_CLOCK 375000
-#define VIA_CRDR_MAX_CLOCK 48000000
-
-/*
- * PCI registers
- */
-
-#define VIA_CRDR_PCI_WORK_MODE 0x40
-#define VIA_CRDR_PCI_DBG_MODE 0x41
-
-/*
- * SDC MMIO Registers
- */
-
-#define VIA_CRDR_SDCTRL 0x0
-#define VIA_CRDR_SDCTRL_START 0x01
-#define VIA_CRDR_SDCTRL_WRITE 0x04
-#define VIA_CRDR_SDCTRL_SINGLE_WR 0x10
-#define VIA_CRDR_SDCTRL_SINGLE_RD 0x20
-#define VIA_CRDR_SDCTRL_MULTI_WR 0x30
-#define VIA_CRDR_SDCTRL_MULTI_RD 0x40
-#define VIA_CRDR_SDCTRL_STOP 0x70
-
-#define VIA_CRDR_SDCTRL_RSP_NONE 0x0
-#define VIA_CRDR_SDCTRL_RSP_R1 0x10000
-#define VIA_CRDR_SDCTRL_RSP_R2 0x20000
-#define VIA_CRDR_SDCTRL_RSP_R3 0x30000
-#define VIA_CRDR_SDCTRL_RSP_R1B 0x90000
-
-#define VIA_CRDR_SDCARG 0x4
-
-#define VIA_CRDR_SDBUSMODE 0x8
-#define VIA_CRDR_SDMODE_4BIT 0x02
-#define VIA_CRDR_SDMODE_CLK_ON 0x40
-
-#define VIA_CRDR_SDBLKLEN 0xc
-/*
- * Bit 0 -Bit 10 : Block length. So, the maximum block length should be 2048.
- * Bit 11 - Bit 13 : Reserved.
- * GPIDET : Select GPI pin to detect card, GPI means CR_CD# in top design.
- * INTEN : Enable SD host interrupt.
- * Bit 16 - Bit 31 : Block count. So, the maximun block count should be 65536.
- */
-#define VIA_CRDR_SDBLKLEN_GPIDET 0x2000
-#define VIA_CRDR_SDBLKLEN_INTEN 0x8000
-#define VIA_CRDR_MAX_BLOCK_COUNT 65536
-#define VIA_CRDR_MAX_BLOCK_LENGTH 2048
-
-#define VIA_CRDR_SDRESP0 0x10
-#define VIA_CRDR_SDRESP1 0x14
-#define VIA_CRDR_SDRESP2 0x18
-#define VIA_CRDR_SDRESP3 0x1c
-
-#define VIA_CRDR_SDCURBLKCNT 0x20
-
-#define VIA_CRDR_SDINTMASK 0x24
-/*
- * MBDIE : Multiple Blocks transfer Done Interrupt Enable
- * BDDIE : Block Data transfer Done Interrupt Enable
- * CIRIE : Card Insertion or Removal Interrupt Enable
- * CRDIE : Command-Response transfer Done Interrupt Enable
- * CRTOIE : Command-Response response TimeOut Interrupt Enable
- * ASCRDIE : Auto Stop Command-Response transfer Done Interrupt Enable
- * DTIE : Data access Timeout Interrupt Enable
- * SCIE : reSponse CRC error Interrupt Enable
- * RCIE : Read data CRC error Interrupt Enable
- * WCIE : Write data CRC error Interrupt Enable
- */
-#define VIA_CRDR_SDINTMASK_MBDIE 0x10
-#define VIA_CRDR_SDINTMASK_BDDIE 0x20
-#define VIA_CRDR_SDINTMASK_CIRIE 0x80
-#define VIA_CRDR_SDINTMASK_CRDIE 0x200
-#define VIA_CRDR_SDINTMASK_CRTOIE 0x400
-#define VIA_CRDR_SDINTMASK_ASCRDIE 0x800
-#define VIA_CRDR_SDINTMASK_DTIE 0x1000
-#define VIA_CRDR_SDINTMASK_SCIE 0x2000
-#define VIA_CRDR_SDINTMASK_RCIE 0x4000
-#define VIA_CRDR_SDINTMASK_WCIE 0x8000
-
-#define VIA_CRDR_SDACTIVE_INTMASK \
- (VIA_CRDR_SDINTMASK_MBDIE | VIA_CRDR_SDINTMASK_CIRIE \
- | VIA_CRDR_SDINTMASK_CRDIE | VIA_CRDR_SDINTMASK_CRTOIE \
- | VIA_CRDR_SDINTMASK_DTIE | VIA_CRDR_SDINTMASK_SCIE \
- | VIA_CRDR_SDINTMASK_RCIE | VIA_CRDR_SDINTMASK_WCIE)
-
-#define VIA_CRDR_SDSTATUS 0x28
-/*
- * CECC : Reserved
- * WP : SD card Write Protect status
- * SLOTD : Reserved
- * SLOTG : SD SLOT status(Gpi pin status)
- * MBD : Multiple Blocks transfer Done interrupt status
- * BDD : Block Data transfer Done interrupt status
- * CD : Reserved
- * CIR : Card Insertion or Removal interrupt detected on GPI pin
- * IO : Reserved
- * CRD : Command-Response transfer Done interrupt status
- * CRTO : Command-Response response TimeOut interrupt status
- * ASCRDIE : Auto Stop Command-Response transfer Done interrupt status
- * DT : Data access Timeout interrupt status
- * SC : reSponse CRC error interrupt status
- * RC : Read data CRC error interrupt status
- * WC : Write data CRC error interrupt status
- */
-#define VIA_CRDR_SDSTS_CECC 0x01
-#define VIA_CRDR_SDSTS_WP 0x02
-#define VIA_CRDR_SDSTS_SLOTD 0x04
-#define VIA_CRDR_SDSTS_SLOTG 0x08
-#define VIA_CRDR_SDSTS_MBD 0x10
-#define VIA_CRDR_SDSTS_BDD 0x20
-#define VIA_CRDR_SDSTS_CD 0x40
-#define VIA_CRDR_SDSTS_CIR 0x80
-#define VIA_CRDR_SDSTS_IO 0x100
-#define VIA_CRDR_SDSTS_CRD 0x200
-#define VIA_CRDR_SDSTS_CRTO 0x400
-#define VIA_CRDR_SDSTS_ASCRDIE 0x800
-#define VIA_CRDR_SDSTS_DT 0x1000
-#define VIA_CRDR_SDSTS_SC 0x2000
-#define VIA_CRDR_SDSTS_RC 0x4000
-#define VIA_CRDR_SDSTS_WC 0x8000
-
-#define VIA_CRDR_SDSTS_IGN_MASK\
- (VIA_CRDR_SDSTS_BDD | VIA_CRDR_SDSTS_ASCRDIE | VIA_CRDR_SDSTS_IO)
-#define VIA_CRDR_SDSTS_INT_MASK \
- (VIA_CRDR_SDSTS_MBD | VIA_CRDR_SDSTS_BDD | VIA_CRDR_SDSTS_CD \
- | VIA_CRDR_SDSTS_CIR | VIA_CRDR_SDSTS_IO | VIA_CRDR_SDSTS_CRD \
- | VIA_CRDR_SDSTS_CRTO | VIA_CRDR_SDSTS_ASCRDIE | VIA_CRDR_SDSTS_DT \
- | VIA_CRDR_SDSTS_SC | VIA_CRDR_SDSTS_RC | VIA_CRDR_SDSTS_WC)
-#define VIA_CRDR_SDSTS_W1C_MASK \
- (VIA_CRDR_SDSTS_CECC | VIA_CRDR_SDSTS_MBD | VIA_CRDR_SDSTS_BDD \
- | VIA_CRDR_SDSTS_CD | VIA_CRDR_SDSTS_CIR | VIA_CRDR_SDSTS_CRD \
- | VIA_CRDR_SDSTS_CRTO | VIA_CRDR_SDSTS_ASCRDIE | VIA_CRDR_SDSTS_DT \
- | VIA_CRDR_SDSTS_SC | VIA_CRDR_SDSTS_RC | VIA_CRDR_SDSTS_WC)
-#define VIA_CRDR_SDSTS_CMD_MASK \
- (VIA_CRDR_SDSTS_CRD | VIA_CRDR_SDSTS_CRTO | VIA_CRDR_SDSTS_SC)
-#define VIA_CRDR_SDSTS_DATA_MASK\
- (VIA_CRDR_SDSTS_MBD | VIA_CRDR_SDSTS_DT \
- | VIA_CRDR_SDSTS_RC | VIA_CRDR_SDSTS_WC)
-
-#define VIA_CRDR_SDSTATUS2 0x2a
-/*
- * CFE : Enable SD host automatic Clock FReezing
- */
-#define VIA_CRDR_SDSTS_CFE 0x80
-
-#define VIA_CRDR_SDRSPTMO 0x2C
-
-#define VIA_CRDR_SDCLKSEL 0x30
-
-#define VIA_CRDR_SDEXTCTRL 0x34
-#define VIS_CRDR_SDEXTCTRL_AUTOSTOP_SD 0x01
-#define VIS_CRDR_SDEXTCTRL_SHIFT_9 0x02
-#define VIS_CRDR_SDEXTCTRL_MMC_8BIT 0x04
-#define VIS_CRDR_SDEXTCTRL_RELD_BLK 0x08
-#define VIS_CRDR_SDEXTCTRL_BAD_CMDA 0x10
-#define VIS_CRDR_SDEXTCTRL_BAD_DATA 0x20
-#define VIS_CRDR_SDEXTCTRL_AUTOSTOP_SPI 0x40
-#define VIA_CRDR_SDEXTCTRL_HISPD 0x80
-/* 0x38-0xFF reserved */
-
-/*
- * Data DMA Control Registers
- */
-
-#define VIA_CRDR_DMABASEADD 0x0
-#define VIA_CRDR_DMACOUNTER 0x4
-
-#define VIA_CRDR_DMACTRL 0x8
-/*
- * DIR :Transaction Direction
- * 0 : From card to memory
- * 1 : From memory to card
- */
-#define VIA_CRDR_DMACTRL_DIR 0x100
-#define VIA_CRDR_DMACTRL_ENIRQ 0x10000
-#define VIA_CRDR_DMACTRL_SFTRST 0x1000000
-
-#define VIA_CRDR_DMASTS 0xc
-
-#define VIA_CRDR_DMASTART 0x10
-/*0x14-0xFF reserved*/
-
-/*
- * PCI Control Registers
- */
-
-/*0x0 - 0x1 reserved*/
-#define VIA_CRDR_PCICLKGATT 0x2
-/*
- * SFTRST :
- * 0 : Soft reset all the controller and it will be de-asserted automatically
- * 1 : Soft reset is de-asserted
- */
-#define VIA_CRDR_PCICLKGATT_SFTRST 0x01
-/*
- * 3V3 : Pad power select
- * 0 : 1.8V
- * 1 : 3.3V
- * NOTE : No mater what the actual value should be, this bit always
- * read as 0. This is a hardware bug.
- */
-#define VIA_CRDR_PCICLKGATT_3V3 0x10
-/*
- * PAD_PWRON : Pad Power on/off select
- * 0 : Power off
- * 1 : Power on
- * NOTE : No mater what the actual value should be, this bit always
- * read as 0. This is a hardware bug.
- */
-#define VIA_CRDR_PCICLKGATT_PAD_PWRON 0x20
-
-#define VIA_CRDR_PCISDCCLK 0x5
-
-#define VIA_CRDR_PCIDMACLK 0x7
-#define VIA_CRDR_PCIDMACLK_SDC 0x2
-
-#define VIA_CRDR_PCIINTCTRL 0x8
-#define VIA_CRDR_PCIINTCTRL_SDCIRQEN 0x04
-
-#define VIA_CRDR_PCIINTSTATUS 0x9
-#define VIA_CRDR_PCIINTSTATUS_SDC 0x04
-
-#define VIA_CRDR_PCITMOCTRL 0xa
-#define VIA_CRDR_PCITMOCTRL_NO 0x0
-#define VIA_CRDR_PCITMOCTRL_32US 0x1
-#define VIA_CRDR_PCITMOCTRL_256US 0x2
-#define VIA_CRDR_PCITMOCTRL_1024US 0x3
-#define VIA_CRDR_PCITMOCTRL_256MS 0x4
-#define VIA_CRDR_PCITMOCTRL_512MS 0x5
-#define VIA_CRDR_PCITMOCTRL_1024MS 0x6
-
-/*0xB-0xFF reserved*/
-
-enum PCI_HOST_CLK_CONTROL {
- PCI_CLK_375K = 0x03,
- PCI_CLK_8M = 0x04,
- PCI_CLK_12M = 0x00,
- PCI_CLK_16M = 0x05,
- PCI_CLK_24M = 0x01,
- PCI_CLK_33M = 0x06,
- PCI_CLK_48M = 0x02
-};
-
-struct sdhcreg {
- u32 sdcontrol_reg;
- u32 sdcmdarg_reg;
- u32 sdbusmode_reg;
- u32 sdblklen_reg;
- u32 sdresp_reg[4];
- u32 sdcurblkcnt_reg;
- u32 sdintmask_reg;
- u32 sdstatus_reg;
- u32 sdrsptmo_reg;
- u32 sdclksel_reg;
- u32 sdextctrl_reg;
-};
-
-struct pcictrlreg {
- u8 reserve[2];
- u8 pciclkgat_reg;
- u8 pcinfcclk_reg;
- u8 pcimscclk_reg;
- u8 pcisdclk_reg;
- u8 pcicaclk_reg;
- u8 pcidmaclk_reg;
- u8 pciintctrl_reg;
- u8 pciintstatus_reg;
- u8 pcitmoctrl_reg;
- u8 Resv;
-};
-
-struct via_crdr_mmc_host {
- struct mmc_host *mmc;
- struct mmc_request *mrq;
- struct mmc_command *cmd;
- struct mmc_data *data;
-
- void __iomem *mmiobase;
- void __iomem *sdhc_mmiobase;
- void __iomem *ddma_mmiobase;
- void __iomem *pcictrl_mmiobase;
-
- struct pcictrlreg pm_pcictrl_reg;
- struct sdhcreg pm_sdhc_reg;
-
- struct work_struct carddet_work;
- struct tasklet_struct finish_tasklet;
-
- struct timer_list timer;
- spinlock_t lock;
- u8 power;
- int reject;
- unsigned int quirks;
-};
-
-/* some devices need a very long delay for power to stabilize */
-#define VIA_CRDR_QUIRK_300MS_PWRDELAY 0x0001
-
-static struct pci_device_id via_ids[] = {
- {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_9530,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,},
- {0,}
-};
-
-MODULE_DEVICE_TABLE(pci, via_ids);
-
-static void via_print_sdchc(struct via_crdr_mmc_host *host)
-{
- void __iomem *addrbase = host->sdhc_mmiobase;
-
- pr_debug("SDC MMIO Registers:\n");
- pr_debug("SDCONTROL=%08x, SDCMDARG=%08x, SDBUSMODE=%08x\n",
- readl(addrbase + VIA_CRDR_SDCTRL),
- readl(addrbase + VIA_CRDR_SDCARG),
- readl(addrbase + VIA_CRDR_SDBUSMODE));
- pr_debug("SDBLKLEN=%08x, SDCURBLKCNT=%08x, SDINTMASK=%08x\n",
- readl(addrbase + VIA_CRDR_SDBLKLEN),
- readl(addrbase + VIA_CRDR_SDCURBLKCNT),
- readl(addrbase + VIA_CRDR_SDINTMASK));
- pr_debug("SDSTATUS=%08x, SDCLKSEL=%08x, SDEXTCTRL=%08x\n",
- readl(addrbase + VIA_CRDR_SDSTATUS),
- readl(addrbase + VIA_CRDR_SDCLKSEL),
- readl(addrbase + VIA_CRDR_SDEXTCTRL));
-}
-
-static void via_print_pcictrl(struct via_crdr_mmc_host *host)
-{
- void __iomem *addrbase = host->pcictrl_mmiobase;
-
- pr_debug("PCI Control Registers:\n");
- pr_debug("PCICLKGATT=%02x, PCISDCCLK=%02x, PCIDMACLK=%02x\n",
- readb(addrbase + VIA_CRDR_PCICLKGATT),
- readb(addrbase + VIA_CRDR_PCISDCCLK),
- readb(addrbase + VIA_CRDR_PCIDMACLK));
- pr_debug("PCIINTCTRL=%02x, PCIINTSTATUS=%02x\n",
- readb(addrbase + VIA_CRDR_PCIINTCTRL),
- readb(addrbase + VIA_CRDR_PCIINTSTATUS));
-}
-
-static void via_save_pcictrlreg(struct via_crdr_mmc_host *host)
-{
- struct pcictrlreg *pm_pcictrl_reg;
- void __iomem *addrbase;
-
- pm_pcictrl_reg = &(host->pm_pcictrl_reg);
- addrbase = host->pcictrl_mmiobase;
-
- pm_pcictrl_reg->pciclkgat_reg = readb(addrbase + VIA_CRDR_PCICLKGATT);
- pm_pcictrl_reg->pciclkgat_reg |=
- VIA_CRDR_PCICLKGATT_3V3 | VIA_CRDR_PCICLKGATT_PAD_PWRON;
- pm_pcictrl_reg->pcisdclk_reg = readb(addrbase + VIA_CRDR_PCISDCCLK);
- pm_pcictrl_reg->pcidmaclk_reg = readb(addrbase + VIA_CRDR_PCIDMACLK);
- pm_pcictrl_reg->pciintctrl_reg = readb(addrbase + VIA_CRDR_PCIINTCTRL);
- pm_pcictrl_reg->pciintstatus_reg =
- readb(addrbase + VIA_CRDR_PCIINTSTATUS);
- pm_pcictrl_reg->pcitmoctrl_reg = readb(addrbase + VIA_CRDR_PCITMOCTRL);
-}
-
-static void via_restore_pcictrlreg(struct via_crdr_mmc_host *host)
-{
- struct pcictrlreg *pm_pcictrl_reg;
- void __iomem *addrbase;
-
- pm_pcictrl_reg = &(host->pm_pcictrl_reg);
- addrbase = host->pcictrl_mmiobase;
-
- writeb(pm_pcictrl_reg->pciclkgat_reg, addrbase + VIA_CRDR_PCICLKGATT);
- writeb(pm_pcictrl_reg->pcisdclk_reg, addrbase + VIA_CRDR_PCISDCCLK);
- writeb(pm_pcictrl_reg->pcidmaclk_reg, addrbase + VIA_CRDR_PCIDMACLK);
- writeb(pm_pcictrl_reg->pciintctrl_reg, addrbase + VIA_CRDR_PCIINTCTRL);
- writeb(pm_pcictrl_reg->pciintstatus_reg,
- addrbase + VIA_CRDR_PCIINTSTATUS);
- writeb(pm_pcictrl_reg->pcitmoctrl_reg, addrbase + VIA_CRDR_PCITMOCTRL);
-}
-
-static void via_save_sdcreg(struct via_crdr_mmc_host *host)
-{
- struct sdhcreg *pm_sdhc_reg;
- void __iomem *addrbase;
-
- pm_sdhc_reg = &(host->pm_sdhc_reg);
- addrbase = host->sdhc_mmiobase;
-
- pm_sdhc_reg->sdcontrol_reg = readl(addrbase + VIA_CRDR_SDCTRL);
- pm_sdhc_reg->sdcmdarg_reg = readl(addrbase + VIA_CRDR_SDCARG);
- pm_sdhc_reg->sdbusmode_reg = readl(addrbase + VIA_CRDR_SDBUSMODE);
- pm_sdhc_reg->sdblklen_reg = readl(addrbase + VIA_CRDR_SDBLKLEN);
- pm_sdhc_reg->sdcurblkcnt_reg = readl(addrbase + VIA_CRDR_SDCURBLKCNT);
- pm_sdhc_reg->sdintmask_reg = readl(addrbase + VIA_CRDR_SDINTMASK);
- pm_sdhc_reg->sdstatus_reg = readl(addrbase + VIA_CRDR_SDSTATUS);
- pm_sdhc_reg->sdrsptmo_reg = readl(addrbase + VIA_CRDR_SDRSPTMO);
- pm_sdhc_reg->sdclksel_reg = readl(addrbase + VIA_CRDR_SDCLKSEL);
- pm_sdhc_reg->sdextctrl_reg = readl(addrbase + VIA_CRDR_SDEXTCTRL);
-}
-
-static void via_restore_sdcreg(struct via_crdr_mmc_host *host)
-{
- struct sdhcreg *pm_sdhc_reg;
- void __iomem *addrbase;
-
- pm_sdhc_reg = &(host->pm_sdhc_reg);
- addrbase = host->sdhc_mmiobase;
-
- writel(pm_sdhc_reg->sdcontrol_reg, addrbase + VIA_CRDR_SDCTRL);
- writel(pm_sdhc_reg->sdcmdarg_reg, addrbase + VIA_CRDR_SDCARG);
- writel(pm_sdhc_reg->sdbusmode_reg, addrbase + VIA_CRDR_SDBUSMODE);
- writel(pm_sdhc_reg->sdblklen_reg, addrbase + VIA_CRDR_SDBLKLEN);
- writel(pm_sdhc_reg->sdcurblkcnt_reg, addrbase + VIA_CRDR_SDCURBLKCNT);
- writel(pm_sdhc_reg->sdintmask_reg, addrbase + VIA_CRDR_SDINTMASK);
- writel(pm_sdhc_reg->sdstatus_reg, addrbase + VIA_CRDR_SDSTATUS);
- writel(pm_sdhc_reg->sdrsptmo_reg, addrbase + VIA_CRDR_SDRSPTMO);
- writel(pm_sdhc_reg->sdclksel_reg, addrbase + VIA_CRDR_SDCLKSEL);
- writel(pm_sdhc_reg->sdextctrl_reg, addrbase + VIA_CRDR_SDEXTCTRL);
-}
-
-static void via_pwron_sleep(struct via_crdr_mmc_host *sdhost)
-{
- if (sdhost->quirks & VIA_CRDR_QUIRK_300MS_PWRDELAY)
- msleep(300);
- else
- msleep(3);
-}
-
-static void via_set_ddma(struct via_crdr_mmc_host *host,
- dma_addr_t dmaaddr, u32 count, int dir, int enirq)
-{
- void __iomem *addrbase;
- u32 ctrl_data = 0;
-
- if (enirq)
- ctrl_data |= VIA_CRDR_DMACTRL_ENIRQ;
-
- if (dir)
- ctrl_data |= VIA_CRDR_DMACTRL_DIR;
-
- addrbase = host->ddma_mmiobase;
-
- writel(dmaaddr, addrbase + VIA_CRDR_DMABASEADD);
- writel(count, addrbase + VIA_CRDR_DMACOUNTER);
- writel(ctrl_data, addrbase + VIA_CRDR_DMACTRL);
- writel(0x01, addrbase + VIA_CRDR_DMASTART);
-
- /* It seems that our DMA can not work normally with 375kHz clock */
- /* FIXME: don't brute-force 8MHz but use PIO at 375kHz !! */
- addrbase = host->pcictrl_mmiobase;
- if (readb(addrbase + VIA_CRDR_PCISDCCLK) == PCI_CLK_375K) {
- dev_info(host->mmc->parent, "forcing card speed to 8MHz\n");
- writeb(PCI_CLK_8M, addrbase + VIA_CRDR_PCISDCCLK);
- }
-}
-
-static void via_sdc_preparedata(struct via_crdr_mmc_host *host,
- struct mmc_data *data)
-{
- void __iomem *addrbase;
- u32 blk_reg;
- int count;
-
- WARN_ON(host->data);
-
- /* Sanity checks */
- BUG_ON(data->blksz > host->mmc->max_blk_size);
- BUG_ON(data->blocks > host->mmc->max_blk_count);
-
- host->data = data;
-
- count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- ((data->flags & MMC_DATA_READ) ?
- PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE));
- BUG_ON(count != 1);
-
- via_set_ddma(host, sg_dma_address(data->sg), sg_dma_len(data->sg),
- (data->flags & MMC_DATA_WRITE) ? 1 : 0, 1);
-
- addrbase = host->sdhc_mmiobase;
-
- blk_reg = data->blksz - 1;
- blk_reg |= VIA_CRDR_SDBLKLEN_GPIDET | VIA_CRDR_SDBLKLEN_INTEN;
- blk_reg |= (data->blocks) << 16;
-
- writel(blk_reg, addrbase + VIA_CRDR_SDBLKLEN);
-}
-
-static void via_sdc_get_response(struct via_crdr_mmc_host *host,
- struct mmc_command *cmd)
-{
- void __iomem *addrbase = host->sdhc_mmiobase;
- u32 dwdata0 = readl(addrbase + VIA_CRDR_SDRESP0);
- u32 dwdata1 = readl(addrbase + VIA_CRDR_SDRESP1);
- u32 dwdata2 = readl(addrbase + VIA_CRDR_SDRESP2);
- u32 dwdata3 = readl(addrbase + VIA_CRDR_SDRESP3);
-
- if (cmd->flags & MMC_RSP_136) {
- cmd->resp[0] = ((u8) (dwdata1)) |
- (((u8) (dwdata0 >> 24)) << 8) |
- (((u8) (dwdata0 >> 16)) << 16) |
- (((u8) (dwdata0 >> 8)) << 24);
-
- cmd->resp[1] = ((u8) (dwdata2)) |
- (((u8) (dwdata1 >> 24)) << 8) |
- (((u8) (dwdata1 >> 16)) << 16) |
- (((u8) (dwdata1 >> 8)) << 24);
-
- cmd->resp[2] = ((u8) (dwdata3)) |
- (((u8) (dwdata2 >> 24)) << 8) |
- (((u8) (dwdata2 >> 16)) << 16) |
- (((u8) (dwdata2 >> 8)) << 24);
-
- cmd->resp[3] = 0xff |
- ((((u8) (dwdata3 >> 24))) << 8) |
- (((u8) (dwdata3 >> 16)) << 16) |
- (((u8) (dwdata3 >> 8)) << 24);
- } else {
- dwdata0 >>= 8;
- cmd->resp[0] = ((dwdata0 & 0xff) << 24) |
- (((dwdata0 >> 8) & 0xff) << 16) |
- (((dwdata0 >> 16) & 0xff) << 8) | (dwdata1 & 0xff);
-
- dwdata1 >>= 8;
- cmd->resp[1] = ((dwdata1 & 0xff) << 24) |
- (((dwdata1 >> 8) & 0xff) << 16) |
- (((dwdata1 >> 16) & 0xff) << 8);
- }
-}
-
-static void via_sdc_send_command(struct via_crdr_mmc_host *host,
- struct mmc_command *cmd)
-{
- void __iomem *addrbase;
- struct mmc_data *data;
- u32 cmdctrl = 0;
-
- WARN_ON(host->cmd);
-
- data = cmd->data;
- mod_timer(&host->timer, jiffies + HZ);
- host->cmd = cmd;
-
- /*Command index*/
- cmdctrl = cmd->opcode << 8;
-
- /*Response type*/
- switch (mmc_resp_type(cmd)) {
- case MMC_RSP_NONE:
- cmdctrl |= VIA_CRDR_SDCTRL_RSP_NONE;
- break;
- case MMC_RSP_R1:
- cmdctrl |= VIA_CRDR_SDCTRL_RSP_R1;
- break;
- case MMC_RSP_R1B:
- cmdctrl |= VIA_CRDR_SDCTRL_RSP_R1B;
- break;
- case MMC_RSP_R2:
- cmdctrl |= VIA_CRDR_SDCTRL_RSP_R2;
- break;
- case MMC_RSP_R3:
- cmdctrl |= VIA_CRDR_SDCTRL_RSP_R3;
- break;
- default:
- pr_err("%s: cmd->flag is not valid\n", mmc_hostname(host->mmc));
- break;
- }
-
- if (!(cmd->data))
- goto nodata;
-
- via_sdc_preparedata(host, data);
-
- /*Command control*/
- if (data->blocks > 1) {
- if (data->flags & MMC_DATA_WRITE) {
- cmdctrl |= VIA_CRDR_SDCTRL_WRITE;
- cmdctrl |= VIA_CRDR_SDCTRL_MULTI_WR;
- } else {
- cmdctrl |= VIA_CRDR_SDCTRL_MULTI_RD;
- }
- } else {
- if (data->flags & MMC_DATA_WRITE) {
- cmdctrl |= VIA_CRDR_SDCTRL_WRITE;
- cmdctrl |= VIA_CRDR_SDCTRL_SINGLE_WR;
- } else {
- cmdctrl |= VIA_CRDR_SDCTRL_SINGLE_RD;
- }
- }
-
-nodata:
- if (cmd == host->mrq->stop)
- cmdctrl |= VIA_CRDR_SDCTRL_STOP;
-
- cmdctrl |= VIA_CRDR_SDCTRL_START;
-
- addrbase = host->sdhc_mmiobase;
- writel(cmd->arg, addrbase + VIA_CRDR_SDCARG);
- writel(cmdctrl, addrbase + VIA_CRDR_SDCTRL);
-}
-
-static void via_sdc_finish_data(struct via_crdr_mmc_host *host)
-{
- struct mmc_data *data;
-
- BUG_ON(!host->data);
-
- data = host->data;
- host->data = NULL;
-
- if (data->error)
- data->bytes_xfered = 0;
- else
- data->bytes_xfered = data->blocks * data->blksz;
-
- dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
- ((data->flags & MMC_DATA_READ) ?
- PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE));
-
- if (data->stop)
- via_sdc_send_command(host, data->stop);
- else
- tasklet_schedule(&host->finish_tasklet);
-}
-
-static void via_sdc_finish_command(struct via_crdr_mmc_host *host)
-{
- via_sdc_get_response(host, host->cmd);
-
- host->cmd->error = 0;
-
- if (!host->cmd->data)
- tasklet_schedule(&host->finish_tasklet);
-
- host->cmd = NULL;
-}
-
-static void via_sdc_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- void __iomem *addrbase;
- struct via_crdr_mmc_host *host;
- unsigned long flags;
- u16 status;
-
- host = mmc_priv(mmc);
-
- spin_lock_irqsave(&host->lock, flags);
-
- addrbase = host->pcictrl_mmiobase;
- writeb(VIA_CRDR_PCIDMACLK_SDC, addrbase + VIA_CRDR_PCIDMACLK);
-
- status = readw(host->sdhc_mmiobase + VIA_CRDR_SDSTATUS);
- status &= VIA_CRDR_SDSTS_W1C_MASK;
- writew(status, host->sdhc_mmiobase + VIA_CRDR_SDSTATUS);
-
- WARN_ON(host->mrq != NULL);
- host->mrq = mrq;
-
- status = readw(host->sdhc_mmiobase + VIA_CRDR_SDSTATUS);
- if (!(status & VIA_CRDR_SDSTS_SLOTG) || host->reject) {
- host->mrq->cmd->error = -ENOMEDIUM;
- tasklet_schedule(&host->finish_tasklet);
- } else {
- via_sdc_send_command(host, mrq->cmd);
- }
-
- mmiowb();
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void via_sdc_set_power(struct via_crdr_mmc_host *host,
- unsigned short power, unsigned int on)
-{
- unsigned long flags;
- u8 gatt;
-
- spin_lock_irqsave(&host->lock, flags);
-
- host->power = (1 << power);
-
- gatt = readb(host->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT);
- if (host->power == MMC_VDD_165_195)
- gatt &= ~VIA_CRDR_PCICLKGATT_3V3;
- else
- gatt |= VIA_CRDR_PCICLKGATT_3V3;
- if (on)
- gatt |= VIA_CRDR_PCICLKGATT_PAD_PWRON;
- else
- gatt &= ~VIA_CRDR_PCICLKGATT_PAD_PWRON;
- writeb(gatt, host->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT);
-
- mmiowb();
- spin_unlock_irqrestore(&host->lock, flags);
-
- via_pwron_sleep(host);
-}
-
-static void via_sdc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct via_crdr_mmc_host *host;
- unsigned long flags;
- void __iomem *addrbase;
- u32 org_data, sdextctrl;
- u8 clock;
-
- host = mmc_priv(mmc);
-
- spin_lock_irqsave(&host->lock, flags);
-
- addrbase = host->sdhc_mmiobase;
- org_data = readl(addrbase + VIA_CRDR_SDBUSMODE);
- sdextctrl = readl(addrbase + VIA_CRDR_SDEXTCTRL);
-
- if (ios->bus_width == MMC_BUS_WIDTH_1)
- org_data &= ~VIA_CRDR_SDMODE_4BIT;
- else
- org_data |= VIA_CRDR_SDMODE_4BIT;
-
- if (ios->power_mode == MMC_POWER_OFF)
- org_data &= ~VIA_CRDR_SDMODE_CLK_ON;
- else
- org_data |= VIA_CRDR_SDMODE_CLK_ON;
-
- if (ios->timing == MMC_TIMING_SD_HS)
- sdextctrl |= VIA_CRDR_SDEXTCTRL_HISPD;
- else
- sdextctrl &= ~VIA_CRDR_SDEXTCTRL_HISPD;
-
- writel(org_data, addrbase + VIA_CRDR_SDBUSMODE);
- writel(sdextctrl, addrbase + VIA_CRDR_SDEXTCTRL);
-
- if (ios->clock >= 48000000)
- clock = PCI_CLK_48M;
- else if (ios->clock >= 33000000)
- clock = PCI_CLK_33M;
- else if (ios->clock >= 24000000)
- clock = PCI_CLK_24M;
- else if (ios->clock >= 16000000)
- clock = PCI_CLK_16M;
- else if (ios->clock >= 12000000)
- clock = PCI_CLK_12M;
- else if (ios->clock >= 8000000)
- clock = PCI_CLK_8M;
- else
- clock = PCI_CLK_375K;
-
- addrbase = host->pcictrl_mmiobase;
- if (readb(addrbase + VIA_CRDR_PCISDCCLK) != clock)
- writeb(clock, addrbase + VIA_CRDR_PCISDCCLK);
-
- mmiowb();
- spin_unlock_irqrestore(&host->lock, flags);
-
- if (ios->power_mode != MMC_POWER_OFF)
- via_sdc_set_power(host, ios->vdd, 1);
- else
- via_sdc_set_power(host, ios->vdd, 0);
-}
-
-static int via_sdc_get_ro(struct mmc_host *mmc)
-{
- struct via_crdr_mmc_host *host;
- unsigned long flags;
- u16 status;
-
- host = mmc_priv(mmc);
-
- spin_lock_irqsave(&host->lock, flags);
-
- status = readw(host->sdhc_mmiobase + VIA_CRDR_SDSTATUS);
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- return !(status & VIA_CRDR_SDSTS_WP);
-}
-
-static const struct mmc_host_ops via_sdc_ops = {
- .request = via_sdc_request,
- .set_ios = via_sdc_set_ios,
- .get_ro = via_sdc_get_ro,
-};
-
-static void via_reset_pcictrl(struct via_crdr_mmc_host *host)
-{
- unsigned long flags;
- u8 gatt;
-
- spin_lock_irqsave(&host->lock, flags);
-
- via_save_pcictrlreg(host);
- via_save_sdcreg(host);
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- gatt = VIA_CRDR_PCICLKGATT_PAD_PWRON;
- if (host->power == MMC_VDD_165_195)
- gatt &= VIA_CRDR_PCICLKGATT_3V3;
- else
- gatt |= VIA_CRDR_PCICLKGATT_3V3;
- writeb(gatt, host->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT);
- via_pwron_sleep(host);
- gatt |= VIA_CRDR_PCICLKGATT_SFTRST;
- writeb(gatt, host->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT);
- msleep(3);
-
- spin_lock_irqsave(&host->lock, flags);
-
- via_restore_pcictrlreg(host);
- via_restore_sdcreg(host);
-
- mmiowb();
- spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void via_sdc_cmd_isr(struct via_crdr_mmc_host *host, u16 intmask)
-{
- BUG_ON(intmask == 0);
-
- if (!host->cmd) {
- pr_err("%s: Got command interrupt 0x%x even "
- "though no command operation was in progress.\n",
- mmc_hostname(host->mmc), intmask);
- return;
- }
-
- if (intmask & VIA_CRDR_SDSTS_CRTO)
- host->cmd->error = -ETIMEDOUT;
- else if (intmask & VIA_CRDR_SDSTS_SC)
- host->cmd->error = -EILSEQ;
-
- if (host->cmd->error)
- tasklet_schedule(&host->finish_tasklet);
- else if (intmask & VIA_CRDR_SDSTS_CRD)
- via_sdc_finish_command(host);
-}
-
-static void via_sdc_data_isr(struct via_crdr_mmc_host *host, u16 intmask)
-{
- BUG_ON(intmask == 0);
-
- if (intmask & VIA_CRDR_SDSTS_DT)
- host->data->error = -ETIMEDOUT;
- else if (intmask & (VIA_CRDR_SDSTS_RC | VIA_CRDR_SDSTS_WC))
- host->data->error = -EILSEQ;
-
- via_sdc_finish_data(host);
-}
-
-static irqreturn_t via_sdc_isr(int irq, void *dev_id)
-{
- struct via_crdr_mmc_host *sdhost = dev_id;
- void __iomem *addrbase;
- u8 pci_status;
- u16 sd_status;
- irqreturn_t result;
-
- if (!sdhost)
- return IRQ_NONE;
-
- spin_lock(&sdhost->lock);
-
- addrbase = sdhost->pcictrl_mmiobase;
- pci_status = readb(addrbase + VIA_CRDR_PCIINTSTATUS);
- if (!(pci_status & VIA_CRDR_PCIINTSTATUS_SDC)) {
- result = IRQ_NONE;
- goto out;
- }
-
- addrbase = sdhost->sdhc_mmiobase;
- sd_status = readw(addrbase + VIA_CRDR_SDSTATUS);
- sd_status &= VIA_CRDR_SDSTS_INT_MASK;
- sd_status &= ~VIA_CRDR_SDSTS_IGN_MASK;
- if (!sd_status) {
- result = IRQ_NONE;
- goto out;
- }
-
- if (sd_status & VIA_CRDR_SDSTS_CIR) {
- writew(sd_status & VIA_CRDR_SDSTS_CIR,
- addrbase + VIA_CRDR_SDSTATUS);
-
- schedule_work(&sdhost->carddet_work);
- }
-
- sd_status &= ~VIA_CRDR_SDSTS_CIR;
- if (sd_status & VIA_CRDR_SDSTS_CMD_MASK) {
- writew(sd_status & VIA_CRDR_SDSTS_CMD_MASK,
- addrbase + VIA_CRDR_SDSTATUS);
- via_sdc_cmd_isr(sdhost, sd_status & VIA_CRDR_SDSTS_CMD_MASK);
- }
- if (sd_status & VIA_CRDR_SDSTS_DATA_MASK) {
- writew(sd_status & VIA_CRDR_SDSTS_DATA_MASK,
- addrbase + VIA_CRDR_SDSTATUS);
- via_sdc_data_isr(sdhost, sd_status & VIA_CRDR_SDSTS_DATA_MASK);
- }
-
- sd_status &= ~(VIA_CRDR_SDSTS_CMD_MASK | VIA_CRDR_SDSTS_DATA_MASK);
- if (sd_status) {
- pr_err("%s: Unexpected interrupt 0x%x\n",
- mmc_hostname(sdhost->mmc), sd_status);
- writew(sd_status, addrbase + VIA_CRDR_SDSTATUS);
- }
-
- result = IRQ_HANDLED;
-
- mmiowb();
-out:
- spin_unlock(&sdhost->lock);
-
- return result;
-}
-
-static void via_sdc_timeout(unsigned long ulongdata)
-{
- struct via_crdr_mmc_host *sdhost;
- unsigned long flags;
-
- sdhost = (struct via_crdr_mmc_host *)ulongdata;
-
- spin_lock_irqsave(&sdhost->lock, flags);
-
- if (sdhost->mrq) {
- pr_err("%s: Timeout waiting for hardware interrupt."
- "cmd:0x%x\n", mmc_hostname(sdhost->mmc),
- sdhost->mrq->cmd->opcode);
-
- if (sdhost->data) {
- writel(VIA_CRDR_DMACTRL_SFTRST,
- sdhost->ddma_mmiobase + VIA_CRDR_DMACTRL);
- sdhost->data->error = -ETIMEDOUT;
- via_sdc_finish_data(sdhost);
- } else {
- if (sdhost->cmd)
- sdhost->cmd->error = -ETIMEDOUT;
- else
- sdhost->mrq->cmd->error = -ETIMEDOUT;
- tasklet_schedule(&sdhost->finish_tasklet);
- }
- }
-
- mmiowb();
- spin_unlock_irqrestore(&sdhost->lock, flags);
-}
-
-static void via_sdc_tasklet_finish(unsigned long param)
-{
- struct via_crdr_mmc_host *host;
- unsigned long flags;
- struct mmc_request *mrq;
-
- host = (struct via_crdr_mmc_host *)param;
-
- spin_lock_irqsave(&host->lock, flags);
-
- del_timer(&host->timer);
- mrq = host->mrq;
- host->mrq = NULL;
- host->cmd = NULL;
- host->data = NULL;
-
- spin_unlock_irqrestore(&host->lock, flags);
-
- mmc_request_done(host->mmc, mrq);
-}
-
-static void via_sdc_card_detect(struct work_struct *work)
-{
- struct via_crdr_mmc_host *host;
- void __iomem *addrbase;
- unsigned long flags;
- u16 status;
-
- host = container_of(work, struct via_crdr_mmc_host, carddet_work);
-
- addrbase = host->ddma_mmiobase;
- writel(VIA_CRDR_DMACTRL_SFTRST, addrbase + VIA_CRDR_DMACTRL);
-
- spin_lock_irqsave(&host->lock, flags);
-
- addrbase = host->pcictrl_mmiobase;
- writeb(VIA_CRDR_PCIDMACLK_SDC, addrbase + VIA_CRDR_PCIDMACLK);
-
- addrbase = host->sdhc_mmiobase;
- status = readw(addrbase + VIA_CRDR_SDSTATUS);
- if (!(status & VIA_CRDR_SDSTS_SLOTG)) {
- if (host->mrq) {
- pr_err("%s: Card removed during transfer!\n",
- mmc_hostname(host->mmc));
- host->mrq->cmd->error = -ENOMEDIUM;
- tasklet_schedule(&host->finish_tasklet);
- }
-
- mmiowb();
- spin_unlock_irqrestore(&host->lock, flags);
-
- via_reset_pcictrl(host);
-
- spin_lock_irqsave(&host->lock, flags);
- }
-
- mmiowb();
- spin_unlock_irqrestore(&host->lock, flags);
-
- via_print_pcictrl(host);
- via_print_sdchc(host);
-
- mmc_detect_change(host->mmc, msecs_to_jiffies(500));
-}
-
-static void via_init_mmc_host(struct via_crdr_mmc_host *host)
-{
- struct mmc_host *mmc = host->mmc;
- void __iomem *addrbase;
- u32 lenreg;
- u32 status;
-
- init_timer(&host->timer);
- host->timer.data = (unsigned long)host;
- host->timer.function = via_sdc_timeout;
-
- spin_lock_init(&host->lock);
-
- mmc->f_min = VIA_CRDR_MIN_CLOCK;
- mmc->f_max = VIA_CRDR_MAX_CLOCK;
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
- mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED;
- mmc->ops = &via_sdc_ops;
-
- /*Hardware cannot do scatter lists*/
- mmc->max_segs = 1;
-
- mmc->max_blk_size = VIA_CRDR_MAX_BLOCK_LENGTH;
- mmc->max_blk_count = VIA_CRDR_MAX_BLOCK_COUNT;
-
- mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count;
- mmc->max_req_size = mmc->max_seg_size;
-
- INIT_WORK(&host->carddet_work, via_sdc_card_detect);
-
- tasklet_init(&host->finish_tasklet, via_sdc_tasklet_finish,
- (unsigned long)host);
-
- addrbase = host->sdhc_mmiobase;
- writel(0x0, addrbase + VIA_CRDR_SDINTMASK);
- msleep(1);
-
- lenreg = VIA_CRDR_SDBLKLEN_GPIDET | VIA_CRDR_SDBLKLEN_INTEN;
- writel(lenreg, addrbase + VIA_CRDR_SDBLKLEN);
-
- status = readw(addrbase + VIA_CRDR_SDSTATUS);
- status &= VIA_CRDR_SDSTS_W1C_MASK;
- writew(status, addrbase + VIA_CRDR_SDSTATUS);
-
- status = readw(addrbase + VIA_CRDR_SDSTATUS2);
- status |= VIA_CRDR_SDSTS_CFE;
- writew(status, addrbase + VIA_CRDR_SDSTATUS2);
-
- writeb(0x0, addrbase + VIA_CRDR_SDEXTCTRL);
-
- writel(VIA_CRDR_SDACTIVE_INTMASK, addrbase + VIA_CRDR_SDINTMASK);
- msleep(1);
-}
-
-static int __devinit via_sd_probe(struct pci_dev *pcidev,
- const struct pci_device_id *id)
-{
- struct mmc_host *mmc;
- struct via_crdr_mmc_host *sdhost;
- u32 base, len;
- u8 gatt;
- int ret;
-
- pr_info(DRV_NAME
- ": VIA SDMMC controller found at %s [%04x:%04x] (rev %x)\n",
- pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device,
- (int)pcidev->revision);
-
- ret = pci_enable_device(pcidev);
- if (ret)
- return ret;
-
- ret = pci_request_regions(pcidev, DRV_NAME);
- if (ret)
- goto disable;
-
- pci_write_config_byte(pcidev, VIA_CRDR_PCI_WORK_MODE, 0);
- pci_write_config_byte(pcidev, VIA_CRDR_PCI_DBG_MODE, 0);
-
- mmc = mmc_alloc_host(sizeof(struct via_crdr_mmc_host), &pcidev->dev);
- if (!mmc) {
- ret = -ENOMEM;
- goto release;
- }
-
- sdhost = mmc_priv(mmc);
- sdhost->mmc = mmc;
- dev_set_drvdata(&pcidev->dev, sdhost);
-
- len = pci_resource_len(pcidev, 0);
- base = pci_resource_start(pcidev, 0);
- sdhost->mmiobase = ioremap_nocache(base, len);
- if (!sdhost->mmiobase) {
- ret = -ENOMEM;
- goto free_mmc_host;
- }
-
- sdhost->sdhc_mmiobase =
- sdhost->mmiobase + VIA_CRDR_SDC_OFF;
- sdhost->ddma_mmiobase =
- sdhost->mmiobase + VIA_CRDR_DDMA_OFF;
- sdhost->pcictrl_mmiobase =
- sdhost->mmiobase + VIA_CRDR_PCICTRL_OFF;
-
- sdhost->power = MMC_VDD_165_195;
-
- gatt = VIA_CRDR_PCICLKGATT_3V3 | VIA_CRDR_PCICLKGATT_PAD_PWRON;
- writeb(gatt, sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT);
- via_pwron_sleep(sdhost);
- gatt |= VIA_CRDR_PCICLKGATT_SFTRST;
- writeb(gatt, sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT);
- msleep(3);
-
- via_init_mmc_host(sdhost);
-
- ret =
- request_irq(pcidev->irq, via_sdc_isr, IRQF_SHARED, DRV_NAME,
- sdhost);
- if (ret)
- goto unmap;
-
- writeb(VIA_CRDR_PCIINTCTRL_SDCIRQEN,
- sdhost->pcictrl_mmiobase + VIA_CRDR_PCIINTCTRL);
- writeb(VIA_CRDR_PCITMOCTRL_1024MS,
- sdhost->pcictrl_mmiobase + VIA_CRDR_PCITMOCTRL);
-
- /* device-specific quirks */
- if (pcidev->subsystem_vendor == PCI_VENDOR_ID_LENOVO &&
- pcidev->subsystem_device == 0x3891)
- sdhost->quirks = VIA_CRDR_QUIRK_300MS_PWRDELAY;
-
- mmc_add_host(mmc);
-
- return 0;
-
-unmap:
- iounmap(sdhost->mmiobase);
-free_mmc_host:
- dev_set_drvdata(&pcidev->dev, NULL);
- mmc_free_host(mmc);
-release:
- pci_release_regions(pcidev);
-disable:
- pci_disable_device(pcidev);
-
- return ret;
-}
-
-static void __devexit via_sd_remove(struct pci_dev *pcidev)
-{
- struct via_crdr_mmc_host *sdhost = pci_get_drvdata(pcidev);
- unsigned long flags;
- u8 gatt;
-
- spin_lock_irqsave(&sdhost->lock, flags);
-
- /* Ensure we don't accept more commands from mmc layer */
- sdhost->reject = 1;
-
- /* Disable generating further interrupts */
- writeb(0x0, sdhost->pcictrl_mmiobase + VIA_CRDR_PCIINTCTRL);
- mmiowb();
-
- if (sdhost->mrq) {
- pr_err("%s: Controller removed during "
- "transfer\n", mmc_hostname(sdhost->mmc));
-
- /* make sure all DMA is stopped */
- writel(VIA_CRDR_DMACTRL_SFTRST,
- sdhost->ddma_mmiobase + VIA_CRDR_DMACTRL);
- mmiowb();
- sdhost->mrq->cmd->error = -ENOMEDIUM;
- if (sdhost->mrq->stop)
- sdhost->mrq->stop->error = -ENOMEDIUM;
- tasklet_schedule(&sdhost->finish_tasklet);
- }
- spin_unlock_irqrestore(&sdhost->lock, flags);
-
- mmc_remove_host(sdhost->mmc);
-
- free_irq(pcidev->irq, sdhost);
-
- del_timer_sync(&sdhost->timer);
-
- tasklet_kill(&sdhost->finish_tasklet);
-
- /* switch off power */
- gatt = readb(sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT);
- gatt &= ~VIA_CRDR_PCICLKGATT_PAD_PWRON;
- writeb(gatt, sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT);
-
- iounmap(sdhost->mmiobase);
- dev_set_drvdata(&pcidev->dev, NULL);
- mmc_free_host(sdhost->mmc);
- pci_release_regions(pcidev);
- pci_disable_device(pcidev);
-
- pr_info(DRV_NAME
- ": VIA SDMMC controller at %s [%04x:%04x] has been removed\n",
- pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device);
-}
-
-#ifdef CONFIG_PM
-
-static void via_init_sdc_pm(struct via_crdr_mmc_host *host)
-{
- struct sdhcreg *pm_sdhcreg;
- void __iomem *addrbase;
- u32 lenreg;
- u16 status;
-
- pm_sdhcreg = &(host->pm_sdhc_reg);
- addrbase = host->sdhc_mmiobase;
-
- writel(0x0, addrbase + VIA_CRDR_SDINTMASK);
-
- lenreg = VIA_CRDR_SDBLKLEN_GPIDET | VIA_CRDR_SDBLKLEN_INTEN;
- writel(lenreg, addrbase + VIA_CRDR_SDBLKLEN);
-
- status = readw(addrbase + VIA_CRDR_SDSTATUS);
- status &= VIA_CRDR_SDSTS_W1C_MASK;
- writew(status, addrbase + VIA_CRDR_SDSTATUS);
-
- status = readw(addrbase + VIA_CRDR_SDSTATUS2);
- status |= VIA_CRDR_SDSTS_CFE;
- writew(status, addrbase + VIA_CRDR_SDSTATUS2);
-
- writel(pm_sdhcreg->sdcontrol_reg, addrbase + VIA_CRDR_SDCTRL);
- writel(pm_sdhcreg->sdcmdarg_reg, addrbase + VIA_CRDR_SDCARG);
- writel(pm_sdhcreg->sdintmask_reg, addrbase + VIA_CRDR_SDINTMASK);
- writel(pm_sdhcreg->sdrsptmo_reg, addrbase + VIA_CRDR_SDRSPTMO);
- writel(pm_sdhcreg->sdclksel_reg, addrbase + VIA_CRDR_SDCLKSEL);
- writel(pm_sdhcreg->sdextctrl_reg, addrbase + VIA_CRDR_SDEXTCTRL);
-
- via_print_pcictrl(host);
- via_print_sdchc(host);
-}
-
-static int via_sd_suspend(struct pci_dev *pcidev, pm_message_t state)
-{
- struct via_crdr_mmc_host *host;
- int ret = 0;
-
- host = pci_get_drvdata(pcidev);
-
- via_save_pcictrlreg(host);
- via_save_sdcreg(host);
-
- ret = mmc_suspend_host(host->mmc);
-
- pci_save_state(pcidev);
- pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0);
- pci_disable_device(pcidev);
- pci_set_power_state(pcidev, pci_choose_state(pcidev, state));
-
- return ret;
-}
-
-static int via_sd_resume(struct pci_dev *pcidev)
-{
- struct via_crdr_mmc_host *sdhost;
- int ret = 0;
- u8 gatt;
-
- sdhost = pci_get_drvdata(pcidev);
-
- gatt = VIA_CRDR_PCICLKGATT_PAD_PWRON;
- if (sdhost->power == MMC_VDD_165_195)
- gatt &= ~VIA_CRDR_PCICLKGATT_3V3;
- else
- gatt |= VIA_CRDR_PCICLKGATT_3V3;
- writeb(gatt, sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT);
- via_pwron_sleep(sdhost);
- gatt |= VIA_CRDR_PCICLKGATT_SFTRST;
- writeb(gatt, sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT);
- msleep(3);
-
- msleep(100);
-
- pci_set_power_state(pcidev, PCI_D0);
- pci_restore_state(pcidev);
- ret = pci_enable_device(pcidev);
- if (ret)
- return ret;
-
- via_restore_pcictrlreg(sdhost);
- via_init_sdc_pm(sdhost);
-
- ret = mmc_resume_host(sdhost->mmc);
-
- return ret;
-}
-
-#else /* CONFIG_PM */
-
-#define via_sd_suspend NULL
-#define via_sd_resume NULL
-
-#endif /* CONFIG_PM */
-
-static struct pci_driver via_sd_driver = {
- .name = DRV_NAME,
- .id_table = via_ids,
- .probe = via_sd_probe,
- .remove = __devexit_p(via_sd_remove),
- .suspend = via_sd_suspend,
- .resume = via_sd_resume,
-};
-
-static int __init via_sd_drv_init(void)
-{
- pr_info(DRV_NAME ": VIA SD/MMC Card Reader driver "
- "(C) 2008 VIA Technologies, Inc.\n");
-
- return pci_register_driver(&via_sd_driver);
-}
-
-static void __exit via_sd_drv_exit(void)
-{
- pci_unregister_driver(&via_sd_driver);
-}
-
-module_init(via_sd_drv_init);
-module_exit(via_sd_drv_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("VIA Technologies Inc.");
-MODULE_DESCRIPTION("VIA SD/MMC Card Interface driver");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/vub300.c b/ANDROID_3.4.5/drivers/mmc/host/vub300.c
deleted file mode 100644
index 3135a1a5..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/vub300.c
+++ /dev/null
@@ -1,2503 +0,0 @@
-/*
- * Remote VUB300 SDIO/SDmem Host Controller Driver
- *
- * Copyright (C) 2010 Elan Digital Systems Limited
- *
- * based on USB Skeleton driver - 2.2
- *
- * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, version 2
- *
- * VUB300: is a USB 2.0 client device with a single SDIO/SDmem/MMC slot
- * Any SDIO/SDmem/MMC device plugged into the VUB300 will appear,
- * by virtue of this driver, to have been plugged into a local
- * SDIO host controller, similar to, say, a PCI Ricoh controller
- * This is because this kernel device driver is both a USB 2.0
- * client device driver AND an MMC host controller driver. Thus
- * if there is an existing driver for the inserted SDIO/SDmem/MMC
- * device then that driver will be used by the kernel to manage
- * the device in exactly the same fashion as if it had been
- * directly plugged into, say, a local pci bus Ricoh controller
- *
- * RANT: this driver was written using a display 128x48 - converting it
- * to a line width of 80 makes it very difficult to support. In
- * particular functions have been broken down into sub functions
- * and the original meaningful names have been shortened into
- * cryptic ones.
- * The problem is that executing a fragment of code subject to
- * two conditions means an indentation of 24, thus leaving only
- * 56 characters for a C statement. And that is quite ridiculous!
- *
- * Data types: data passed to/from the VUB300 is fixed to a number of
- * bits and driver data fields reflect that limit by using
- * u8, u16, u32
- */
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/kref.h>
-#include <linux/uaccess.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/mmc/sdio_ids.h>
-#include <linux/workqueue.h>
-#include <linux/ctype.h>
-#include <linux/firmware.h>
-#include <linux/scatterlist.h>
-
-struct host_controller_info {
- u8 info_size;
- u16 firmware_version;
- u8 number_of_ports;
-} __packed;
-
-#define FIRMWARE_BLOCK_BOUNDARY 1024
-struct sd_command_header {
- u8 header_size;
- u8 header_type;
- u8 port_number;
- u8 command_type; /* Bit7 - Rd/Wr */
- u8 command_index;
- u8 transfer_size[4]; /* ReadSize + ReadSize */
- u8 response_type;
- u8 arguments[4];
- u8 block_count[2];
- u8 block_size[2];
- u8 block_boundary[2];
- u8 reserved[44]; /* to pad out to 64 bytes */
-} __packed;
-
-struct sd_irqpoll_header {
- u8 header_size;
- u8 header_type;
- u8 port_number;
- u8 command_type; /* Bit7 - Rd/Wr */
- u8 padding[16]; /* don't ask why !! */
- u8 poll_timeout_msb;
- u8 poll_timeout_lsb;
- u8 reserved[42]; /* to pad out to 64 bytes */
-} __packed;
-
-struct sd_common_header {
- u8 header_size;
- u8 header_type;
- u8 port_number;
-} __packed;
-
-struct sd_response_header {
- u8 header_size;
- u8 header_type;
- u8 port_number;
- u8 command_type;
- u8 command_index;
- u8 command_response[0];
-} __packed;
-
-struct sd_status_header {
- u8 header_size;
- u8 header_type;
- u8 port_number;
- u16 port_flags;
- u32 sdio_clock;
- u16 host_header_size;
- u16 func_header_size;
- u16 ctrl_header_size;
-} __packed;
-
-struct sd_error_header {
- u8 header_size;
- u8 header_type;
- u8 port_number;
- u8 error_code;
-} __packed;
-
-struct sd_interrupt_header {
- u8 header_size;
- u8 header_type;
- u8 port_number;
-} __packed;
-
-struct offload_registers_access {
- u8 command_byte[4];
- u8 Respond_Byte[4];
-} __packed;
-
-#define INTERRUPT_REGISTER_ACCESSES 15
-struct sd_offloaded_interrupt {
- u8 header_size;
- u8 header_type;
- u8 port_number;
- struct offload_registers_access reg[INTERRUPT_REGISTER_ACCESSES];
-} __packed;
-
-struct sd_register_header {
- u8 header_size;
- u8 header_type;
- u8 port_number;
- u8 command_type;
- u8 command_index;
- u8 command_response[6];
-} __packed;
-
-#define PIGGYBACK_REGISTER_ACCESSES 14
-struct sd_offloaded_piggyback {
- struct sd_register_header sdio;
- struct offload_registers_access reg[PIGGYBACK_REGISTER_ACCESSES];
-} __packed;
-
-union sd_response {
- struct sd_common_header common;
- struct sd_status_header status;
- struct sd_error_header error;
- struct sd_interrupt_header interrupt;
- struct sd_response_header response;
- struct sd_offloaded_interrupt irq;
- struct sd_offloaded_piggyback pig;
-} __packed;
-
-union sd_command {
- struct sd_command_header head;
- struct sd_irqpoll_header poll;
-} __packed;
-
-enum SD_RESPONSE_TYPE {
- SDRT_UNSPECIFIED = 0,
- SDRT_NONE,
- SDRT_1,
- SDRT_1B,
- SDRT_2,
- SDRT_3,
- SDRT_4,
- SDRT_5,
- SDRT_5B,
- SDRT_6,
- SDRT_7,
-};
-
-#define RESPONSE_INTERRUPT 0x01
-#define RESPONSE_ERROR 0x02
-#define RESPONSE_STATUS 0x03
-#define RESPONSE_IRQ_DISABLED 0x05
-#define RESPONSE_IRQ_ENABLED 0x06
-#define RESPONSE_PIGGYBACKED 0x07
-#define RESPONSE_NO_INTERRUPT 0x08
-#define RESPONSE_PIG_DISABLED 0x09
-#define RESPONSE_PIG_ENABLED 0x0A
-#define SD_ERROR_1BIT_TIMEOUT 0x01
-#define SD_ERROR_4BIT_TIMEOUT 0x02
-#define SD_ERROR_1BIT_CRC_WRONG 0x03
-#define SD_ERROR_4BIT_CRC_WRONG 0x04
-#define SD_ERROR_1BIT_CRC_ERROR 0x05
-#define SD_ERROR_4BIT_CRC_ERROR 0x06
-#define SD_ERROR_NO_CMD_ENDBIT 0x07
-#define SD_ERROR_NO_1BIT_DATEND 0x08
-#define SD_ERROR_NO_4BIT_DATEND 0x09
-#define SD_ERROR_1BIT_UNEXPECTED_TIMEOUT 0x0A
-#define SD_ERROR_4BIT_UNEXPECTED_TIMEOUT 0x0B
-#define SD_ERROR_ILLEGAL_COMMAND 0x0C
-#define SD_ERROR_NO_DEVICE 0x0D
-#define SD_ERROR_TRANSFER_LENGTH 0x0E
-#define SD_ERROR_1BIT_DATA_TIMEOUT 0x0F
-#define SD_ERROR_4BIT_DATA_TIMEOUT 0x10
-#define SD_ERROR_ILLEGAL_STATE 0x11
-#define SD_ERROR_UNKNOWN_ERROR 0x12
-#define SD_ERROR_RESERVED_ERROR 0x13
-#define SD_ERROR_INVALID_FUNCTION 0x14
-#define SD_ERROR_OUT_OF_RANGE 0x15
-#define SD_ERROR_STAT_CMD 0x16
-#define SD_ERROR_STAT_DATA 0x17
-#define SD_ERROR_STAT_CMD_TIMEOUT 0x18
-#define SD_ERROR_SDCRDY_STUCK 0x19
-#define SD_ERROR_UNHANDLED 0x1A
-#define SD_ERROR_OVERRUN 0x1B
-#define SD_ERROR_PIO_TIMEOUT 0x1C
-
-#define FUN(c) (0x000007 & (c->arg>>28))
-#define REG(c) (0x01FFFF & (c->arg>>9))
-
-static bool limit_speed_to_24_MHz;
-module_param(limit_speed_to_24_MHz, bool, 0644);
-MODULE_PARM_DESC(limit_speed_to_24_MHz, "Limit Max SDIO Clock Speed to 24 MHz");
-
-static bool pad_input_to_usb_pkt;
-module_param(pad_input_to_usb_pkt, bool, 0644);
-MODULE_PARM_DESC(pad_input_to_usb_pkt,
- "Pad USB data input transfers to whole USB Packet");
-
-static bool disable_offload_processing;
-module_param(disable_offload_processing, bool, 0644);
-MODULE_PARM_DESC(disable_offload_processing, "Disable Offload Processing");
-
-static bool force_1_bit_data_xfers;
-module_param(force_1_bit_data_xfers, bool, 0644);
-MODULE_PARM_DESC(force_1_bit_data_xfers,
- "Force SDIO Data Transfers to 1-bit Mode");
-
-static bool force_polling_for_irqs;
-module_param(force_polling_for_irqs, bool, 0644);
-MODULE_PARM_DESC(force_polling_for_irqs, "Force Polling for SDIO interrupts");
-
-static int firmware_irqpoll_timeout = 1024;
-module_param(firmware_irqpoll_timeout, int, 0644);
-MODULE_PARM_DESC(firmware_irqpoll_timeout, "VUB300 firmware irqpoll timeout");
-
-static int force_max_req_size = 128;
-module_param(force_max_req_size, int, 0644);
-MODULE_PARM_DESC(force_max_req_size, "set max request size in kBytes");
-
-#ifdef SMSC_DEVELOPMENT_BOARD
-static int firmware_rom_wait_states = 0x04;
-#else
-static int firmware_rom_wait_states = 0x1C;
-#endif
-
-module_param(firmware_rom_wait_states, int, 0644);
-MODULE_PARM_DESC(firmware_rom_wait_states,
- "ROM wait states byte=RRRIIEEE (Reserved Internal External)");
-
-#define ELAN_VENDOR_ID 0x2201
-#define VUB300_VENDOR_ID 0x0424
-#define VUB300_PRODUCT_ID 0x012C
-static struct usb_device_id vub300_table[] = {
- {USB_DEVICE(ELAN_VENDOR_ID, VUB300_PRODUCT_ID)},
- {USB_DEVICE(VUB300_VENDOR_ID, VUB300_PRODUCT_ID)},
- {} /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, vub300_table);
-
-static struct workqueue_struct *cmndworkqueue;
-static struct workqueue_struct *pollworkqueue;
-static struct workqueue_struct *deadworkqueue;
-
-static inline int interface_to_InterfaceNumber(struct usb_interface *interface)
-{
- if (!interface)
- return -1;
- if (!interface->cur_altsetting)
- return -1;
- return interface->cur_altsetting->desc.bInterfaceNumber;
-}
-
-struct sdio_register {
- unsigned func_num:3;
- unsigned sdio_reg:17;
- unsigned activate:1;
- unsigned prepared:1;
- unsigned regvalue:8;
- unsigned response:8;
- unsigned sparebit:26;
-};
-
-struct vub300_mmc_host {
- struct usb_device *udev;
- struct usb_interface *interface;
- struct kref kref;
- struct mutex cmd_mutex;
- struct mutex irq_mutex;
- char vub_name[3 + (9 * 8) + 4 + 1]; /* max of 7 sdio fn's */
- u8 cmnd_out_ep; /* EndPoint for commands */
- u8 cmnd_res_ep; /* EndPoint for responses */
- u8 data_out_ep; /* EndPoint for out data */
- u8 data_inp_ep; /* EndPoint for inp data */
- bool card_powered;
- bool card_present;
- bool read_only;
- bool large_usb_packets;
- bool app_spec; /* ApplicationSpecific */
- bool irq_enabled; /* by the MMC CORE */
- bool irq_disabled; /* in the firmware */
- unsigned bus_width:4;
- u8 total_offload_count;
- u8 dynamic_register_count;
- u8 resp_len;
- u32 datasize;
- int errors;
- int usb_transport_fail;
- int usb_timed_out;
- int irqs_queued;
- struct sdio_register sdio_register[16];
- struct offload_interrupt_function_register {
-#define MAXREGBITS 4
-#define MAXREGS (1<<MAXREGBITS)
-#define MAXREGMASK (MAXREGS-1)
- u8 offload_count;
- u32 offload_point;
- struct offload_registers_access reg[MAXREGS];
- } fn[8];
- u16 fbs[8]; /* Function Block Size */
- struct mmc_command *cmd;
- struct mmc_request *req;
- struct mmc_data *data;
- struct mmc_host *mmc;
- struct urb *urb;
- struct urb *command_out_urb;
- struct urb *command_res_urb;
- struct completion command_complete;
- struct completion irqpoll_complete;
- union sd_command cmnd;
- union sd_response resp;
- struct timer_list sg_transfer_timer;
- struct usb_sg_request sg_request;
- struct timer_list inactivity_timer;
- struct work_struct deadwork;
- struct work_struct cmndwork;
- struct delayed_work pollwork;
- struct host_controller_info hc_info;
- struct sd_status_header system_port_status;
- u8 padded_buffer[64];
-};
-
-#define kref_to_vub300_mmc_host(d) container_of(d, struct vub300_mmc_host, kref)
-#define SET_TRANSFER_PSEUDOCODE 21
-#define SET_INTERRUPT_PSEUDOCODE 20
-#define SET_FAILURE_MODE 18
-#define SET_ROM_WAIT_STATES 16
-#define SET_IRQ_ENABLE 13
-#define SET_CLOCK_SPEED 11
-#define SET_FUNCTION_BLOCK_SIZE 9
-#define SET_SD_DATA_MODE 6
-#define SET_SD_POWER 4
-#define ENTER_DFU_MODE 3
-#define GET_HC_INF0 1
-#define GET_SYSTEM_PORT_STATUS 0
-
-static void vub300_delete(struct kref *kref)
-{ /* kref callback - softirq */
- struct vub300_mmc_host *vub300 = kref_to_vub300_mmc_host(kref);
- struct mmc_host *mmc = vub300->mmc;
- usb_free_urb(vub300->command_out_urb);
- vub300->command_out_urb = NULL;
- usb_free_urb(vub300->command_res_urb);
- vub300->command_res_urb = NULL;
- usb_put_dev(vub300->udev);
- mmc_free_host(mmc);
- /*
- * and hence also frees vub300
- * which is contained at the end of struct mmc
- */
-}
-
-static void vub300_queue_cmnd_work(struct vub300_mmc_host *vub300)
-{
- kref_get(&vub300->kref);
- if (queue_work(cmndworkqueue, &vub300->cmndwork)) {
- /*
- * then the cmndworkqueue was not previously
- * running and the above get ref is obvious
- * required and will be put when the thread
- * terminates by a specific call
- */
- } else {
- /*
- * the cmndworkqueue was already running from
- * a previous invocation and thus to keep the
- * kref counts correct we must undo the get
- */
- kref_put(&vub300->kref, vub300_delete);
- }
-}
-
-static void vub300_queue_poll_work(struct vub300_mmc_host *vub300, int delay)
-{
- kref_get(&vub300->kref);
- if (queue_delayed_work(pollworkqueue, &vub300->pollwork, delay)) {
- /*
- * then the pollworkqueue was not previously
- * running and the above get ref is obvious
- * required and will be put when the thread
- * terminates by a specific call
- */
- } else {
- /*
- * the pollworkqueue was already running from
- * a previous invocation and thus to keep the
- * kref counts correct we must undo the get
- */
- kref_put(&vub300->kref, vub300_delete);
- }
-}
-
-static void vub300_queue_dead_work(struct vub300_mmc_host *vub300)
-{
- kref_get(&vub300->kref);
- if (queue_work(deadworkqueue, &vub300->deadwork)) {
- /*
- * then the deadworkqueue was not previously
- * running and the above get ref is obvious
- * required and will be put when the thread
- * terminates by a specific call
- */
- } else {
- /*
- * the deadworkqueue was already running from
- * a previous invocation and thus to keep the
- * kref counts correct we must undo the get
- */
- kref_put(&vub300->kref, vub300_delete);
- }
-}
-
-static void irqpoll_res_completed(struct urb *urb)
-{ /* urb completion handler - hardirq */
- struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
- if (urb->status)
- vub300->usb_transport_fail = urb->status;
- complete(&vub300->irqpoll_complete);
-}
-
-static void irqpoll_out_completed(struct urb *urb)
-{ /* urb completion handler - hardirq */
- struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
- if (urb->status) {
- vub300->usb_transport_fail = urb->status;
- complete(&vub300->irqpoll_complete);
- return;
- } else {
- int ret;
- unsigned int pipe =
- usb_rcvbulkpipe(vub300->udev, vub300->cmnd_res_ep);
- usb_fill_bulk_urb(vub300->command_res_urb, vub300->udev, pipe,
- &vub300->resp, sizeof(vub300->resp),
- irqpoll_res_completed, vub300);
- vub300->command_res_urb->actual_length = 0;
- ret = usb_submit_urb(vub300->command_res_urb, GFP_ATOMIC);
- if (ret) {
- vub300->usb_transport_fail = ret;
- complete(&vub300->irqpoll_complete);
- }
- return;
- }
-}
-
-static void send_irqpoll(struct vub300_mmc_host *vub300)
-{
- /* cmd_mutex is held by vub300_pollwork_thread */
- int retval;
- int timeout = 0xFFFF & (0x0001FFFF - firmware_irqpoll_timeout);
- vub300->cmnd.poll.header_size = 22;
- vub300->cmnd.poll.header_type = 1;
- vub300->cmnd.poll.port_number = 0;
- vub300->cmnd.poll.command_type = 2;
- vub300->cmnd.poll.poll_timeout_lsb = 0xFF & (unsigned)timeout;
- vub300->cmnd.poll.poll_timeout_msb = 0xFF & (unsigned)(timeout >> 8);
- usb_fill_bulk_urb(vub300->command_out_urb, vub300->udev,
- usb_sndbulkpipe(vub300->udev, vub300->cmnd_out_ep)
- , &vub300->cmnd, sizeof(vub300->cmnd)
- , irqpoll_out_completed, vub300);
- retval = usb_submit_urb(vub300->command_out_urb, GFP_KERNEL);
- if (0 > retval) {
- vub300->usb_transport_fail = retval;
- vub300_queue_poll_work(vub300, 1);
- complete(&vub300->irqpoll_complete);
- return;
- } else {
- return;
- }
-}
-
-static void new_system_port_status(struct vub300_mmc_host *vub300)
-{
- int old_card_present = vub300->card_present;
- int new_card_present =
- (0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
- vub300->read_only =
- (0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
- if (new_card_present && !old_card_present) {
- dev_info(&vub300->udev->dev, "card just inserted\n");
- vub300->card_present = 1;
- vub300->bus_width = 0;
- if (disable_offload_processing)
- strncpy(vub300->vub_name, "EMPTY Processing Disabled",
- sizeof(vub300->vub_name));
- else
- vub300->vub_name[0] = 0;
- mmc_detect_change(vub300->mmc, 1);
- } else if (!new_card_present && old_card_present) {
- dev_info(&vub300->udev->dev, "card just ejected\n");
- vub300->card_present = 0;
- mmc_detect_change(vub300->mmc, 0);
- } else {
- /* no change */
- }
-}
-
-static void __add_offloaded_reg_to_fifo(struct vub300_mmc_host *vub300,
- struct offload_registers_access
- *register_access, u8 func)
-{
- u8 r = vub300->fn[func].offload_point + vub300->fn[func].offload_count;
- memcpy(&vub300->fn[func].reg[MAXREGMASK & r], register_access,
- sizeof(struct offload_registers_access));
- vub300->fn[func].offload_count += 1;
- vub300->total_offload_count += 1;
-}
-
-static void add_offloaded_reg(struct vub300_mmc_host *vub300,
- struct offload_registers_access *register_access)
-{
- u32 Register = ((0x03 & register_access->command_byte[0]) << 15)
- | ((0xFF & register_access->command_byte[1]) << 7)
- | ((0xFE & register_access->command_byte[2]) >> 1);
- u8 func = ((0x70 & register_access->command_byte[0]) >> 4);
- u8 regs = vub300->dynamic_register_count;
- u8 i = 0;
- while (0 < regs-- && 1 == vub300->sdio_register[i].activate) {
- if (vub300->sdio_register[i].func_num == func &&
- vub300->sdio_register[i].sdio_reg == Register) {
- if (vub300->sdio_register[i].prepared == 0)
- vub300->sdio_register[i].prepared = 1;
- vub300->sdio_register[i].response =
- register_access->Respond_Byte[2];
- vub300->sdio_register[i].regvalue =
- register_access->Respond_Byte[3];
- return;
- } else {
- i += 1;
- continue;
- }
- };
- __add_offloaded_reg_to_fifo(vub300, register_access, func);
-}
-
-static void check_vub300_port_status(struct vub300_mmc_host *vub300)
-{
- /*
- * cmd_mutex is held by vub300_pollwork_thread,
- * vub300_deadwork_thread or vub300_cmndwork_thread
- */
- int retval;
- retval =
- usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
- GET_SYSTEM_PORT_STATUS,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x0000, 0x0000, &vub300->system_port_status,
- sizeof(vub300->system_port_status), HZ);
- if (sizeof(vub300->system_port_status) == retval)
- new_system_port_status(vub300);
-}
-
-static void __vub300_irqpoll_response(struct vub300_mmc_host *vub300)
-{
- /* cmd_mutex is held by vub300_pollwork_thread */
- if (vub300->command_res_urb->actual_length == 0)
- return;
-
- switch (vub300->resp.common.header_type) {
- case RESPONSE_INTERRUPT:
- mutex_lock(&vub300->irq_mutex);
- if (vub300->irq_enabled)
- mmc_signal_sdio_irq(vub300->mmc);
- else
- vub300->irqs_queued += 1;
- vub300->irq_disabled = 1;
- mutex_unlock(&vub300->irq_mutex);
- break;
- case RESPONSE_ERROR:
- if (vub300->resp.error.error_code == SD_ERROR_NO_DEVICE)
- check_vub300_port_status(vub300);
- break;
- case RESPONSE_STATUS:
- vub300->system_port_status = vub300->resp.status;
- new_system_port_status(vub300);
- if (!vub300->card_present)
- vub300_queue_poll_work(vub300, HZ / 5);
- break;
- case RESPONSE_IRQ_DISABLED:
- {
- int offloaded_data_length = vub300->resp.common.header_size - 3;
- int register_count = offloaded_data_length >> 3;
- int ri = 0;
- while (register_count--) {
- add_offloaded_reg(vub300, &vub300->resp.irq.reg[ri]);
- ri += 1;
- }
- mutex_lock(&vub300->irq_mutex);
- if (vub300->irq_enabled)
- mmc_signal_sdio_irq(vub300->mmc);
- else
- vub300->irqs_queued += 1;
- vub300->irq_disabled = 1;
- mutex_unlock(&vub300->irq_mutex);
- break;
- }
- case RESPONSE_IRQ_ENABLED:
- {
- int offloaded_data_length = vub300->resp.common.header_size - 3;
- int register_count = offloaded_data_length >> 3;
- int ri = 0;
- while (register_count--) {
- add_offloaded_reg(vub300, &vub300->resp.irq.reg[ri]);
- ri += 1;
- }
- mutex_lock(&vub300->irq_mutex);
- if (vub300->irq_enabled)
- mmc_signal_sdio_irq(vub300->mmc);
- else if (vub300->irqs_queued)
- vub300->irqs_queued += 1;
- else
- vub300->irqs_queued += 1;
- vub300->irq_disabled = 0;
- mutex_unlock(&vub300->irq_mutex);
- break;
- }
- case RESPONSE_NO_INTERRUPT:
- vub300_queue_poll_work(vub300, 1);
- break;
- default:
- break;
- }
-}
-
-static void __do_poll(struct vub300_mmc_host *vub300)
-{
- /* cmd_mutex is held by vub300_pollwork_thread */
- long commretval;
- mod_timer(&vub300->inactivity_timer, jiffies + HZ);
- init_completion(&vub300->irqpoll_complete);
- send_irqpoll(vub300);
- commretval = wait_for_completion_timeout(&vub300->irqpoll_complete,
- msecs_to_jiffies(500));
- if (vub300->usb_transport_fail) {
- /* no need to do anything */
- } else if (commretval == 0) {
- vub300->usb_timed_out = 1;
- usb_kill_urb(vub300->command_out_urb);
- usb_kill_urb(vub300->command_res_urb);
- } else if (commretval < 0) {
- vub300_queue_poll_work(vub300, 1);
- } else { /* commretval > 0 */
- __vub300_irqpoll_response(vub300);
- }
-}
-
-/* this thread runs only when the driver
- * is trying to poll the device for an IRQ
- */
-static void vub300_pollwork_thread(struct work_struct *work)
-{ /* NOT irq */
- struct vub300_mmc_host *vub300 = container_of(work,
- struct vub300_mmc_host, pollwork.work);
- if (!vub300->interface) {
- kref_put(&vub300->kref, vub300_delete);
- return;
- }
- mutex_lock(&vub300->cmd_mutex);
- if (vub300->cmd) {
- vub300_queue_poll_work(vub300, 1);
- } else if (!vub300->card_present) {
- /* no need to do anything */
- } else { /* vub300->card_present */
- mutex_lock(&vub300->irq_mutex);
- if (!vub300->irq_enabled) {
- mutex_unlock(&vub300->irq_mutex);
- } else if (vub300->irqs_queued) {
- vub300->irqs_queued -= 1;
- mmc_signal_sdio_irq(vub300->mmc);
- mod_timer(&vub300->inactivity_timer, jiffies + HZ);
- mutex_unlock(&vub300->irq_mutex);
- } else { /* NOT vub300->irqs_queued */
- mutex_unlock(&vub300->irq_mutex);
- __do_poll(vub300);
- }
- }
- mutex_unlock(&vub300->cmd_mutex);
- kref_put(&vub300->kref, vub300_delete);
-}
-
-static void vub300_deadwork_thread(struct work_struct *work)
-{ /* NOT irq */
- struct vub300_mmc_host *vub300 =
- container_of(work, struct vub300_mmc_host, deadwork);
- if (!vub300->interface) {
- kref_put(&vub300->kref, vub300_delete);
- return;
- }
- mutex_lock(&vub300->cmd_mutex);
- if (vub300->cmd) {
- /*
- * a command got in as the inactivity
- * timer expired - so we just let the
- * processing of the command show if
- * the device is dead
- */
- } else if (vub300->card_present) {
- check_vub300_port_status(vub300);
- } else if (vub300->mmc && vub300->mmc->card &&
- mmc_card_present(vub300->mmc->card)) {
- /*
- * the MMC core must not have responded
- * to the previous indication - lets
- * hope that it eventually does so we
- * will just ignore this for now
- */
- } else {
- check_vub300_port_status(vub300);
- }
- mod_timer(&vub300->inactivity_timer, jiffies + HZ);
- mutex_unlock(&vub300->cmd_mutex);
- kref_put(&vub300->kref, vub300_delete);
-}
-
-static void vub300_inactivity_timer_expired(unsigned long data)
-{ /* softirq */
- struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)data;
- if (!vub300->interface) {
- kref_put(&vub300->kref, vub300_delete);
- } else if (vub300->cmd) {
- mod_timer(&vub300->inactivity_timer, jiffies + HZ);
- } else {
- vub300_queue_dead_work(vub300);
- mod_timer(&vub300->inactivity_timer, jiffies + HZ);
- }
-}
-
-static int vub300_response_error(u8 error_code)
-{
- switch (error_code) {
- case SD_ERROR_PIO_TIMEOUT:
- case SD_ERROR_1BIT_TIMEOUT:
- case SD_ERROR_4BIT_TIMEOUT:
- return -ETIMEDOUT;
- case SD_ERROR_STAT_DATA:
- case SD_ERROR_OVERRUN:
- case SD_ERROR_STAT_CMD:
- case SD_ERROR_STAT_CMD_TIMEOUT:
- case SD_ERROR_SDCRDY_STUCK:
- case SD_ERROR_UNHANDLED:
- case SD_ERROR_1BIT_CRC_WRONG:
- case SD_ERROR_4BIT_CRC_WRONG:
- case SD_ERROR_1BIT_CRC_ERROR:
- case SD_ERROR_4BIT_CRC_ERROR:
- case SD_ERROR_NO_CMD_ENDBIT:
- case SD_ERROR_NO_1BIT_DATEND:
- case SD_ERROR_NO_4BIT_DATEND:
- case SD_ERROR_1BIT_DATA_TIMEOUT:
- case SD_ERROR_4BIT_DATA_TIMEOUT:
- case SD_ERROR_1BIT_UNEXPECTED_TIMEOUT:
- case SD_ERROR_4BIT_UNEXPECTED_TIMEOUT:
- return -EILSEQ;
- case 33:
- return -EILSEQ;
- case SD_ERROR_ILLEGAL_COMMAND:
- return -EINVAL;
- case SD_ERROR_NO_DEVICE:
- return -ENOMEDIUM;
- default:
- return -ENODEV;
- }
-}
-
-static void command_res_completed(struct urb *urb)
-{ /* urb completion handler - hardirq */
- struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
- if (urb->status) {
- /* we have to let the initiator handle the error */
- } else if (vub300->command_res_urb->actual_length == 0) {
- /*
- * we have seen this happen once or twice and
- * we suspect a buggy USB host controller
- */
- } else if (!vub300->data) {
- /* this means that the command (typically CMD52) suceeded */
- } else if (vub300->resp.common.header_type != 0x02) {
- /*
- * this is an error response from the VUB300 chip
- * and we let the initiator handle it
- */
- } else if (vub300->urb) {
- vub300->cmd->error =
- vub300_response_error(vub300->resp.error.error_code);
- usb_unlink_urb(vub300->urb);
- } else {
- vub300->cmd->error =
- vub300_response_error(vub300->resp.error.error_code);
- usb_sg_cancel(&vub300->sg_request);
- }
- complete(&vub300->command_complete); /* got_response_in */
-}
-
-static void command_out_completed(struct urb *urb)
-{ /* urb completion handler - hardirq */
- struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
- if (urb->status) {
- complete(&vub300->command_complete);
- } else {
- int ret;
- unsigned int pipe =
- usb_rcvbulkpipe(vub300->udev, vub300->cmnd_res_ep);
- usb_fill_bulk_urb(vub300->command_res_urb, vub300->udev, pipe,
- &vub300->resp, sizeof(vub300->resp),
- command_res_completed, vub300);
- vub300->command_res_urb->actual_length = 0;
- ret = usb_submit_urb(vub300->command_res_urb, GFP_ATOMIC);
- if (ret == 0) {
- /*
- * the urb completion handler will call
- * our completion handler
- */
- } else {
- /*
- * and thus we only call it directly
- * when it will not be called
- */
- complete(&vub300->command_complete);
- }
- }
-}
-
-/*
- * the STUFF bits are masked out for the comparisons
- */
-static void snoop_block_size_and_bus_width(struct vub300_mmc_host *vub300,
- u32 cmd_arg)
-{
- if ((0xFBFFFE00 & cmd_arg) == 0x80022200)
- vub300->fbs[1] = (cmd_arg << 8) | (0x00FF & vub300->fbs[1]);
- else if ((0xFBFFFE00 & cmd_arg) == 0x80022000)
- vub300->fbs[1] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[1]);
- else if ((0xFBFFFE00 & cmd_arg) == 0x80042200)
- vub300->fbs[2] = (cmd_arg << 8) | (0x00FF & vub300->fbs[2]);
- else if ((0xFBFFFE00 & cmd_arg) == 0x80042000)
- vub300->fbs[2] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[2]);
- else if ((0xFBFFFE00 & cmd_arg) == 0x80062200)
- vub300->fbs[3] = (cmd_arg << 8) | (0x00FF & vub300->fbs[3]);
- else if ((0xFBFFFE00 & cmd_arg) == 0x80062000)
- vub300->fbs[3] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[3]);
- else if ((0xFBFFFE00 & cmd_arg) == 0x80082200)
- vub300->fbs[4] = (cmd_arg << 8) | (0x00FF & vub300->fbs[4]);
- else if ((0xFBFFFE00 & cmd_arg) == 0x80082000)
- vub300->fbs[4] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[4]);
- else if ((0xFBFFFE00 & cmd_arg) == 0x800A2200)
- vub300->fbs[5] = (cmd_arg << 8) | (0x00FF & vub300->fbs[5]);
- else if ((0xFBFFFE00 & cmd_arg) == 0x800A2000)
- vub300->fbs[5] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[5]);
- else if ((0xFBFFFE00 & cmd_arg) == 0x800C2200)
- vub300->fbs[6] = (cmd_arg << 8) | (0x00FF & vub300->fbs[6]);
- else if ((0xFBFFFE00 & cmd_arg) == 0x800C2000)
- vub300->fbs[6] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[6]);
- else if ((0xFBFFFE00 & cmd_arg) == 0x800E2200)
- vub300->fbs[7] = (cmd_arg << 8) | (0x00FF & vub300->fbs[7]);
- else if ((0xFBFFFE00 & cmd_arg) == 0x800E2000)
- vub300->fbs[7] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[7]);
- else if ((0xFBFFFE03 & cmd_arg) == 0x80000E00)
- vub300->bus_width = 1;
- else if ((0xFBFFFE03 & cmd_arg) == 0x80000E02)
- vub300->bus_width = 4;
-}
-
-static void send_command(struct vub300_mmc_host *vub300)
-{
- /* cmd_mutex is held by vub300_cmndwork_thread */
- struct mmc_command *cmd = vub300->cmd;
- struct mmc_data *data = vub300->data;
- int retval;
- int i;
- u8 response_type;
- if (vub300->app_spec) {
- switch (cmd->opcode) {
- case 6:
- response_type = SDRT_1;
- vub300->resp_len = 6;
- if (0x00000000 == (0x00000003 & cmd->arg))
- vub300->bus_width = 1;
- else if (0x00000002 == (0x00000003 & cmd->arg))
- vub300->bus_width = 4;
- else
- dev_err(&vub300->udev->dev,
- "unexpected ACMD6 bus_width=%d\n",
- 0x00000003 & cmd->arg);
- break;
- case 13:
- response_type = SDRT_1;
- vub300->resp_len = 6;
- break;
- case 22:
- response_type = SDRT_1;
- vub300->resp_len = 6;
- break;
- case 23:
- response_type = SDRT_1;
- vub300->resp_len = 6;
- break;
- case 41:
- response_type = SDRT_3;
- vub300->resp_len = 6;
- break;
- case 42:
- response_type = SDRT_1;
- vub300->resp_len = 6;
- break;
- case 51:
- response_type = SDRT_1;
- vub300->resp_len = 6;
- break;
- case 55:
- response_type = SDRT_1;
- vub300->resp_len = 6;
- break;
- default:
- vub300->resp_len = 0;
- cmd->error = -EINVAL;
- complete(&vub300->command_complete);
- return;
- }
- vub300->app_spec = 0;
- } else {
- switch (cmd->opcode) {
- case 0:
- response_type = SDRT_NONE;
- vub300->resp_len = 0;
- break;
- case 1:
- response_type = SDRT_3;
- vub300->resp_len = 6;
- break;
- case 2:
- response_type = SDRT_2;
- vub300->resp_len = 17;
- break;
- case 3:
- response_type = SDRT_6;
- vub300->resp_len = 6;
- break;
- case 4:
- response_type = SDRT_NONE;
- vub300->resp_len = 0;
- break;
- case 5:
- response_type = SDRT_4;
- vub300->resp_len = 6;
- break;
- case 6:
- response_type = SDRT_1;
- vub300->resp_len = 6;
- break;
- case 7:
- response_type = SDRT_1B;
- vub300->resp_len = 6;
- break;
- case 8:
- response_type = SDRT_7;
- vub300->resp_len = 6;
- break;
- case 9:
- response_type = SDRT_2;
- vub300->resp_len = 17;
- break;
- case 10:
- response_type = SDRT_2;
- vub300->resp_len = 17;
- break;
- case 12:
- response_type = SDRT_1B;
- vub300->resp_len = 6;
- break;
- case 13:
- response_type = SDRT_1;
- vub300->resp_len = 6;
- break;
- case 15:
- response_type = SDRT_NONE;
- vub300->resp_len = 0;
- break;
- case 16:
- for (i = 0; i < ARRAY_SIZE(vub300->fbs); i++)
- vub300->fbs[i] = 0xFFFF & cmd->arg;
- response_type = SDRT_1;
- vub300->resp_len = 6;
- break;
- case 17:
- case 18:
- case 24:
- case 25:
- case 27:
- response_type = SDRT_1;
- vub300->resp_len = 6;
- break;
- case 28:
- case 29:
- response_type = SDRT_1B;
- vub300->resp_len = 6;
- break;
- case 30:
- case 32:
- case 33:
- response_type = SDRT_1;
- vub300->resp_len = 6;
- break;
- case 38:
- response_type = SDRT_1B;
- vub300->resp_len = 6;
- break;
- case 42:
- response_type = SDRT_1;
- vub300->resp_len = 6;
- break;
- case 52:
- response_type = SDRT_5;
- vub300->resp_len = 6;
- snoop_block_size_and_bus_width(vub300, cmd->arg);
- break;
- case 53:
- response_type = SDRT_5;
- vub300->resp_len = 6;
- break;
- case 55:
- response_type = SDRT_1;
- vub300->resp_len = 6;
- vub300->app_spec = 1;
- break;
- case 56:
- response_type = SDRT_1;
- vub300->resp_len = 6;
- break;
- default:
- vub300->resp_len = 0;
- cmd->error = -EINVAL;
- complete(&vub300->command_complete);
- return;
- }
- }
- /*
- * it is a shame that we can not use "sizeof(struct sd_command_header)"
- * this is because the packet _must_ be padded to 64 bytes
- */
- vub300->cmnd.head.header_size = 20;
- vub300->cmnd.head.header_type = 0x00;
- vub300->cmnd.head.port_number = 0; /* "0" means port 1 */
- vub300->cmnd.head.command_type = 0x00; /* standard read command */
- vub300->cmnd.head.response_type = response_type;
- vub300->cmnd.head.command_index = cmd->opcode;
- vub300->cmnd.head.arguments[0] = cmd->arg >> 24;
- vub300->cmnd.head.arguments[1] = cmd->arg >> 16;
- vub300->cmnd.head.arguments[2] = cmd->arg >> 8;
- vub300->cmnd.head.arguments[3] = cmd->arg >> 0;
- if (cmd->opcode == 52) {
- int fn = 0x7 & (cmd->arg >> 28);
- vub300->cmnd.head.block_count[0] = 0;
- vub300->cmnd.head.block_count[1] = 0;
- vub300->cmnd.head.block_size[0] = (vub300->fbs[fn] >> 8) & 0xFF;
- vub300->cmnd.head.block_size[1] = (vub300->fbs[fn] >> 0) & 0xFF;
- vub300->cmnd.head.command_type = 0x00;
- vub300->cmnd.head.transfer_size[0] = 0;
- vub300->cmnd.head.transfer_size[1] = 0;
- vub300->cmnd.head.transfer_size[2] = 0;
- vub300->cmnd.head.transfer_size[3] = 0;
- } else if (!data) {
- vub300->cmnd.head.block_count[0] = 0;
- vub300->cmnd.head.block_count[1] = 0;
- vub300->cmnd.head.block_size[0] = (vub300->fbs[0] >> 8) & 0xFF;
- vub300->cmnd.head.block_size[1] = (vub300->fbs[0] >> 0) & 0xFF;
- vub300->cmnd.head.command_type = 0x00;
- vub300->cmnd.head.transfer_size[0] = 0;
- vub300->cmnd.head.transfer_size[1] = 0;
- vub300->cmnd.head.transfer_size[2] = 0;
- vub300->cmnd.head.transfer_size[3] = 0;
- } else if (cmd->opcode == 53) {
- int fn = 0x7 & (cmd->arg >> 28);
- if (0x08 & vub300->cmnd.head.arguments[0]) { /* BLOCK MODE */
- vub300->cmnd.head.block_count[0] =
- (data->blocks >> 8) & 0xFF;
- vub300->cmnd.head.block_count[1] =
- (data->blocks >> 0) & 0xFF;
- vub300->cmnd.head.block_size[0] =
- (data->blksz >> 8) & 0xFF;
- vub300->cmnd.head.block_size[1] =
- (data->blksz >> 0) & 0xFF;
- } else { /* BYTE MODE */
- vub300->cmnd.head.block_count[0] = 0;
- vub300->cmnd.head.block_count[1] = 0;
- vub300->cmnd.head.block_size[0] =
- (vub300->datasize >> 8) & 0xFF;
- vub300->cmnd.head.block_size[1] =
- (vub300->datasize >> 0) & 0xFF;
- }
- vub300->cmnd.head.command_type =
- (MMC_DATA_READ & data->flags) ? 0x00 : 0x80;
- vub300->cmnd.head.transfer_size[0] =
- (vub300->datasize >> 24) & 0xFF;
- vub300->cmnd.head.transfer_size[1] =
- (vub300->datasize >> 16) & 0xFF;
- vub300->cmnd.head.transfer_size[2] =
- (vub300->datasize >> 8) & 0xFF;
- vub300->cmnd.head.transfer_size[3] =
- (vub300->datasize >> 0) & 0xFF;
- if (vub300->datasize < vub300->fbs[fn]) {
- vub300->cmnd.head.block_count[0] = 0;
- vub300->cmnd.head.block_count[1] = 0;
- }
- } else {
- vub300->cmnd.head.block_count[0] = (data->blocks >> 8) & 0xFF;
- vub300->cmnd.head.block_count[1] = (data->blocks >> 0) & 0xFF;
- vub300->cmnd.head.block_size[0] = (data->blksz >> 8) & 0xFF;
- vub300->cmnd.head.block_size[1] = (data->blksz >> 0) & 0xFF;
- vub300->cmnd.head.command_type =
- (MMC_DATA_READ & data->flags) ? 0x00 : 0x80;
- vub300->cmnd.head.transfer_size[0] =
- (vub300->datasize >> 24) & 0xFF;
- vub300->cmnd.head.transfer_size[1] =
- (vub300->datasize >> 16) & 0xFF;
- vub300->cmnd.head.transfer_size[2] =
- (vub300->datasize >> 8) & 0xFF;
- vub300->cmnd.head.transfer_size[3] =
- (vub300->datasize >> 0) & 0xFF;
- if (vub300->datasize < vub300->fbs[0]) {
- vub300->cmnd.head.block_count[0] = 0;
- vub300->cmnd.head.block_count[1] = 0;
- }
- }
- if (vub300->cmnd.head.block_size[0] || vub300->cmnd.head.block_size[1]) {
- u16 block_size = vub300->cmnd.head.block_size[1] |
- (vub300->cmnd.head.block_size[0] << 8);
- u16 block_boundary = FIRMWARE_BLOCK_BOUNDARY -
- (FIRMWARE_BLOCK_BOUNDARY % block_size);
- vub300->cmnd.head.block_boundary[0] =
- (block_boundary >> 8) & 0xFF;
- vub300->cmnd.head.block_boundary[1] =
- (block_boundary >> 0) & 0xFF;
- } else {
- vub300->cmnd.head.block_boundary[0] = 0;
- vub300->cmnd.head.block_boundary[1] = 0;
- }
- usb_fill_bulk_urb(vub300->command_out_urb, vub300->udev,
- usb_sndbulkpipe(vub300->udev, vub300->cmnd_out_ep),
- &vub300->cmnd, sizeof(vub300->cmnd),
- command_out_completed, vub300);
- retval = usb_submit_urb(vub300->command_out_urb, GFP_KERNEL);
- if (retval < 0) {
- cmd->error = retval;
- complete(&vub300->command_complete);
- return;
- } else {
- return;
- }
-}
-
-/*
- * timer callback runs in atomic mode
- * so it cannot call usb_kill_urb()
- */
-static void vub300_sg_timed_out(unsigned long data)
-{
- struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)data;
- vub300->usb_timed_out = 1;
- usb_sg_cancel(&vub300->sg_request);
- usb_unlink_urb(vub300->command_out_urb);
- usb_unlink_urb(vub300->command_res_urb);
-}
-
-static u16 roundup_to_multiple_of_64(u16 number)
-{
- return 0xFFC0 & (0x3F + number);
-}
-
-/*
- * this is a separate function to solve the 80 column width restriction
- */
-static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
- const struct firmware *fw)
-{
- u8 register_count = 0;
- u16 ts = 0;
- u16 interrupt_size = 0;
- const u8 *data = fw->data;
- int size = fw->size;
- u8 c;
- dev_info(&vub300->udev->dev, "using %s for SDIO offload processing\n",
- vub300->vub_name);
- do {
- c = *data++;
- } while (size-- && c); /* skip comment */
- dev_info(&vub300->udev->dev, "using offload firmware %s %s\n", fw->data,
- vub300->vub_name);
- if (size < 4) {
- dev_err(&vub300->udev->dev,
- "corrupt offload pseudocode in firmware %s\n",
- vub300->vub_name);
- strncpy(vub300->vub_name, "corrupt offload pseudocode",
- sizeof(vub300->vub_name));
- return;
- }
- interrupt_size += *data++;
- size -= 1;
- interrupt_size <<= 8;
- interrupt_size += *data++;
- size -= 1;
- if (interrupt_size < size) {
- u16 xfer_length = roundup_to_multiple_of_64(interrupt_size);
- u8 *xfer_buffer = kmalloc(xfer_length, GFP_KERNEL);
- if (xfer_buffer) {
- int retval;
- memcpy(xfer_buffer, data, interrupt_size);
- memset(xfer_buffer + interrupt_size, 0,
- xfer_length - interrupt_size);
- size -= interrupt_size;
- data += interrupt_size;
- retval =
- usb_control_msg(vub300->udev,
- usb_sndctrlpipe(vub300->udev, 0),
- SET_INTERRUPT_PSEUDOCODE,
- USB_DIR_OUT | USB_TYPE_VENDOR |
- USB_RECIP_DEVICE, 0x0000, 0x0000,
- xfer_buffer, xfer_length, HZ);
- kfree(xfer_buffer);
- if (retval < 0) {
- strncpy(vub300->vub_name,
- "SDIO pseudocode download failed",
- sizeof(vub300->vub_name));
- return;
- }
- } else {
- dev_err(&vub300->udev->dev,
- "not enough memory for xfer buffer to send"
- " INTERRUPT_PSEUDOCODE for %s %s\n", fw->data,
- vub300->vub_name);
- strncpy(vub300->vub_name,
- "SDIO interrupt pseudocode download failed",
- sizeof(vub300->vub_name));
- return;
- }
- } else {
- dev_err(&vub300->udev->dev,
- "corrupt interrupt pseudocode in firmware %s %s\n",
- fw->data, vub300->vub_name);
- strncpy(vub300->vub_name, "corrupt interrupt pseudocode",
- sizeof(vub300->vub_name));
- return;
- }
- ts += *data++;
- size -= 1;
- ts <<= 8;
- ts += *data++;
- size -= 1;
- if (ts < size) {
- u16 xfer_length = roundup_to_multiple_of_64(ts);
- u8 *xfer_buffer = kmalloc(xfer_length, GFP_KERNEL);
- if (xfer_buffer) {
- int retval;
- memcpy(xfer_buffer, data, ts);
- memset(xfer_buffer + ts, 0,
- xfer_length - ts);
- size -= ts;
- data += ts;
- retval =
- usb_control_msg(vub300->udev,
- usb_sndctrlpipe(vub300->udev, 0),
- SET_TRANSFER_PSEUDOCODE,
- USB_DIR_OUT | USB_TYPE_VENDOR |
- USB_RECIP_DEVICE, 0x0000, 0x0000,
- xfer_buffer, xfer_length, HZ);
- kfree(xfer_buffer);
- if (retval < 0) {
- strncpy(vub300->vub_name,
- "SDIO pseudocode download failed",
- sizeof(vub300->vub_name));
- return;
- }
- } else {
- dev_err(&vub300->udev->dev,
- "not enough memory for xfer buffer to send"
- " TRANSFER_PSEUDOCODE for %s %s\n", fw->data,
- vub300->vub_name);
- strncpy(vub300->vub_name,
- "SDIO transfer pseudocode download failed",
- sizeof(vub300->vub_name));
- return;
- }
- } else {
- dev_err(&vub300->udev->dev,
- "corrupt transfer pseudocode in firmware %s %s\n",
- fw->data, vub300->vub_name);
- strncpy(vub300->vub_name, "corrupt transfer pseudocode",
- sizeof(vub300->vub_name));
- return;
- }
- register_count += *data++;
- size -= 1;
- if (register_count * 4 == size) {
- int I = vub300->dynamic_register_count = register_count;
- int i = 0;
- while (I--) {
- unsigned int func_num = 0;
- vub300->sdio_register[i].func_num = *data++;
- size -= 1;
- func_num += *data++;
- size -= 1;
- func_num <<= 8;
- func_num += *data++;
- size -= 1;
- func_num <<= 8;
- func_num += *data++;
- size -= 1;
- vub300->sdio_register[i].sdio_reg = func_num;
- vub300->sdio_register[i].activate = 1;
- vub300->sdio_register[i].prepared = 0;
- i += 1;
- }
- dev_info(&vub300->udev->dev,
- "initialized %d dynamic pseudocode registers\n",
- vub300->dynamic_register_count);
- return;
- } else {
- dev_err(&vub300->udev->dev,
- "corrupt dynamic registers in firmware %s\n",
- vub300->vub_name);
- strncpy(vub300->vub_name, "corrupt dynamic registers",
- sizeof(vub300->vub_name));
- return;
- }
-}
-
-/*
- * if the binary containing the EMPTY PseudoCode can not be found
- * vub300->vub_name is set anyway in order to prevent an automatic retry
- */
-static void download_offload_pseudocode(struct vub300_mmc_host *vub300)
-{
- struct mmc_card *card = vub300->mmc->card;
- int sdio_funcs = card->sdio_funcs;
- const struct firmware *fw = NULL;
- int l = snprintf(vub300->vub_name, sizeof(vub300->vub_name),
- "vub_%04X%04X", card->cis.vendor, card->cis.device);
- int n = 0;
- int retval;
- for (n = 0; n < sdio_funcs; n++) {
- struct sdio_func *sf = card->sdio_func[n];
- l += snprintf(vub300->vub_name + l,
- sizeof(vub300->vub_name) - l, "_%04X%04X",
- sf->vendor, sf->device);
- };
- snprintf(vub300->vub_name + l, sizeof(vub300->vub_name) - l, ".bin");
- dev_info(&vub300->udev->dev, "requesting offload firmware %s\n",
- vub300->vub_name);
- retval = request_firmware(&fw, vub300->vub_name, &card->dev);
- if (retval < 0) {
- strncpy(vub300->vub_name, "vub_default.bin",
- sizeof(vub300->vub_name));
- retval = request_firmware(&fw, vub300->vub_name, &card->dev);
- if (retval < 0) {
- strncpy(vub300->vub_name,
- "no SDIO offload firmware found",
- sizeof(vub300->vub_name));
- } else {
- __download_offload_pseudocode(vub300, fw);
- release_firmware(fw);
- }
- } else {
- __download_offload_pseudocode(vub300, fw);
- release_firmware(fw);
- }
-}
-
-static void vub300_usb_bulk_msg_completion(struct urb *urb)
-{ /* urb completion handler - hardirq */
- complete((struct completion *)urb->context);
-}
-
-static int vub300_usb_bulk_msg(struct vub300_mmc_host *vub300,
- unsigned int pipe, void *data, int len,
- int *actual_length, int timeout_msecs)
-{
- /* cmd_mutex is held by vub300_cmndwork_thread */
- struct usb_device *usb_dev = vub300->udev;
- struct completion done;
- int retval;
- vub300->urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!vub300->urb)
- return -ENOMEM;
- usb_fill_bulk_urb(vub300->urb, usb_dev, pipe, data, len,
- vub300_usb_bulk_msg_completion, NULL);
- init_completion(&done);
- vub300->urb->context = &done;
- vub300->urb->actual_length = 0;
- retval = usb_submit_urb(vub300->urb, GFP_KERNEL);
- if (unlikely(retval))
- goto out;
- if (!wait_for_completion_timeout
- (&done, msecs_to_jiffies(timeout_msecs))) {
- retval = -ETIMEDOUT;
- usb_kill_urb(vub300->urb);
- } else {
- retval = vub300->urb->status;
- }
-out:
- *actual_length = vub300->urb->actual_length;
- usb_free_urb(vub300->urb);
- vub300->urb = NULL;
- return retval;
-}
-
-static int __command_read_data(struct vub300_mmc_host *vub300,
- struct mmc_command *cmd, struct mmc_data *data)
-{
- /* cmd_mutex is held by vub300_cmndwork_thread */
- int linear_length = vub300->datasize;
- int padded_length = vub300->large_usb_packets ?
- ((511 + linear_length) >> 9) << 9 :
- ((63 + linear_length) >> 6) << 6;
- if ((padded_length == linear_length) || !pad_input_to_usb_pkt) {
- int result;
- unsigned pipe;
- pipe = usb_rcvbulkpipe(vub300->udev, vub300->data_inp_ep);
- result = usb_sg_init(&vub300->sg_request, vub300->udev,
- pipe, 0, data->sg,
- data->sg_len, 0, GFP_KERNEL);
- if (result < 0) {
- usb_unlink_urb(vub300->command_out_urb);
- usb_unlink_urb(vub300->command_res_urb);
- cmd->error = result;
- data->bytes_xfered = 0;
- return 0;
- } else {
- vub300->sg_transfer_timer.expires =
- jiffies + msecs_to_jiffies(2000 +
- (linear_length / 16384));
- add_timer(&vub300->sg_transfer_timer);
- usb_sg_wait(&vub300->sg_request);
- del_timer(&vub300->sg_transfer_timer);
- if (vub300->sg_request.status < 0) {
- cmd->error = vub300->sg_request.status;
- data->bytes_xfered = 0;
- return 0;
- } else {
- data->bytes_xfered = vub300->datasize;
- return linear_length;
- }
- }
- } else {
- u8 *buf = kmalloc(padded_length, GFP_KERNEL);
- if (buf) {
- int result;
- unsigned pipe = usb_rcvbulkpipe(vub300->udev,
- vub300->data_inp_ep);
- int actual_length = 0;
- result = vub300_usb_bulk_msg(vub300, pipe, buf,
- padded_length, &actual_length,
- 2000 + (padded_length / 16384));
- if (result < 0) {
- cmd->error = result;
- data->bytes_xfered = 0;
- kfree(buf);
- return 0;
- } else if (actual_length < linear_length) {
- cmd->error = -EREMOTEIO;
- data->bytes_xfered = 0;
- kfree(buf);
- return 0;
- } else {
- sg_copy_from_buffer(data->sg, data->sg_len, buf,
- linear_length);
- kfree(buf);
- data->bytes_xfered = vub300->datasize;
- return linear_length;
- }
- } else {
- cmd->error = -ENOMEM;
- data->bytes_xfered = 0;
- return 0;
- }
- }
-}
-
-static int __command_write_data(struct vub300_mmc_host *vub300,
- struct mmc_command *cmd, struct mmc_data *data)
-{
- /* cmd_mutex is held by vub300_cmndwork_thread */
- unsigned pipe = usb_sndbulkpipe(vub300->udev, vub300->data_out_ep);
- int linear_length = vub300->datasize;
- int modulo_64_length = linear_length & 0x003F;
- int modulo_512_length = linear_length & 0x01FF;
- if (linear_length < 64) {
- int result;
- int actual_length;
- sg_copy_to_buffer(data->sg, data->sg_len,
- vub300->padded_buffer,
- sizeof(vub300->padded_buffer));
- memset(vub300->padded_buffer + linear_length, 0,
- sizeof(vub300->padded_buffer) - linear_length);
- result = vub300_usb_bulk_msg(vub300, pipe, vub300->padded_buffer,
- sizeof(vub300->padded_buffer),
- &actual_length, 2000 +
- (sizeof(vub300->padded_buffer) /
- 16384));
- if (result < 0) {
- cmd->error = result;
- data->bytes_xfered = 0;
- } else {
- data->bytes_xfered = vub300->datasize;
- }
- } else if ((!vub300->large_usb_packets && (0 < modulo_64_length)) ||
- (vub300->large_usb_packets && (64 > modulo_512_length))
- ) { /* don't you just love these work-rounds */
- int padded_length = ((63 + linear_length) >> 6) << 6;
- u8 *buf = kmalloc(padded_length, GFP_KERNEL);
- if (buf) {
- int result;
- int actual_length;
- sg_copy_to_buffer(data->sg, data->sg_len, buf,
- padded_length);
- memset(buf + linear_length, 0,
- padded_length - linear_length);
- result =
- vub300_usb_bulk_msg(vub300, pipe, buf,
- padded_length, &actual_length,
- 2000 + padded_length / 16384);
- kfree(buf);
- if (result < 0) {
- cmd->error = result;
- data->bytes_xfered = 0;
- } else {
- data->bytes_xfered = vub300->datasize;
- }
- } else {
- cmd->error = -ENOMEM;
- data->bytes_xfered = 0;
- }
- } else { /* no data padding required */
- int result;
- unsigned char buf[64 * 4];
- sg_copy_to_buffer(data->sg, data->sg_len, buf, sizeof(buf));
- result = usb_sg_init(&vub300->sg_request, vub300->udev,
- pipe, 0, data->sg,
- data->sg_len, 0, GFP_KERNEL);
- if (result < 0) {
- usb_unlink_urb(vub300->command_out_urb);
- usb_unlink_urb(vub300->command_res_urb);
- cmd->error = result;
- data->bytes_xfered = 0;
- } else {
- vub300->sg_transfer_timer.expires =
- jiffies + msecs_to_jiffies(2000 +
- linear_length / 16384);
- add_timer(&vub300->sg_transfer_timer);
- usb_sg_wait(&vub300->sg_request);
- if (cmd->error) {
- data->bytes_xfered = 0;
- } else {
- del_timer(&vub300->sg_transfer_timer);
- if (vub300->sg_request.status < 0) {
- cmd->error = vub300->sg_request.status;
- data->bytes_xfered = 0;
- } else {
- data->bytes_xfered = vub300->datasize;
- }
- }
- }
- }
- return linear_length;
-}
-
-static void __vub300_command_response(struct vub300_mmc_host *vub300,
- struct mmc_command *cmd,
- struct mmc_data *data, int data_length)
-{
- /* cmd_mutex is held by vub300_cmndwork_thread */
- long respretval;
- int msec_timeout = 1000 + data_length / 4;
- respretval =
- wait_for_completion_timeout(&vub300->command_complete,
- msecs_to_jiffies(msec_timeout));
- if (respretval == 0) { /* TIMED OUT */
- /* we don't know which of "out" and "res" if any failed */
- int result;
- vub300->usb_timed_out = 1;
- usb_kill_urb(vub300->command_out_urb);
- usb_kill_urb(vub300->command_res_urb);
- cmd->error = -ETIMEDOUT;
- result = usb_lock_device_for_reset(vub300->udev,
- vub300->interface);
- if (result == 0) {
- result = usb_reset_device(vub300->udev);
- usb_unlock_device(vub300->udev);
- }
- } else if (respretval < 0) {
- /* we don't know which of "out" and "res" if any failed */
- usb_kill_urb(vub300->command_out_urb);
- usb_kill_urb(vub300->command_res_urb);
- cmd->error = respretval;
- } else if (cmd->error) {
- /*
- * the error occurred sending the command
- * or receiving the response
- */
- } else if (vub300->command_out_urb->status) {
- vub300->usb_transport_fail = vub300->command_out_urb->status;
- cmd->error = -EPROTO == vub300->command_out_urb->status ?
- -ESHUTDOWN : vub300->command_out_urb->status;
- } else if (vub300->command_res_urb->status) {
- vub300->usb_transport_fail = vub300->command_res_urb->status;
- cmd->error = -EPROTO == vub300->command_res_urb->status ?
- -ESHUTDOWN : vub300->command_res_urb->status;
- } else if (vub300->resp.common.header_type == 0x00) {
- /*
- * the command completed successfully
- * and there was no piggybacked data
- */
- } else if (vub300->resp.common.header_type == RESPONSE_ERROR) {
- cmd->error =
- vub300_response_error(vub300->resp.error.error_code);
- if (vub300->data)
- usb_sg_cancel(&vub300->sg_request);
- } else if (vub300->resp.common.header_type == RESPONSE_PIGGYBACKED) {
- int offloaded_data_length =
- vub300->resp.common.header_size -
- sizeof(struct sd_register_header);
- int register_count = offloaded_data_length >> 3;
- int ri = 0;
- while (register_count--) {
- add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]);
- ri += 1;
- }
- vub300->resp.common.header_size =
- sizeof(struct sd_register_header);
- vub300->resp.common.header_type = 0x00;
- cmd->error = 0;
- } else if (vub300->resp.common.header_type == RESPONSE_PIG_DISABLED) {
- int offloaded_data_length =
- vub300->resp.common.header_size -
- sizeof(struct sd_register_header);
- int register_count = offloaded_data_length >> 3;
- int ri = 0;
- while (register_count--) {
- add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]);
- ri += 1;
- }
- mutex_lock(&vub300->irq_mutex);
- if (vub300->irqs_queued) {
- vub300->irqs_queued += 1;
- } else if (vub300->irq_enabled) {
- vub300->irqs_queued += 1;
- vub300_queue_poll_work(vub300, 0);
- } else {
- vub300->irqs_queued += 1;
- }
- vub300->irq_disabled = 1;
- mutex_unlock(&vub300->irq_mutex);
- vub300->resp.common.header_size =
- sizeof(struct sd_register_header);
- vub300->resp.common.header_type = 0x00;
- cmd->error = 0;
- } else if (vub300->resp.common.header_type == RESPONSE_PIG_ENABLED) {
- int offloaded_data_length =
- vub300->resp.common.header_size -
- sizeof(struct sd_register_header);
- int register_count = offloaded_data_length >> 3;
- int ri = 0;
- while (register_count--) {
- add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]);
- ri += 1;
- }
- mutex_lock(&vub300->irq_mutex);
- if (vub300->irqs_queued) {
- vub300->irqs_queued += 1;
- } else if (vub300->irq_enabled) {
- vub300->irqs_queued += 1;
- vub300_queue_poll_work(vub300, 0);
- } else {
- vub300->irqs_queued += 1;
- }
- vub300->irq_disabled = 0;
- mutex_unlock(&vub300->irq_mutex);
- vub300->resp.common.header_size =
- sizeof(struct sd_register_header);
- vub300->resp.common.header_type = 0x00;
- cmd->error = 0;
- } else {
- cmd->error = -EINVAL;
- }
-}
-
-static void construct_request_response(struct vub300_mmc_host *vub300,
- struct mmc_command *cmd)
-{
- int resp_len = vub300->resp_len;
- int less_cmd = (17 == resp_len) ? resp_len : resp_len - 1;
- int bytes = 3 & less_cmd;
- int words = less_cmd >> 2;
- u8 *r = vub300->resp.response.command_response;
- if (bytes == 3) {
- cmd->resp[words] = (r[1 + (words << 2)] << 24)
- | (r[2 + (words << 2)] << 16)
- | (r[3 + (words << 2)] << 8);
- } else if (bytes == 2) {
- cmd->resp[words] = (r[1 + (words << 2)] << 24)
- | (r[2 + (words << 2)] << 16);
- } else if (bytes == 1) {
- cmd->resp[words] = (r[1 + (words << 2)] << 24);
- }
- while (words-- > 0) {
- cmd->resp[words] = (r[1 + (words << 2)] << 24)
- | (r[2 + (words << 2)] << 16)
- | (r[3 + (words << 2)] << 8)
- | (r[4 + (words << 2)] << 0);
- }
- if ((cmd->opcode == 53) && (0x000000FF & cmd->resp[0]))
- cmd->resp[0] &= 0xFFFFFF00;
-}
-
-/* this thread runs only when there is an upper level command req outstanding */
-static void vub300_cmndwork_thread(struct work_struct *work)
-{
- struct vub300_mmc_host *vub300 =
- container_of(work, struct vub300_mmc_host, cmndwork);
- if (!vub300->interface) {
- kref_put(&vub300->kref, vub300_delete);
- return;
- } else {
- struct mmc_request *req = vub300->req;
- struct mmc_command *cmd = vub300->cmd;
- struct mmc_data *data = vub300->data;
- int data_length;
- mutex_lock(&vub300->cmd_mutex);
- init_completion(&vub300->command_complete);
- if (likely(vub300->vub_name[0]) || !vub300->mmc->card ||
- !mmc_card_present(vub300->mmc->card)) {
- /*
- * the name of the EMPTY Pseudo firmware file
- * is used as a flag to indicate that the file
- * has been already downloaded to the VUB300 chip
- */
- } else if (0 == vub300->mmc->card->sdio_funcs) {
- strncpy(vub300->vub_name, "SD memory device",
- sizeof(vub300->vub_name));
- } else {
- download_offload_pseudocode(vub300);
- }
- send_command(vub300);
- if (!data)
- data_length = 0;
- else if (MMC_DATA_READ & data->flags)
- data_length = __command_read_data(vub300, cmd, data);
- else
- data_length = __command_write_data(vub300, cmd, data);
- __vub300_command_response(vub300, cmd, data, data_length);
- vub300->req = NULL;
- vub300->cmd = NULL;
- vub300->data = NULL;
- if (cmd->error) {
- if (cmd->error == -ENOMEDIUM)
- check_vub300_port_status(vub300);
- mutex_unlock(&vub300->cmd_mutex);
- mmc_request_done(vub300->mmc, req);
- kref_put(&vub300->kref, vub300_delete);
- return;
- } else {
- construct_request_response(vub300, cmd);
- vub300->resp_len = 0;
- mutex_unlock(&vub300->cmd_mutex);
- kref_put(&vub300->kref, vub300_delete);
- mmc_request_done(vub300->mmc, req);
- return;
- }
- }
-}
-
-static int examine_cyclic_buffer(struct vub300_mmc_host *vub300,
- struct mmc_command *cmd, u8 Function)
-{
- /* cmd_mutex is held by vub300_mmc_request */
- u8 cmd0 = 0xFF & (cmd->arg >> 24);
- u8 cmd1 = 0xFF & (cmd->arg >> 16);
- u8 cmd2 = 0xFF & (cmd->arg >> 8);
- u8 cmd3 = 0xFF & (cmd->arg >> 0);
- int first = MAXREGMASK & vub300->fn[Function].offload_point;
- struct offload_registers_access *rf = &vub300->fn[Function].reg[first];
- if (cmd0 == rf->command_byte[0] &&
- cmd1 == rf->command_byte[1] &&
- cmd2 == rf->command_byte[2] &&
- cmd3 == rf->command_byte[3]) {
- u8 checksum = 0x00;
- cmd->resp[1] = checksum << 24;
- cmd->resp[0] = (rf->Respond_Byte[0] << 24)
- | (rf->Respond_Byte[1] << 16)
- | (rf->Respond_Byte[2] << 8)
- | (rf->Respond_Byte[3] << 0);
- vub300->fn[Function].offload_point += 1;
- vub300->fn[Function].offload_count -= 1;
- vub300->total_offload_count -= 1;
- return 1;
- } else {
- int delta = 1; /* because it does not match the first one */
- u8 register_count = vub300->fn[Function].offload_count - 1;
- u32 register_point = vub300->fn[Function].offload_point + 1;
- while (0 < register_count) {
- int point = MAXREGMASK & register_point;
- struct offload_registers_access *r =
- &vub300->fn[Function].reg[point];
- if (cmd0 == r->command_byte[0] &&
- cmd1 == r->command_byte[1] &&
- cmd2 == r->command_byte[2] &&
- cmd3 == r->command_byte[3]) {
- u8 checksum = 0x00;
- cmd->resp[1] = checksum << 24;
- cmd->resp[0] = (r->Respond_Byte[0] << 24)
- | (r->Respond_Byte[1] << 16)
- | (r->Respond_Byte[2] << 8)
- | (r->Respond_Byte[3] << 0);
- vub300->fn[Function].offload_point += delta;
- vub300->fn[Function].offload_count -= delta;
- vub300->total_offload_count -= delta;
- return 1;
- } else {
- register_point += 1;
- register_count -= 1;
- delta += 1;
- continue;
- }
- }
- return 0;
- }
-}
-
-static int satisfy_request_from_offloaded_data(struct vub300_mmc_host *vub300,
- struct mmc_command *cmd)
-{
- /* cmd_mutex is held by vub300_mmc_request */
- u8 regs = vub300->dynamic_register_count;
- u8 i = 0;
- u8 func = FUN(cmd);
- u32 reg = REG(cmd);
- while (0 < regs--) {
- if ((vub300->sdio_register[i].func_num == func) &&
- (vub300->sdio_register[i].sdio_reg == reg)) {
- if (!vub300->sdio_register[i].prepared) {
- return 0;
- } else if ((0x80000000 & cmd->arg) == 0x80000000) {
- /*
- * a write to a dynamic register
- * nullifies our offloaded value
- */
- vub300->sdio_register[i].prepared = 0;
- return 0;
- } else {
- u8 checksum = 0x00;
- u8 rsp0 = 0x00;
- u8 rsp1 = 0x00;
- u8 rsp2 = vub300->sdio_register[i].response;
- u8 rsp3 = vub300->sdio_register[i].regvalue;
- vub300->sdio_register[i].prepared = 0;
- cmd->resp[1] = checksum << 24;
- cmd->resp[0] = (rsp0 << 24)
- | (rsp1 << 16)
- | (rsp2 << 8)
- | (rsp3 << 0);
- return 1;
- }
- } else {
- i += 1;
- continue;
- }
- };
- if (vub300->total_offload_count == 0)
- return 0;
- else if (vub300->fn[func].offload_count == 0)
- return 0;
- else
- return examine_cyclic_buffer(vub300, cmd, func);
-}
-
-static void vub300_mmc_request(struct mmc_host *mmc, struct mmc_request *req)
-{ /* NOT irq */
- struct mmc_command *cmd = req->cmd;
- struct vub300_mmc_host *vub300 = mmc_priv(mmc);
- if (!vub300->interface) {
- cmd->error = -ESHUTDOWN;
- mmc_request_done(mmc, req);
- return;
- } else {
- struct mmc_data *data = req->data;
- if (!vub300->card_powered) {
- cmd->error = -ENOMEDIUM;
- mmc_request_done(mmc, req);
- return;
- }
- if (!vub300->card_present) {
- cmd->error = -ENOMEDIUM;
- mmc_request_done(mmc, req);
- return;
- }
- if (vub300->usb_transport_fail) {
- cmd->error = vub300->usb_transport_fail;
- mmc_request_done(mmc, req);
- return;
- }
- if (!vub300->interface) {
- cmd->error = -ENODEV;
- mmc_request_done(mmc, req);
- return;
- }
- kref_get(&vub300->kref);
- mutex_lock(&vub300->cmd_mutex);
- mod_timer(&vub300->inactivity_timer, jiffies + HZ);
- /*
- * for performance we have to return immediately
- * if the requested data has been offloaded
- */
- if (cmd->opcode == 52 &&
- satisfy_request_from_offloaded_data(vub300, cmd)) {
- cmd->error = 0;
- mutex_unlock(&vub300->cmd_mutex);
- kref_put(&vub300->kref, vub300_delete);
- mmc_request_done(mmc, req);
- return;
- } else {
- vub300->cmd = cmd;
- vub300->req = req;
- vub300->data = data;
- if (data)
- vub300->datasize = data->blksz * data->blocks;
- else
- vub300->datasize = 0;
- vub300_queue_cmnd_work(vub300);
- mutex_unlock(&vub300->cmd_mutex);
- kref_put(&vub300->kref, vub300_delete);
- /*
- * the kernel lock diagnostics complain
- * if the cmd_mutex * is "passed on"
- * to the cmndwork thread,
- * so we must release it now
- * and re-acquire it in the cmndwork thread
- */
- }
- }
-}
-
-static void __set_clock_speed(struct vub300_mmc_host *vub300, u8 buf[8],
- struct mmc_ios *ios)
-{
- int buf_array_size = 8; /* ARRAY_SIZE(buf) does not work !!! */
- int retval;
- u32 kHzClock;
- if (ios->clock >= 48000000)
- kHzClock = 48000;
- else if (ios->clock >= 24000000)
- kHzClock = 24000;
- else if (ios->clock >= 20000000)
- kHzClock = 20000;
- else if (ios->clock >= 15000000)
- kHzClock = 15000;
- else if (ios->clock >= 200000)
- kHzClock = 200;
- else
- kHzClock = 0;
- {
- int i;
- u64 c = kHzClock;
- for (i = 0; i < buf_array_size; i++) {
- buf[i] = c;
- c >>= 8;
- }
- }
- retval =
- usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
- SET_CLOCK_SPEED,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x00, 0x00, buf, buf_array_size, HZ);
- if (retval != 8) {
- dev_err(&vub300->udev->dev, "SET_CLOCK_SPEED"
- " %dkHz failed with retval=%d\n", kHzClock, retval);
- } else {
- dev_dbg(&vub300->udev->dev, "SET_CLOCK_SPEED"
- " %dkHz\n", kHzClock);
- }
-}
-
-static void vub300_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{ /* NOT irq */
- struct vub300_mmc_host *vub300 = mmc_priv(mmc);
- if (!vub300->interface)
- return;
- kref_get(&vub300->kref);
- mutex_lock(&vub300->cmd_mutex);
- if ((ios->power_mode == MMC_POWER_OFF) && vub300->card_powered) {
- vub300->card_powered = 0;
- usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
- SET_SD_POWER,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x0000, 0x0000, NULL, 0, HZ);
- /* must wait for the VUB300 u-proc to boot up */
- msleep(600);
- } else if ((ios->power_mode == MMC_POWER_UP) && !vub300->card_powered) {
- usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
- SET_SD_POWER,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x0001, 0x0000, NULL, 0, HZ);
- msleep(600);
- vub300->card_powered = 1;
- } else if (ios->power_mode == MMC_POWER_ON) {
- u8 *buf = kmalloc(8, GFP_KERNEL);
- if (buf) {
- __set_clock_speed(vub300, buf, ios);
- kfree(buf);
- }
- } else {
- /* this should mean no change of state */
- }
- mutex_unlock(&vub300->cmd_mutex);
- kref_put(&vub300->kref, vub300_delete);
-}
-
-static int vub300_mmc_get_ro(struct mmc_host *mmc)
-{
- struct vub300_mmc_host *vub300 = mmc_priv(mmc);
- return vub300->read_only;
-}
-
-static void vub300_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{ /* NOT irq */
- struct vub300_mmc_host *vub300 = mmc_priv(mmc);
- if (!vub300->interface)
- return;
- kref_get(&vub300->kref);
- if (enable) {
- mutex_lock(&vub300->irq_mutex);
- if (vub300->irqs_queued) {
- vub300->irqs_queued -= 1;
- mmc_signal_sdio_irq(vub300->mmc);
- } else if (vub300->irq_disabled) {
- vub300->irq_disabled = 0;
- vub300->irq_enabled = 1;
- vub300_queue_poll_work(vub300, 0);
- } else if (vub300->irq_enabled) {
- /* this should not happen, so we will just ignore it */
- } else {
- vub300->irq_enabled = 1;
- vub300_queue_poll_work(vub300, 0);
- }
- mutex_unlock(&vub300->irq_mutex);
- } else {
- vub300->irq_enabled = 0;
- }
- kref_put(&vub300->kref, vub300_delete);
-}
-
-void vub300_init_card(struct mmc_host *mmc, struct mmc_card *card)
-{ /* NOT irq */
- struct vub300_mmc_host *vub300 = mmc_priv(mmc);
- dev_info(&vub300->udev->dev, "NO host QUIRKS for this card\n");
-}
-
-static struct mmc_host_ops vub300_mmc_ops = {
- .request = vub300_mmc_request,
- .set_ios = vub300_mmc_set_ios,
- .get_ro = vub300_mmc_get_ro,
- .enable_sdio_irq = vub300_enable_sdio_irq,
- .init_card = vub300_init_card,
-};
-
-static int vub300_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{ /* NOT irq */
- struct vub300_mmc_host *vub300;
- struct usb_host_interface *iface_desc;
- struct usb_device *udev = usb_get_dev(interface_to_usbdev(interface));
- int i;
- int retval = -ENOMEM;
- struct urb *command_out_urb;
- struct urb *command_res_urb;
- struct mmc_host *mmc;
- char manufacturer[48];
- char product[32];
- char serial_number[32];
- usb_string(udev, udev->descriptor.iManufacturer, manufacturer,
- sizeof(manufacturer));
- usb_string(udev, udev->descriptor.iProduct, product, sizeof(product));
- usb_string(udev, udev->descriptor.iSerialNumber, serial_number,
- sizeof(serial_number));
- dev_info(&udev->dev, "probing VID:PID(%04X:%04X) %s %s %s\n",
- udev->descriptor.idVendor, udev->descriptor.idProduct,
- manufacturer, product, serial_number);
- command_out_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!command_out_urb) {
- retval = -ENOMEM;
- dev_err(&udev->dev, "not enough memory for command_out_urb\n");
- goto error0;
- }
- command_res_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!command_res_urb) {
- retval = -ENOMEM;
- dev_err(&udev->dev, "not enough memory for command_res_urb\n");
- goto error1;
- }
- /* this also allocates memory for our VUB300 mmc host device */
- mmc = mmc_alloc_host(sizeof(struct vub300_mmc_host), &udev->dev);
- if (!mmc) {
- retval = -ENOMEM;
- dev_err(&udev->dev, "not enough memory for the mmc_host\n");
- goto error4;
- }
- /* MMC core transfer sizes tunable parameters */
- mmc->caps = 0;
- if (!force_1_bit_data_xfers)
- mmc->caps |= MMC_CAP_4_BIT_DATA;
- if (!force_polling_for_irqs)
- mmc->caps |= MMC_CAP_SDIO_IRQ;
- mmc->caps &= ~MMC_CAP_NEEDS_POLL;
- /*
- * MMC_CAP_NEEDS_POLL causes core.c:mmc_rescan() to poll
- * for devices which results in spurious CMD7's being
- * issued which stops some SDIO cards from working
- */
- if (limit_speed_to_24_MHz) {
- mmc->caps |= MMC_CAP_MMC_HIGHSPEED;
- mmc->caps |= MMC_CAP_SD_HIGHSPEED;
- mmc->f_max = 24000000;
- dev_info(&udev->dev, "limiting SDIO speed to 24_MHz\n");
- } else {
- mmc->caps |= MMC_CAP_MMC_HIGHSPEED;
- mmc->caps |= MMC_CAP_SD_HIGHSPEED;
- mmc->f_max = 48000000;
- }
- mmc->f_min = 200000;
- mmc->max_blk_count = 511;
- mmc->max_blk_size = 512;
- mmc->max_segs = 128;
- if (force_max_req_size)
- mmc->max_req_size = force_max_req_size * 1024;
- else
- mmc->max_req_size = 64 * 1024;
- mmc->max_seg_size = mmc->max_req_size;
- mmc->ocr_avail = 0;
- mmc->ocr_avail |= MMC_VDD_165_195;
- mmc->ocr_avail |= MMC_VDD_20_21;
- mmc->ocr_avail |= MMC_VDD_21_22;
- mmc->ocr_avail |= MMC_VDD_22_23;
- mmc->ocr_avail |= MMC_VDD_23_24;
- mmc->ocr_avail |= MMC_VDD_24_25;
- mmc->ocr_avail |= MMC_VDD_25_26;
- mmc->ocr_avail |= MMC_VDD_26_27;
- mmc->ocr_avail |= MMC_VDD_27_28;
- mmc->ocr_avail |= MMC_VDD_28_29;
- mmc->ocr_avail |= MMC_VDD_29_30;
- mmc->ocr_avail |= MMC_VDD_30_31;
- mmc->ocr_avail |= MMC_VDD_31_32;
- mmc->ocr_avail |= MMC_VDD_32_33;
- mmc->ocr_avail |= MMC_VDD_33_34;
- mmc->ocr_avail |= MMC_VDD_34_35;
- mmc->ocr_avail |= MMC_VDD_35_36;
- mmc->ops = &vub300_mmc_ops;
- vub300 = mmc_priv(mmc);
- vub300->mmc = mmc;
- vub300->card_powered = 0;
- vub300->bus_width = 0;
- vub300->cmnd.head.block_size[0] = 0x00;
- vub300->cmnd.head.block_size[1] = 0x00;
- vub300->app_spec = 0;
- mutex_init(&vub300->cmd_mutex);
- mutex_init(&vub300->irq_mutex);
- vub300->command_out_urb = command_out_urb;
- vub300->command_res_urb = command_res_urb;
- vub300->usb_timed_out = 0;
- vub300->dynamic_register_count = 0;
-
- for (i = 0; i < ARRAY_SIZE(vub300->fn); i++) {
- vub300->fn[i].offload_point = 0;
- vub300->fn[i].offload_count = 0;
- }
-
- vub300->total_offload_count = 0;
- vub300->irq_enabled = 0;
- vub300->irq_disabled = 0;
- vub300->irqs_queued = 0;
-
- for (i = 0; i < ARRAY_SIZE(vub300->sdio_register); i++)
- vub300->sdio_register[i++].activate = 0;
-
- vub300->udev = udev;
- vub300->interface = interface;
- vub300->cmnd_res_ep = 0;
- vub300->cmnd_out_ep = 0;
- vub300->data_inp_ep = 0;
- vub300->data_out_ep = 0;
-
- for (i = 0; i < ARRAY_SIZE(vub300->fbs); i++)
- vub300->fbs[i] = 512;
-
- /*
- * set up the endpoint information
- *
- * use the first pair of bulk-in and bulk-out
- * endpoints for Command/Response+Interrupt
- *
- * use the second pair of bulk-in and bulk-out
- * endpoints for Data In/Out
- */
- vub300->large_usb_packets = 0;
- iface_desc = interface->cur_altsetting;
- for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
- struct usb_endpoint_descriptor *endpoint =
- &iface_desc->endpoint[i].desc;
- dev_info(&vub300->udev->dev,
- "vub300 testing %s EndPoint(%d) %02X\n",
- usb_endpoint_is_bulk_in(endpoint) ? "BULK IN" :
- usb_endpoint_is_bulk_out(endpoint) ? "BULK OUT" :
- "UNKNOWN", i, endpoint->bEndpointAddress);
- if (endpoint->wMaxPacketSize > 64)
- vub300->large_usb_packets = 1;
- if (usb_endpoint_is_bulk_in(endpoint)) {
- if (!vub300->cmnd_res_ep) {
- vub300->cmnd_res_ep =
- endpoint->bEndpointAddress;
- } else if (!vub300->data_inp_ep) {
- vub300->data_inp_ep =
- endpoint->bEndpointAddress;
- } else {
- dev_warn(&vub300->udev->dev,
- "ignoring"
- " unexpected bulk_in endpoint");
- }
- } else if (usb_endpoint_is_bulk_out(endpoint)) {
- if (!vub300->cmnd_out_ep) {
- vub300->cmnd_out_ep =
- endpoint->bEndpointAddress;
- } else if (!vub300->data_out_ep) {
- vub300->data_out_ep =
- endpoint->bEndpointAddress;
- } else {
- dev_warn(&vub300->udev->dev,
- "ignoring"
- " unexpected bulk_out endpoint");
- }
- } else {
- dev_warn(&vub300->udev->dev,
- "vub300 ignoring EndPoint(%d) %02X", i,
- endpoint->bEndpointAddress);
- }
- }
- if (vub300->cmnd_res_ep && vub300->cmnd_out_ep &&
- vub300->data_inp_ep && vub300->data_out_ep) {
- dev_info(&vub300->udev->dev,
- "vub300 %s packets"
- " using EndPoints %02X %02X %02X %02X\n",
- vub300->large_usb_packets ? "LARGE" : "SMALL",
- vub300->cmnd_out_ep, vub300->cmnd_res_ep,
- vub300->data_out_ep, vub300->data_inp_ep);
- /* we have the expected EndPoints */
- } else {
- dev_err(&vub300->udev->dev,
- "Could not find two sets of bulk-in/out endpoint pairs\n");
- retval = -EINVAL;
- goto error5;
- }
- retval =
- usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
- GET_HC_INF0,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x0000, 0x0000, &vub300->hc_info,
- sizeof(vub300->hc_info), HZ);
- if (retval < 0)
- goto error5;
- retval =
- usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
- SET_ROM_WAIT_STATES,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- firmware_rom_wait_states, 0x0000, NULL, 0, HZ);
- if (retval < 0)
- goto error5;
- dev_info(&vub300->udev->dev,
- "operating_mode = %s %s %d MHz %s %d byte USB packets\n",
- (mmc->caps & MMC_CAP_SDIO_IRQ) ? "IRQs" : "POLL",
- (mmc->caps & MMC_CAP_4_BIT_DATA) ? "4-bit" : "1-bit",
- mmc->f_max / 1000000,
- pad_input_to_usb_pkt ? "padding input data to" : "with",
- vub300->large_usb_packets ? 512 : 64);
- retval =
- usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
- GET_SYSTEM_PORT_STATUS,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x0000, 0x0000, &vub300->system_port_status,
- sizeof(vub300->system_port_status), HZ);
- if (retval < 0) {
- goto error4;
- } else if (sizeof(vub300->system_port_status) == retval) {
- vub300->card_present =
- (0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
- vub300->read_only =
- (0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
- } else {
- goto error4;
- }
- usb_set_intfdata(interface, vub300);
- INIT_DELAYED_WORK(&vub300->pollwork, vub300_pollwork_thread);
- INIT_WORK(&vub300->cmndwork, vub300_cmndwork_thread);
- INIT_WORK(&vub300->deadwork, vub300_deadwork_thread);
- kref_init(&vub300->kref);
- init_timer(&vub300->sg_transfer_timer);
- vub300->sg_transfer_timer.data = (unsigned long)vub300;
- vub300->sg_transfer_timer.function = vub300_sg_timed_out;
- kref_get(&vub300->kref);
- init_timer(&vub300->inactivity_timer);
- vub300->inactivity_timer.data = (unsigned long)vub300;
- vub300->inactivity_timer.function = vub300_inactivity_timer_expired;
- vub300->inactivity_timer.expires = jiffies + HZ;
- add_timer(&vub300->inactivity_timer);
- if (vub300->card_present)
- dev_info(&vub300->udev->dev,
- "USB vub300 remote SDIO host controller[%d]"
- "connected with SD/SDIO card inserted\n",
- interface_to_InterfaceNumber(interface));
- else
- dev_info(&vub300->udev->dev,
- "USB vub300 remote SDIO host controller[%d]"
- "connected with no SD/SDIO card inserted\n",
- interface_to_InterfaceNumber(interface));
- mmc_add_host(mmc);
- return 0;
-error5:
- mmc_free_host(mmc);
- /*
- * and hence also frees vub300
- * which is contained at the end of struct mmc
- */
-error4:
- usb_free_urb(command_out_urb);
-error1:
- usb_free_urb(command_res_urb);
-error0:
- return retval;
-}
-
-static void vub300_disconnect(struct usb_interface *interface)
-{ /* NOT irq */
- struct vub300_mmc_host *vub300 = usb_get_intfdata(interface);
- if (!vub300 || !vub300->mmc) {
- return;
- } else {
- struct mmc_host *mmc = vub300->mmc;
- if (!vub300->mmc) {
- return;
- } else {
- int ifnum = interface_to_InterfaceNumber(interface);
- usb_set_intfdata(interface, NULL);
- /* prevent more I/O from starting */
- vub300->interface = NULL;
- kref_put(&vub300->kref, vub300_delete);
- mmc_remove_host(mmc);
- pr_info("USB vub300 remote SDIO host controller[%d]"
- " now disconnected", ifnum);
- return;
- }
- }
-}
-
-#ifdef CONFIG_PM
-static int vub300_suspend(struct usb_interface *intf, pm_message_t message)
-{
- struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
- if (!vub300 || !vub300->mmc) {
- return 0;
- } else {
- struct mmc_host *mmc = vub300->mmc;
- mmc_suspend_host(mmc);
- return 0;
- }
-}
-
-static int vub300_resume(struct usb_interface *intf)
-{
- struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
- if (!vub300 || !vub300->mmc) {
- return 0;
- } else {
- struct mmc_host *mmc = vub300->mmc;
- mmc_resume_host(mmc);
- return 0;
- }
-}
-#else
-#define vub300_suspend NULL
-#define vub300_resume NULL
-#endif
-static int vub300_pre_reset(struct usb_interface *intf)
-{ /* NOT irq */
- struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
- mutex_lock(&vub300->cmd_mutex);
- return 0;
-}
-
-static int vub300_post_reset(struct usb_interface *intf)
-{ /* NOT irq */
- struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
- /* we are sure no URBs are active - no locking needed */
- vub300->errors = -EPIPE;
- mutex_unlock(&vub300->cmd_mutex);
- return 0;
-}
-
-static struct usb_driver vub300_driver = {
- .name = "vub300",
- .probe = vub300_probe,
- .disconnect = vub300_disconnect,
- .suspend = vub300_suspend,
- .resume = vub300_resume,
- .pre_reset = vub300_pre_reset,
- .post_reset = vub300_post_reset,
- .id_table = vub300_table,
- .supports_autosuspend = 1,
-};
-
-static int __init vub300_init(void)
-{ /* NOT irq */
- int result;
-
- pr_info("VUB300 Driver rom wait states = %02X irqpoll timeout = %04X",
- firmware_rom_wait_states, 0x0FFFF & firmware_irqpoll_timeout);
- cmndworkqueue = create_singlethread_workqueue("kvub300c");
- if (!cmndworkqueue) {
- pr_err("not enough memory for the REQUEST workqueue");
- result = -ENOMEM;
- goto out1;
- }
- pollworkqueue = create_singlethread_workqueue("kvub300p");
- if (!pollworkqueue) {
- pr_err("not enough memory for the IRQPOLL workqueue");
- result = -ENOMEM;
- goto out2;
- }
- deadworkqueue = create_singlethread_workqueue("kvub300d");
- if (!deadworkqueue) {
- pr_err("not enough memory for the EXPIRED workqueue");
- result = -ENOMEM;
- goto out3;
- }
- result = usb_register(&vub300_driver);
- if (result) {
- pr_err("usb_register failed. Error number %d", result);
- goto out4;
- }
- return 0;
-out4:
- destroy_workqueue(deadworkqueue);
-out3:
- destroy_workqueue(pollworkqueue);
-out2:
- destroy_workqueue(cmndworkqueue);
-out1:
- return result;
-}
-
-static void __exit vub300_exit(void)
-{
- usb_deregister(&vub300_driver);
- flush_workqueue(cmndworkqueue);
- flush_workqueue(pollworkqueue);
- flush_workqueue(deadworkqueue);
- destroy_workqueue(cmndworkqueue);
- destroy_workqueue(pollworkqueue);
- destroy_workqueue(deadworkqueue);
-}
-
-module_init(vub300_init);
-module_exit(vub300_exit);
-
-MODULE_AUTHOR("Tony Olech <tony.olech@elandigitalsystems.com>");
-MODULE_DESCRIPTION("VUB300 USB to SD/MMC/SDIO adapter driver");
-MODULE_LICENSE("GPL");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/wbsd.c b/ANDROID_3.4.5/drivers/mmc/host/wbsd.c
deleted file mode 100644
index 64acd9ce..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/wbsd.c
+++ /dev/null
@@ -1,2047 +0,0 @@
-/*
- * linux/drivers/mmc/host/wbsd.c - Winbond W83L51xD SD/MMC driver
- *
- * Copyright (C) 2004-2007 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.
- *
- *
- * Warning!
- *
- * Changes to the FIFO system should be done with extreme care since
- * the hardware is full of bugs related to the FIFO. Known issues are:
- *
- * - FIFO size field in FSR is always zero.
- *
- * - FIFO interrupts tend not to work as they should. Interrupts are
- * triggered only for full/empty events, not for threshold values.
- *
- * - On APIC systems the FIFO empty interrupt is sometimes lost.
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/pnp.h>
-#include <linux/highmem.h>
-#include <linux/mmc/host.h>
-#include <linux/scatterlist.h>
-#include <linux/slab.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include "wbsd.h"
-
-#define DRIVER_NAME "wbsd"
-
-#define DBG(x...) \
- pr_debug(DRIVER_NAME ": " x)
-#define DBGF(f, x...) \
- pr_debug(DRIVER_NAME " [%s()]: " f, __func__ , ##x)
-
-/*
- * Device resources
- */
-
-#ifdef CONFIG_PNP
-
-static const struct pnp_device_id pnp_dev_table[] = {
- { "WEC0517", 0 },
- { "WEC0518", 0 },
- { "", 0 },
-};
-
-MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
-
-#endif /* CONFIG_PNP */
-
-static const int config_ports[] = { 0x2E, 0x4E };
-static const int unlock_codes[] = { 0x83, 0x87 };
-
-static const int valid_ids[] = {
- 0x7112,
-};
-
-#ifdef CONFIG_PNP
-static unsigned int param_nopnp = 0;
-#else
-static const unsigned int param_nopnp = 1;
-#endif
-static unsigned int param_io = 0x248;
-static unsigned int param_irq = 6;
-static int param_dma = 2;
-
-/*
- * Basic functions
- */
-
-static inline void wbsd_unlock_config(struct wbsd_host *host)
-{
- BUG_ON(host->config == 0);
-
- outb(host->unlock_code, host->config);
- outb(host->unlock_code, host->config);
-}
-
-static inline void wbsd_lock_config(struct wbsd_host *host)
-{
- BUG_ON(host->config == 0);
-
- outb(LOCK_CODE, host->config);
-}
-
-static inline void wbsd_write_config(struct wbsd_host *host, u8 reg, u8 value)
-{
- BUG_ON(host->config == 0);
-
- outb(reg, host->config);
- outb(value, host->config + 1);
-}
-
-static inline u8 wbsd_read_config(struct wbsd_host *host, u8 reg)
-{
- BUG_ON(host->config == 0);
-
- outb(reg, host->config);
- return inb(host->config + 1);
-}
-
-static inline void wbsd_write_index(struct wbsd_host *host, u8 index, u8 value)
-{
- outb(index, host->base + WBSD_IDXR);
- outb(value, host->base + WBSD_DATAR);
-}
-
-static inline u8 wbsd_read_index(struct wbsd_host *host, u8 index)
-{
- outb(index, host->base + WBSD_IDXR);
- return inb(host->base + WBSD_DATAR);
-}
-
-/*
- * Common routines
- */
-
-static void wbsd_init_device(struct wbsd_host *host)
-{
- u8 setup, ier;
-
- /*
- * Reset chip (SD/MMC part) and fifo.
- */
- setup = wbsd_read_index(host, WBSD_IDX_SETUP);
- setup |= WBSD_FIFO_RESET | WBSD_SOFT_RESET;
- wbsd_write_index(host, WBSD_IDX_SETUP, setup);
-
- /*
- * Set DAT3 to input
- */
- setup &= ~WBSD_DAT3_H;
- wbsd_write_index(host, WBSD_IDX_SETUP, setup);
- host->flags &= ~WBSD_FIGNORE_DETECT;
-
- /*
- * Read back default clock.
- */
- host->clk = wbsd_read_index(host, WBSD_IDX_CLK);
-
- /*
- * Power down port.
- */
- outb(WBSD_POWER_N, host->base + WBSD_CSR);
-
- /*
- * Set maximum timeout.
- */
- wbsd_write_index(host, WBSD_IDX_TAAC, 0x7F);
-
- /*
- * Test for card presence
- */
- if (inb(host->base + WBSD_CSR) & WBSD_CARDPRESENT)
- host->flags |= WBSD_FCARD_PRESENT;
- else
- host->flags &= ~WBSD_FCARD_PRESENT;
-
- /*
- * Enable interesting interrupts.
- */
- ier = 0;
- ier |= WBSD_EINT_CARD;
- ier |= WBSD_EINT_FIFO_THRE;
- ier |= WBSD_EINT_CRC;
- ier |= WBSD_EINT_TIMEOUT;
- ier |= WBSD_EINT_TC;
-
- outb(ier, host->base + WBSD_EIR);
-
- /*
- * Clear interrupts.
- */
- inb(host->base + WBSD_ISR);
-}
-
-static void wbsd_reset(struct wbsd_host *host)
-{
- u8 setup;
-
- pr_err("%s: Resetting chip\n", mmc_hostname(host->mmc));
-
- /*
- * Soft reset of chip (SD/MMC part).
- */
- setup = wbsd_read_index(host, WBSD_IDX_SETUP);
- setup |= WBSD_SOFT_RESET;
- wbsd_write_index(host, WBSD_IDX_SETUP, setup);
-}
-
-static void wbsd_request_end(struct wbsd_host *host, struct mmc_request *mrq)
-{
- unsigned long dmaflags;
-
- if (host->dma >= 0) {
- /*
- * Release ISA DMA controller.
- */
- dmaflags = claim_dma_lock();
- disable_dma(host->dma);
- clear_dma_ff(host->dma);
- release_dma_lock(dmaflags);
-
- /*
- * Disable DMA on host.
- */
- wbsd_write_index(host, WBSD_IDX_DMA, 0);
- }
-
- host->mrq = NULL;
-
- /*
- * MMC layer might call back into the driver so first unlock.
- */
- spin_unlock(&host->lock);
- mmc_request_done(host->mmc, mrq);
- spin_lock(&host->lock);
-}
-
-/*
- * Scatter/gather functions
- */
-
-static inline void wbsd_init_sg(struct wbsd_host *host, struct mmc_data *data)
-{
- /*
- * Get info. about SG list from data structure.
- */
- host->cur_sg = data->sg;
- host->num_sg = data->sg_len;
-
- host->offset = 0;
- host->remain = host->cur_sg->length;
-}
-
-static inline int wbsd_next_sg(struct wbsd_host *host)
-{
- /*
- * Skip to next SG entry.
- */
- host->cur_sg++;
- host->num_sg--;
-
- /*
- * Any entries left?
- */
- if (host->num_sg > 0) {
- host->offset = 0;
- host->remain = host->cur_sg->length;
- }
-
- return host->num_sg;
-}
-
-static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)
-{
- return sg_virt(host->cur_sg);
-}
-
-static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
-{
- unsigned int len, i;
- struct scatterlist *sg;
- char *dmabuf = host->dma_buffer;
- char *sgbuf;
-
- sg = data->sg;
- len = data->sg_len;
-
- for (i = 0; i < len; i++) {
- sgbuf = sg_virt(&sg[i]);
- memcpy(dmabuf, sgbuf, sg[i].length);
- dmabuf += sg[i].length;
- }
-}
-
-static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
-{
- unsigned int len, i;
- struct scatterlist *sg;
- char *dmabuf = host->dma_buffer;
- char *sgbuf;
-
- sg = data->sg;
- len = data->sg_len;
-
- for (i = 0; i < len; i++) {
- sgbuf = sg_virt(&sg[i]);
- memcpy(sgbuf, dmabuf, sg[i].length);
- dmabuf += sg[i].length;
- }
-}
-
-/*
- * Command handling
- */
-
-static inline void wbsd_get_short_reply(struct wbsd_host *host,
- struct mmc_command *cmd)
-{
- /*
- * Correct response type?
- */
- if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_SHORT) {
- cmd->error = -EILSEQ;
- return;
- }
-
- cmd->resp[0] = wbsd_read_index(host, WBSD_IDX_RESP12) << 24;
- cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP13) << 16;
- cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP14) << 8;
- cmd->resp[0] |= wbsd_read_index(host, WBSD_IDX_RESP15) << 0;
- cmd->resp[1] = wbsd_read_index(host, WBSD_IDX_RESP16) << 24;
-}
-
-static inline void wbsd_get_long_reply(struct wbsd_host *host,
- struct mmc_command *cmd)
-{
- int i;
-
- /*
- * Correct response type?
- */
- if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_LONG) {
- cmd->error = -EILSEQ;
- return;
- }
-
- for (i = 0; i < 4; i++) {
- cmd->resp[i] =
- wbsd_read_index(host, WBSD_IDX_RESP1 + i * 4) << 24;
- cmd->resp[i] |=
- wbsd_read_index(host, WBSD_IDX_RESP2 + i * 4) << 16;
- cmd->resp[i] |=
- wbsd_read_index(host, WBSD_IDX_RESP3 + i * 4) << 8;
- cmd->resp[i] |=
- wbsd_read_index(host, WBSD_IDX_RESP4 + i * 4) << 0;
- }
-}
-
-static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd)
-{
- int i;
- u8 status, isr;
-
- /*
- * Clear accumulated ISR. The interrupt routine
- * will fill this one with events that occur during
- * transfer.
- */
- host->isr = 0;
-
- /*
- * Send the command (CRC calculated by host).
- */
- outb(cmd->opcode, host->base + WBSD_CMDR);
- for (i = 3; i >= 0; i--)
- outb((cmd->arg >> (i * 8)) & 0xff, host->base + WBSD_CMDR);
-
- cmd->error = 0;
-
- /*
- * Wait for the request to complete.
- */
- do {
- status = wbsd_read_index(host, WBSD_IDX_STATUS);
- } while (status & WBSD_CARDTRAFFIC);
-
- /*
- * Do we expect a reply?
- */
- if (cmd->flags & MMC_RSP_PRESENT) {
- /*
- * Read back status.
- */
- isr = host->isr;
-
- /* Card removed? */
- if (isr & WBSD_INT_CARD)
- cmd->error = -ENOMEDIUM;
- /* Timeout? */
- else if (isr & WBSD_INT_TIMEOUT)
- cmd->error = -ETIMEDOUT;
- /* CRC? */
- else if ((cmd->flags & MMC_RSP_CRC) && (isr & WBSD_INT_CRC))
- cmd->error = -EILSEQ;
- /* All ok */
- else {
- if (cmd->flags & MMC_RSP_136)
- wbsd_get_long_reply(host, cmd);
- else
- wbsd_get_short_reply(host, cmd);
- }
- }
-}
-
-/*
- * Data functions
- */
-
-static void wbsd_empty_fifo(struct wbsd_host *host)
-{
- struct mmc_data *data = host->mrq->cmd->data;
- char *buffer;
- int i, fsr, fifo;
-
- /*
- * Handle excessive data.
- */
- if (host->num_sg == 0)
- return;
-
- buffer = wbsd_sg_to_buffer(host) + host->offset;
-
- /*
- * Drain the fifo. This has a tendency to loop longer
- * than the FIFO length (usually one block).
- */
- while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_EMPTY)) {
- /*
- * The size field in the FSR is broken so we have to
- * do some guessing.
- */
- if (fsr & WBSD_FIFO_FULL)
- fifo = 16;
- else if (fsr & WBSD_FIFO_FUTHRE)
- fifo = 8;
- else
- fifo = 1;
-
- for (i = 0; i < fifo; i++) {
- *buffer = inb(host->base + WBSD_DFR);
- buffer++;
- host->offset++;
- host->remain--;
-
- data->bytes_xfered++;
-
- /*
- * End of scatter list entry?
- */
- if (host->remain == 0) {
- /*
- * Get next entry. Check if last.
- */
- if (!wbsd_next_sg(host))
- return;
-
- buffer = wbsd_sg_to_buffer(host);
- }
- }
- }
-
- /*
- * This is a very dirty hack to solve a
- * hardware problem. The chip doesn't trigger
- * FIFO threshold interrupts properly.
- */
- if ((data->blocks * data->blksz - data->bytes_xfered) < 16)
- tasklet_schedule(&host->fifo_tasklet);
-}
-
-static void wbsd_fill_fifo(struct wbsd_host *host)
-{
- struct mmc_data *data = host->mrq->cmd->data;
- char *buffer;
- int i, fsr, fifo;
-
- /*
- * Check that we aren't being called after the
- * entire buffer has been transferred.
- */
- if (host->num_sg == 0)
- return;
-
- buffer = wbsd_sg_to_buffer(host) + host->offset;
-
- /*
- * Fill the fifo. This has a tendency to loop longer
- * than the FIFO length (usually one block).
- */
- while (!((fsr = inb(host->base + WBSD_FSR)) & WBSD_FIFO_FULL)) {
- /*
- * The size field in the FSR is broken so we have to
- * do some guessing.
- */
- if (fsr & WBSD_FIFO_EMPTY)
- fifo = 0;
- else if (fsr & WBSD_FIFO_EMTHRE)
- fifo = 8;
- else
- fifo = 15;
-
- for (i = 16; i > fifo; i--) {
- outb(*buffer, host->base + WBSD_DFR);
- buffer++;
- host->offset++;
- host->remain--;
-
- data->bytes_xfered++;
-
- /*
- * End of scatter list entry?
- */
- if (host->remain == 0) {
- /*
- * Get next entry. Check if last.
- */
- if (!wbsd_next_sg(host))
- return;
-
- buffer = wbsd_sg_to_buffer(host);
- }
- }
- }
-
- /*
- * The controller stops sending interrupts for
- * 'FIFO empty' under certain conditions. So we
- * need to be a bit more pro-active.
- */
- tasklet_schedule(&host->fifo_tasklet);
-}
-
-static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
-{
- u16 blksize;
- u8 setup;
- unsigned long dmaflags;
- unsigned int size;
-
- /*
- * Calculate size.
- */
- size = data->blocks * data->blksz;
-
- /*
- * Check timeout values for overflow.
- * (Yes, some cards cause this value to overflow).
- */
- if (data->timeout_ns > 127000000)
- wbsd_write_index(host, WBSD_IDX_TAAC, 127);
- else {
- wbsd_write_index(host, WBSD_IDX_TAAC,
- data->timeout_ns / 1000000);
- }
-
- if (data->timeout_clks > 255)
- wbsd_write_index(host, WBSD_IDX_NSAC, 255);
- else
- wbsd_write_index(host, WBSD_IDX_NSAC, data->timeout_clks);
-
- /*
- * Inform the chip of how large blocks will be
- * sent. It needs this to determine when to
- * calculate CRC.
- *
- * Space for CRC must be included in the size.
- * Two bytes are needed for each data line.
- */
- if (host->bus_width == MMC_BUS_WIDTH_1) {
- blksize = data->blksz + 2;
-
- wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0);
- wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
- } else if (host->bus_width == MMC_BUS_WIDTH_4) {
- blksize = data->blksz + 2 * 4;
-
- wbsd_write_index(host, WBSD_IDX_PBSMSB,
- ((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH);
- wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
- } else {
- data->error = -EINVAL;
- return;
- }
-
- /*
- * Clear the FIFO. This is needed even for DMA
- * transfers since the chip still uses the FIFO
- * internally.
- */
- setup = wbsd_read_index(host, WBSD_IDX_SETUP);
- setup |= WBSD_FIFO_RESET;
- wbsd_write_index(host, WBSD_IDX_SETUP, setup);
-
- /*
- * DMA transfer?
- */
- if (host->dma >= 0) {
- /*
- * The buffer for DMA is only 64 kB.
- */
- BUG_ON(size > 0x10000);
- if (size > 0x10000) {
- data->error = -EINVAL;
- return;
- }
-
- /*
- * Transfer data from the SG list to
- * the DMA buffer.
- */
- if (data->flags & MMC_DATA_WRITE)
- wbsd_sg_to_dma(host, data);
-
- /*
- * Initialise the ISA DMA controller.
- */
- dmaflags = claim_dma_lock();
- disable_dma(host->dma);
- clear_dma_ff(host->dma);
- if (data->flags & MMC_DATA_READ)
- set_dma_mode(host->dma, DMA_MODE_READ & ~0x40);
- else
- set_dma_mode(host->dma, DMA_MODE_WRITE & ~0x40);
- set_dma_addr(host->dma, host->dma_addr);
- set_dma_count(host->dma, size);
-
- enable_dma(host->dma);
- release_dma_lock(dmaflags);
-
- /*
- * Enable DMA on the host.
- */
- wbsd_write_index(host, WBSD_IDX_DMA, WBSD_DMA_ENABLE);
- } else {
- /*
- * This flag is used to keep printk
- * output to a minimum.
- */
- host->firsterr = 1;
-
- /*
- * Initialise the SG list.
- */
- wbsd_init_sg(host, data);
-
- /*
- * Turn off DMA.
- */
- wbsd_write_index(host, WBSD_IDX_DMA, 0);
-
- /*
- * Set up FIFO threshold levels (and fill
- * buffer if doing a write).
- */
- if (data->flags & MMC_DATA_READ) {
- wbsd_write_index(host, WBSD_IDX_FIFOEN,
- WBSD_FIFOEN_FULL | 8);
- } else {
- wbsd_write_index(host, WBSD_IDX_FIFOEN,
- WBSD_FIFOEN_EMPTY | 8);
- wbsd_fill_fifo(host);
- }
- }
-
- data->error = 0;
-}
-
-static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
-{
- unsigned long dmaflags;
- int count;
- u8 status;
-
- WARN_ON(host->mrq == NULL);
-
- /*
- * Send a stop command if needed.
- */
- if (data->stop)
- wbsd_send_command(host, data->stop);
-
- /*
- * Wait for the controller to leave data
- * transfer state.
- */
- do {
- status = wbsd_read_index(host, WBSD_IDX_STATUS);
- } while (status & (WBSD_BLOCK_READ | WBSD_BLOCK_WRITE));
-
- /*
- * DMA transfer?
- */
- if (host->dma >= 0) {
- /*
- * Disable DMA on the host.
- */
- wbsd_write_index(host, WBSD_IDX_DMA, 0);
-
- /*
- * Turn of ISA DMA controller.
- */
- dmaflags = claim_dma_lock();
- disable_dma(host->dma);
- clear_dma_ff(host->dma);
- count = get_dma_residue(host->dma);
- release_dma_lock(dmaflags);
-
- data->bytes_xfered = host->mrq->data->blocks *
- host->mrq->data->blksz - count;
- data->bytes_xfered -= data->bytes_xfered % data->blksz;
-
- /*
- * Any leftover data?
- */
- if (count) {
- pr_err("%s: Incomplete DMA transfer. "
- "%d bytes left.\n",
- mmc_hostname(host->mmc), count);
-
- if (!data->error)
- data->error = -EIO;
- } else {
- /*
- * Transfer data from DMA buffer to
- * SG list.
- */
- if (data->flags & MMC_DATA_READ)
- wbsd_dma_to_sg(host, data);
- }
-
- if (data->error) {
- if (data->bytes_xfered)
- data->bytes_xfered -= data->blksz;
- }
- }
-
- wbsd_request_end(host, host->mrq);
-}
-
-/*****************************************************************************\
- * *
- * MMC layer callbacks *
- * *
-\*****************************************************************************/
-
-static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
- struct wbsd_host *host = mmc_priv(mmc);
- struct mmc_command *cmd;
-
- /*
- * Disable tasklets to avoid a deadlock.
- */
- spin_lock_bh(&host->lock);
-
- BUG_ON(host->mrq != NULL);
-
- cmd = mrq->cmd;
-
- host->mrq = mrq;
-
- /*
- * Check that there is actually a card in the slot.
- */
- if (!(host->flags & WBSD_FCARD_PRESENT)) {
- cmd->error = -ENOMEDIUM;
- goto done;
- }
-
- if (cmd->data) {
- /*
- * The hardware is so delightfully stupid that it has a list
- * of "data" commands. If a command isn't on this list, it'll
- * just go back to the idle state and won't send any data
- * interrupts.
- */
- switch (cmd->opcode) {
- case 11:
- case 17:
- case 18:
- case 20:
- case 24:
- case 25:
- case 26:
- case 27:
- case 30:
- case 42:
- case 56:
- break;
-
- /* ACMDs. We don't keep track of state, so we just treat them
- * like any other command. */
- case 51:
- break;
-
- default:
-#ifdef CONFIG_MMC_DEBUG
- pr_warning("%s: Data command %d is not "
- "supported by this controller.\n",
- mmc_hostname(host->mmc), cmd->opcode);
-#endif
- cmd->error = -EINVAL;
-
- goto done;
- };
- }
-
- /*
- * Does the request include data?
- */
- if (cmd->data) {
- wbsd_prepare_data(host, cmd->data);
-
- if (cmd->data->error)
- goto done;
- }
-
- wbsd_send_command(host, cmd);
-
- /*
- * If this is a data transfer the request
- * will be finished after the data has
- * transferred.
- */
- if (cmd->data && !cmd->error) {
- /*
- * Dirty fix for hardware bug.
- */
- if (host->dma == -1)
- tasklet_schedule(&host->fifo_tasklet);
-
- spin_unlock_bh(&host->lock);
-
- return;
- }
-
-done:
- wbsd_request_end(host, mrq);
-
- spin_unlock_bh(&host->lock);
-}
-
-static void wbsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
- struct wbsd_host *host = mmc_priv(mmc);
- u8 clk, setup, pwr;
-
- spin_lock_bh(&host->lock);
-
- /*
- * Reset the chip on each power off.
- * Should clear out any weird states.
- */
- if (ios->power_mode == MMC_POWER_OFF)
- wbsd_init_device(host);
-
- if (ios->clock >= 24000000)
- clk = WBSD_CLK_24M;
- else if (ios->clock >= 16000000)
- clk = WBSD_CLK_16M;
- else if (ios->clock >= 12000000)
- clk = WBSD_CLK_12M;
- else
- clk = WBSD_CLK_375K;
-
- /*
- * Only write to the clock register when
- * there is an actual change.
- */
- if (clk != host->clk) {
- wbsd_write_index(host, WBSD_IDX_CLK, clk);
- host->clk = clk;
- }
-
- /*
- * Power up card.
- */
- if (ios->power_mode != MMC_POWER_OFF) {
- pwr = inb(host->base + WBSD_CSR);
- pwr &= ~WBSD_POWER_N;
- outb(pwr, host->base + WBSD_CSR);
- }
-
- /*
- * MMC cards need to have pin 1 high during init.
- * It wreaks havoc with the card detection though so
- * that needs to be disabled.
- */
- setup = wbsd_read_index(host, WBSD_IDX_SETUP);
- if (ios->chip_select == MMC_CS_HIGH) {
- BUG_ON(ios->bus_width != MMC_BUS_WIDTH_1);
- setup |= WBSD_DAT3_H;
- host->flags |= WBSD_FIGNORE_DETECT;
- } else {
- if (setup & WBSD_DAT3_H) {
- setup &= ~WBSD_DAT3_H;
-
- /*
- * We cannot resume card detection immediately
- * because of capacitance and delays in the chip.
- */
- mod_timer(&host->ignore_timer, jiffies + HZ / 100);
- }
- }
- wbsd_write_index(host, WBSD_IDX_SETUP, setup);
-
- /*
- * Store bus width for later. Will be used when
- * setting up the data transfer.
- */
- host->bus_width = ios->bus_width;
-
- spin_unlock_bh(&host->lock);
-}
-
-static int wbsd_get_ro(struct mmc_host *mmc)
-{
- struct wbsd_host *host = mmc_priv(mmc);
- u8 csr;
-
- spin_lock_bh(&host->lock);
-
- csr = inb(host->base + WBSD_CSR);
- csr |= WBSD_MSLED;
- outb(csr, host->base + WBSD_CSR);
-
- mdelay(1);
-
- csr = inb(host->base + WBSD_CSR);
- csr &= ~WBSD_MSLED;
- outb(csr, host->base + WBSD_CSR);
-
- spin_unlock_bh(&host->lock);
-
- return !!(csr & WBSD_WRPT);
-}
-
-static const struct mmc_host_ops wbsd_ops = {
- .request = wbsd_request,
- .set_ios = wbsd_set_ios,
- .get_ro = wbsd_get_ro,
-};
-
-/*****************************************************************************\
- * *
- * Interrupt handling *
- * *
-\*****************************************************************************/
-
-/*
- * Helper function to reset detection ignore
- */
-
-static void wbsd_reset_ignore(unsigned long data)
-{
- struct wbsd_host *host = (struct wbsd_host *)data;
-
- BUG_ON(host == NULL);
-
- DBG("Resetting card detection ignore\n");
-
- spin_lock_bh(&host->lock);
-
- host->flags &= ~WBSD_FIGNORE_DETECT;
-
- /*
- * Card status might have changed during the
- * blackout.
- */
- tasklet_schedule(&host->card_tasklet);
-
- spin_unlock_bh(&host->lock);
-}
-
-/*
- * Tasklets
- */
-
-static inline struct mmc_data *wbsd_get_data(struct wbsd_host *host)
-{
- WARN_ON(!host->mrq);
- if (!host->mrq)
- return NULL;
-
- WARN_ON(!host->mrq->cmd);
- if (!host->mrq->cmd)
- return NULL;
-
- WARN_ON(!host->mrq->cmd->data);
- if (!host->mrq->cmd->data)
- return NULL;
-
- return host->mrq->cmd->data;
-}
-
-static void wbsd_tasklet_card(unsigned long param)
-{
- struct wbsd_host *host = (struct wbsd_host *)param;
- u8 csr;
- int delay = -1;
-
- spin_lock(&host->lock);
-
- if (host->flags & WBSD_FIGNORE_DETECT) {
- spin_unlock(&host->lock);
- return;
- }
-
- csr = inb(host->base + WBSD_CSR);
- WARN_ON(csr == 0xff);
-
- if (csr & WBSD_CARDPRESENT) {
- if (!(host->flags & WBSD_FCARD_PRESENT)) {
- DBG("Card inserted\n");
- host->flags |= WBSD_FCARD_PRESENT;
-
- delay = 500;
- }
- } else if (host->flags & WBSD_FCARD_PRESENT) {
- DBG("Card removed\n");
- host->flags &= ~WBSD_FCARD_PRESENT;
-
- if (host->mrq) {
- pr_err("%s: Card removed during transfer!\n",
- mmc_hostname(host->mmc));
- wbsd_reset(host);
-
- host->mrq->cmd->error = -ENOMEDIUM;
- tasklet_schedule(&host->finish_tasklet);
- }
-
- delay = 0;
- }
-
- /*
- * Unlock first since we might get a call back.
- */
-
- spin_unlock(&host->lock);
-
- if (delay != -1)
- mmc_detect_change(host->mmc, msecs_to_jiffies(delay));
-}
-
-static void wbsd_tasklet_fifo(unsigned long param)
-{
- struct wbsd_host *host = (struct wbsd_host *)param;
- struct mmc_data *data;
-
- spin_lock(&host->lock);
-
- if (!host->mrq)
- goto end;
-
- data = wbsd_get_data(host);
- if (!data)
- goto end;
-
- if (data->flags & MMC_DATA_WRITE)
- wbsd_fill_fifo(host);
- else
- wbsd_empty_fifo(host);
-
- /*
- * Done?
- */
- if (host->num_sg == 0) {
- wbsd_write_index(host, WBSD_IDX_FIFOEN, 0);
- tasklet_schedule(&host->finish_tasklet);
- }
-
-end:
- spin_unlock(&host->lock);
-}
-
-static void wbsd_tasklet_crc(unsigned long param)
-{
- struct wbsd_host *host = (struct wbsd_host *)param;
- struct mmc_data *data;
-
- spin_lock(&host->lock);
-
- if (!host->mrq)
- goto end;
-
- data = wbsd_get_data(host);
- if (!data)
- goto end;
-
- DBGF("CRC error\n");
-
- data->error = -EILSEQ;
-
- tasklet_schedule(&host->finish_tasklet);
-
-end:
- spin_unlock(&host->lock);
-}
-
-static void wbsd_tasklet_timeout(unsigned long param)
-{
- struct wbsd_host *host = (struct wbsd_host *)param;
- struct mmc_data *data;
-
- spin_lock(&host->lock);
-
- if (!host->mrq)
- goto end;
-
- data = wbsd_get_data(host);
- if (!data)
- goto end;
-
- DBGF("Timeout\n");
-
- data->error = -ETIMEDOUT;
-
- tasklet_schedule(&host->finish_tasklet);
-
-end:
- spin_unlock(&host->lock);
-}
-
-static void wbsd_tasklet_finish(unsigned long param)
-{
- struct wbsd_host *host = (struct wbsd_host *)param;
- struct mmc_data *data;
-
- spin_lock(&host->lock);
-
- WARN_ON(!host->mrq);
- if (!host->mrq)
- goto end;
-
- data = wbsd_get_data(host);
- if (!data)
- goto end;
-
- wbsd_finish_data(host, data);
-
-end:
- spin_unlock(&host->lock);
-}
-
-/*
- * Interrupt handling
- */
-
-static irqreturn_t wbsd_irq(int irq, void *dev_id)
-{
- struct wbsd_host *host = dev_id;
- int isr;
-
- isr = inb(host->base + WBSD_ISR);
-
- /*
- * Was it actually our hardware that caused the interrupt?
- */
- if (isr == 0xff || isr == 0x00)
- return IRQ_NONE;
-
- host->isr |= isr;
-
- /*
- * Schedule tasklets as needed.
- */
- if (isr & WBSD_INT_CARD)
- tasklet_schedule(&host->card_tasklet);
- if (isr & WBSD_INT_FIFO_THRE)
- tasklet_schedule(&host->fifo_tasklet);
- if (isr & WBSD_INT_CRC)
- tasklet_hi_schedule(&host->crc_tasklet);
- if (isr & WBSD_INT_TIMEOUT)
- tasklet_hi_schedule(&host->timeout_tasklet);
- if (isr & WBSD_INT_TC)
- tasklet_schedule(&host->finish_tasklet);
-
- return IRQ_HANDLED;
-}
-
-/*****************************************************************************\
- * *
- * Device initialisation and shutdown *
- * *
-\*****************************************************************************/
-
-/*
- * Allocate/free MMC structure.
- */
-
-static int __devinit wbsd_alloc_mmc(struct device *dev)
-{
- struct mmc_host *mmc;
- struct wbsd_host *host;
-
- /*
- * Allocate MMC structure.
- */
- mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev);
- if (!mmc)
- return -ENOMEM;
-
- host = mmc_priv(mmc);
- host->mmc = mmc;
-
- host->dma = -1;
-
- /*
- * Set host parameters.
- */
- mmc->ops = &wbsd_ops;
- mmc->f_min = 375000;
- mmc->f_max = 24000000;
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps = MMC_CAP_4_BIT_DATA;
-
- spin_lock_init(&host->lock);
-
- /*
- * Set up timers
- */
- init_timer(&host->ignore_timer);
- host->ignore_timer.data = (unsigned long)host;
- host->ignore_timer.function = wbsd_reset_ignore;
-
- /*
- * Maximum number of segments. Worst case is one sector per segment
- * so this will be 64kB/512.
- */
- mmc->max_segs = 128;
-
- /*
- * Maximum request size. Also limited by 64KiB buffer.
- */
- mmc->max_req_size = 65536;
-
- /*
- * Maximum segment size. Could be one segment with the maximum number
- * of bytes.
- */
- mmc->max_seg_size = mmc->max_req_size;
-
- /*
- * Maximum block size. We have 12 bits (= 4095) but have to subtract
- * space for CRC. So the maximum is 4095 - 4*2 = 4087.
- */
- mmc->max_blk_size = 4087;
-
- /*
- * Maximum block count. There is no real limit so the maximum
- * request size will be the only restriction.
- */
- mmc->max_blk_count = mmc->max_req_size;
-
- dev_set_drvdata(dev, mmc);
-
- return 0;
-}
-
-static void wbsd_free_mmc(struct device *dev)
-{
- struct mmc_host *mmc;
- struct wbsd_host *host;
-
- mmc = dev_get_drvdata(dev);
- if (!mmc)
- return;
-
- host = mmc_priv(mmc);
- BUG_ON(host == NULL);
-
- del_timer_sync(&host->ignore_timer);
-
- mmc_free_host(mmc);
-
- dev_set_drvdata(dev, NULL);
-}
-
-/*
- * Scan for known chip id:s
- */
-
-static int __devinit wbsd_scan(struct wbsd_host *host)
-{
- int i, j, k;
- int id;
-
- /*
- * Iterate through all ports, all codes to
- * find hardware that is in our known list.
- */
- for (i = 0; i < ARRAY_SIZE(config_ports); i++) {
- if (!request_region(config_ports[i], 2, DRIVER_NAME))
- continue;
-
- for (j = 0; j < ARRAY_SIZE(unlock_codes); j++) {
- id = 0xFFFF;
-
- host->config = config_ports[i];
- host->unlock_code = unlock_codes[j];
-
- wbsd_unlock_config(host);
-
- outb(WBSD_CONF_ID_HI, config_ports[i]);
- id = inb(config_ports[i] + 1) << 8;
-
- outb(WBSD_CONF_ID_LO, config_ports[i]);
- id |= inb(config_ports[i] + 1);
-
- wbsd_lock_config(host);
-
- for (k = 0; k < ARRAY_SIZE(valid_ids); k++) {
- if (id == valid_ids[k]) {
- host->chip_id = id;
-
- return 0;
- }
- }
-
- if (id != 0xFFFF) {
- DBG("Unknown hardware (id %x) found at %x\n",
- id, config_ports[i]);
- }
- }
-
- release_region(config_ports[i], 2);
- }
-
- host->config = 0;
- host->unlock_code = 0;
-
- return -ENODEV;
-}
-
-/*
- * Allocate/free io port ranges
- */
-
-static int __devinit wbsd_request_region(struct wbsd_host *host, int base)
-{
- if (base & 0x7)
- return -EINVAL;
-
- if (!request_region(base, 8, DRIVER_NAME))
- return -EIO;
-
- host->base = base;
-
- return 0;
-}
-
-static void wbsd_release_regions(struct wbsd_host *host)
-{
- if (host->base)
- release_region(host->base, 8);
-
- host->base = 0;
-
- if (host->config)
- release_region(host->config, 2);
-
- host->config = 0;
-}
-
-/*
- * Allocate/free DMA port and buffer
- */
-
-static void __devinit wbsd_request_dma(struct wbsd_host *host, int dma)
-{
- if (dma < 0)
- return;
-
- if (request_dma(dma, DRIVER_NAME))
- goto err;
-
- /*
- * We need to allocate a special buffer in
- * order for ISA to be able to DMA to it.
- */
- host->dma_buffer = kmalloc(WBSD_DMA_SIZE,
- GFP_NOIO | GFP_DMA | __GFP_REPEAT | __GFP_NOWARN);
- if (!host->dma_buffer)
- goto free;
-
- /*
- * Translate the address to a physical address.
- */
- host->dma_addr = dma_map_single(mmc_dev(host->mmc), host->dma_buffer,
- WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
-
- /*
- * ISA DMA must be aligned on a 64k basis.
- */
- if ((host->dma_addr & 0xffff) != 0)
- goto kfree;
- /*
- * ISA cannot access memory above 16 MB.
- */
- else if (host->dma_addr >= 0x1000000)
- goto kfree;
-
- host->dma = dma;
-
- return;
-
-kfree:
- /*
- * If we've gotten here then there is some kind of alignment bug
- */
- BUG_ON(1);
-
- dma_unmap_single(mmc_dev(host->mmc), host->dma_addr,
- WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
- host->dma_addr = 0;
-
- kfree(host->dma_buffer);
- host->dma_buffer = NULL;
-
-free:
- free_dma(dma);
-
-err:
- pr_warning(DRIVER_NAME ": Unable to allocate DMA %d. "
- "Falling back on FIFO.\n", dma);
-}
-
-static void wbsd_release_dma(struct wbsd_host *host)
-{
- if (host->dma_addr) {
- dma_unmap_single(mmc_dev(host->mmc), host->dma_addr,
- WBSD_DMA_SIZE, DMA_BIDIRECTIONAL);
- }
- kfree(host->dma_buffer);
- if (host->dma >= 0)
- free_dma(host->dma);
-
- host->dma = -1;
- host->dma_buffer = NULL;
- host->dma_addr = 0;
-}
-
-/*
- * Allocate/free IRQ.
- */
-
-static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq)
-{
- int ret;
-
- /*
- * Set up tasklets. Must be done before requesting interrupt.
- */
- tasklet_init(&host->card_tasklet, wbsd_tasklet_card,
- (unsigned long)host);
- tasklet_init(&host->fifo_tasklet, wbsd_tasklet_fifo,
- (unsigned long)host);
- tasklet_init(&host->crc_tasklet, wbsd_tasklet_crc,
- (unsigned long)host);
- tasklet_init(&host->timeout_tasklet, wbsd_tasklet_timeout,
- (unsigned long)host);
- tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish,
- (unsigned long)host);
-
- /*
- * Allocate interrupt.
- */
- ret = request_irq(irq, wbsd_irq, IRQF_SHARED, DRIVER_NAME, host);
- if (ret)
- return ret;
-
- host->irq = irq;
-
- return 0;
-}
-
-static void wbsd_release_irq(struct wbsd_host *host)
-{
- if (!host->irq)
- return;
-
- free_irq(host->irq, host);
-
- host->irq = 0;
-
- tasklet_kill(&host->card_tasklet);
- tasklet_kill(&host->fifo_tasklet);
- tasklet_kill(&host->crc_tasklet);
- tasklet_kill(&host->timeout_tasklet);
- tasklet_kill(&host->finish_tasklet);
-}
-
-/*
- * Allocate all resources for the host.
- */
-
-static int __devinit wbsd_request_resources(struct wbsd_host *host,
- int base, int irq, int dma)
-{
- int ret;
-
- /*
- * Allocate I/O ports.
- */
- ret = wbsd_request_region(host, base);
- if (ret)
- return ret;
-
- /*
- * Allocate interrupt.
- */
- ret = wbsd_request_irq(host, irq);
- if (ret)
- return ret;
-
- /*
- * Allocate DMA.
- */
- wbsd_request_dma(host, dma);
-
- return 0;
-}
-
-/*
- * Release all resources for the host.
- */
-
-static void wbsd_release_resources(struct wbsd_host *host)
-{
- wbsd_release_dma(host);
- wbsd_release_irq(host);
- wbsd_release_regions(host);
-}
-
-/*
- * Configure the resources the chip should use.
- */
-
-static void wbsd_chip_config(struct wbsd_host *host)
-{
- wbsd_unlock_config(host);
-
- /*
- * Reset the chip.
- */
- wbsd_write_config(host, WBSD_CONF_SWRST, 1);
- wbsd_write_config(host, WBSD_CONF_SWRST, 0);
-
- /*
- * Select SD/MMC function.
- */
- wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
-
- /*
- * Set up card detection.
- */
- wbsd_write_config(host, WBSD_CONF_PINS, WBSD_PINS_DETECT_GP11);
-
- /*
- * Configure chip
- */
- wbsd_write_config(host, WBSD_CONF_PORT_HI, host->base >> 8);
- wbsd_write_config(host, WBSD_CONF_PORT_LO, host->base & 0xff);
-
- wbsd_write_config(host, WBSD_CONF_IRQ, host->irq);
-
- if (host->dma >= 0)
- wbsd_write_config(host, WBSD_CONF_DRQ, host->dma);
-
- /*
- * Enable and power up chip.
- */
- wbsd_write_config(host, WBSD_CONF_ENABLE, 1);
- wbsd_write_config(host, WBSD_CONF_POWER, 0x20);
-
- wbsd_lock_config(host);
-}
-
-/*
- * Check that configured resources are correct.
- */
-
-static int wbsd_chip_validate(struct wbsd_host *host)
-{
- int base, irq, dma;
-
- wbsd_unlock_config(host);
-
- /*
- * Select SD/MMC function.
- */
- wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
-
- /*
- * Read configuration.
- */
- base = wbsd_read_config(host, WBSD_CONF_PORT_HI) << 8;
- base |= wbsd_read_config(host, WBSD_CONF_PORT_LO);
-
- irq = wbsd_read_config(host, WBSD_CONF_IRQ);
-
- dma = wbsd_read_config(host, WBSD_CONF_DRQ);
-
- wbsd_lock_config(host);
-
- /*
- * Validate against given configuration.
- */
- if (base != host->base)
- return 0;
- if (irq != host->irq)
- return 0;
- if ((dma != host->dma) && (host->dma != -1))
- return 0;
-
- return 1;
-}
-
-/*
- * Powers down the SD function
- */
-
-static void wbsd_chip_poweroff(struct wbsd_host *host)
-{
- wbsd_unlock_config(host);
-
- wbsd_write_config(host, WBSD_CONF_DEVICE, DEVICE_SD);
- wbsd_write_config(host, WBSD_CONF_ENABLE, 0);
-
- wbsd_lock_config(host);
-}
-
-/*****************************************************************************\
- * *
- * Devices setup and shutdown *
- * *
-\*****************************************************************************/
-
-static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma,
- int pnp)
-{
- struct wbsd_host *host = NULL;
- struct mmc_host *mmc = NULL;
- int ret;
-
- ret = wbsd_alloc_mmc(dev);
- if (ret)
- return ret;
-
- mmc = dev_get_drvdata(dev);
- host = mmc_priv(mmc);
-
- /*
- * Scan for hardware.
- */
- ret = wbsd_scan(host);
- if (ret) {
- if (pnp && (ret == -ENODEV)) {
- pr_warning(DRIVER_NAME
- ": Unable to confirm device presence. You may "
- "experience lock-ups.\n");
- } else {
- wbsd_free_mmc(dev);
- return ret;
- }
- }
-
- /*
- * Request resources.
- */
- ret = wbsd_request_resources(host, base, irq, dma);
- if (ret) {
- wbsd_release_resources(host);
- wbsd_free_mmc(dev);
- return ret;
- }
-
- /*
- * See if chip needs to be configured.
- */
- if (pnp) {
- if ((host->config != 0) && !wbsd_chip_validate(host)) {
- pr_warning(DRIVER_NAME
- ": PnP active but chip not configured! "
- "You probably have a buggy BIOS. "
- "Configuring chip manually.\n");
- wbsd_chip_config(host);
- }
- } else
- wbsd_chip_config(host);
-
- /*
- * Power Management stuff. No idea how this works.
- * Not tested.
- */
-#ifdef CONFIG_PM
- if (host->config) {
- wbsd_unlock_config(host);
- wbsd_write_config(host, WBSD_CONF_PME, 0xA0);
- wbsd_lock_config(host);
- }
-#endif
- /*
- * Allow device to initialise itself properly.
- */
- mdelay(5);
-
- /*
- * Reset the chip into a known state.
- */
- wbsd_init_device(host);
-
- mmc_add_host(mmc);
-
- pr_info("%s: W83L51xD", mmc_hostname(mmc));
- if (host->chip_id != 0)
- printk(" id %x", (int)host->chip_id);
- printk(" at 0x%x irq %d", (int)host->base, (int)host->irq);
- if (host->dma >= 0)
- printk(" dma %d", (int)host->dma);
- else
- printk(" FIFO");
- if (pnp)
- printk(" PnP");
- printk("\n");
-
- return 0;
-}
-
-static void __devexit wbsd_shutdown(struct device *dev, int pnp)
-{
- struct mmc_host *mmc = dev_get_drvdata(dev);
- struct wbsd_host *host;
-
- if (!mmc)
- return;
-
- host = mmc_priv(mmc);
-
- mmc_remove_host(mmc);
-
- /*
- * Power down the SD/MMC function.
- */
- if (!pnp)
- wbsd_chip_poweroff(host);
-
- wbsd_release_resources(host);
-
- wbsd_free_mmc(dev);
-}
-
-/*
- * Non-PnP
- */
-
-static int __devinit wbsd_probe(struct platform_device *dev)
-{
- /* Use the module parameters for resources */
- return wbsd_init(&dev->dev, param_io, param_irq, param_dma, 0);
-}
-
-static int __devexit wbsd_remove(struct platform_device *dev)
-{
- wbsd_shutdown(&dev->dev, 0);
-
- return 0;
-}
-
-/*
- * PnP
- */
-
-#ifdef CONFIG_PNP
-
-static int __devinit
-wbsd_pnp_probe(struct pnp_dev *pnpdev, const struct pnp_device_id *dev_id)
-{
- int io, irq, dma;
-
- /*
- * Get resources from PnP layer.
- */
- io = pnp_port_start(pnpdev, 0);
- irq = pnp_irq(pnpdev, 0);
- if (pnp_dma_valid(pnpdev, 0))
- dma = pnp_dma(pnpdev, 0);
- else
- dma = -1;
-
- DBGF("PnP resources: port %3x irq %d dma %d\n", io, irq, dma);
-
- return wbsd_init(&pnpdev->dev, io, irq, dma, 1);
-}
-
-static void __devexit wbsd_pnp_remove(struct pnp_dev *dev)
-{
- wbsd_shutdown(&dev->dev, 1);
-}
-
-#endif /* CONFIG_PNP */
-
-/*
- * Power management
- */
-
-#ifdef CONFIG_PM
-
-static int wbsd_suspend(struct wbsd_host *host, pm_message_t state)
-{
- BUG_ON(host == NULL);
-
- return mmc_suspend_host(host->mmc);
-}
-
-static int wbsd_resume(struct wbsd_host *host)
-{
- BUG_ON(host == NULL);
-
- wbsd_init_device(host);
-
- return mmc_resume_host(host->mmc);
-}
-
-static int wbsd_platform_suspend(struct platform_device *dev,
- pm_message_t state)
-{
- struct mmc_host *mmc = platform_get_drvdata(dev);
- struct wbsd_host *host;
- int ret;
-
- if (mmc == NULL)
- return 0;
-
- DBGF("Suspending...\n");
-
- host = mmc_priv(mmc);
-
- ret = wbsd_suspend(host, state);
- if (ret)
- return ret;
-
- wbsd_chip_poweroff(host);
-
- return 0;
-}
-
-static int wbsd_platform_resume(struct platform_device *dev)
-{
- struct mmc_host *mmc = platform_get_drvdata(dev);
- struct wbsd_host *host;
-
- if (mmc == NULL)
- return 0;
-
- DBGF("Resuming...\n");
-
- host = mmc_priv(mmc);
-
- wbsd_chip_config(host);
-
- /*
- * Allow device to initialise itself properly.
- */
- mdelay(5);
-
- return wbsd_resume(host);
-}
-
-#ifdef CONFIG_PNP
-
-static int wbsd_pnp_suspend(struct pnp_dev *pnp_dev, pm_message_t state)
-{
- struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev);
- struct wbsd_host *host;
-
- if (mmc == NULL)
- return 0;
-
- DBGF("Suspending...\n");
-
- host = mmc_priv(mmc);
-
- return wbsd_suspend(host, state);
-}
-
-static int wbsd_pnp_resume(struct pnp_dev *pnp_dev)
-{
- struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev);
- struct wbsd_host *host;
-
- if (mmc == NULL)
- return 0;
-
- DBGF("Resuming...\n");
-
- host = mmc_priv(mmc);
-
- /*
- * See if chip needs to be configured.
- */
- if (host->config != 0) {
- if (!wbsd_chip_validate(host)) {
- pr_warning(DRIVER_NAME
- ": PnP active but chip not configured! "
- "You probably have a buggy BIOS. "
- "Configuring chip manually.\n");
- wbsd_chip_config(host);
- }
- }
-
- /*
- * Allow device to initialise itself properly.
- */
- mdelay(5);
-
- return wbsd_resume(host);
-}
-
-#endif /* CONFIG_PNP */
-
-#else /* CONFIG_PM */
-
-#define wbsd_platform_suspend NULL
-#define wbsd_platform_resume NULL
-
-#define wbsd_pnp_suspend NULL
-#define wbsd_pnp_resume NULL
-
-#endif /* CONFIG_PM */
-
-static struct platform_device *wbsd_device;
-
-static struct platform_driver wbsd_driver = {
- .probe = wbsd_probe,
- .remove = __devexit_p(wbsd_remove),
-
- .suspend = wbsd_platform_suspend,
- .resume = wbsd_platform_resume,
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- },
-};
-
-#ifdef CONFIG_PNP
-
-static struct pnp_driver wbsd_pnp_driver = {
- .name = DRIVER_NAME,
- .id_table = pnp_dev_table,
- .probe = wbsd_pnp_probe,
- .remove = __devexit_p(wbsd_pnp_remove),
-
- .suspend = wbsd_pnp_suspend,
- .resume = wbsd_pnp_resume,
-};
-
-#endif /* CONFIG_PNP */
-
-/*
- * Module loading/unloading
- */
-
-static int __init wbsd_drv_init(void)
-{
- int result;
-
- pr_info(DRIVER_NAME
- ": Winbond W83L51xD SD/MMC card interface driver\n");
- pr_info(DRIVER_NAME ": Copyright(c) Pierre Ossman\n");
-
-#ifdef CONFIG_PNP
-
- if (!param_nopnp) {
- result = pnp_register_driver(&wbsd_pnp_driver);
- if (result < 0)
- return result;
- }
-#endif /* CONFIG_PNP */
-
- if (param_nopnp) {
- result = platform_driver_register(&wbsd_driver);
- if (result < 0)
- return result;
-
- wbsd_device = platform_device_alloc(DRIVER_NAME, -1);
- if (!wbsd_device) {
- platform_driver_unregister(&wbsd_driver);
- return -ENOMEM;
- }
-
- result = platform_device_add(wbsd_device);
- if (result) {
- platform_device_put(wbsd_device);
- platform_driver_unregister(&wbsd_driver);
- return result;
- }
- }
-
- return 0;
-}
-
-static void __exit wbsd_drv_exit(void)
-{
-#ifdef CONFIG_PNP
-
- if (!param_nopnp)
- pnp_unregister_driver(&wbsd_pnp_driver);
-
-#endif /* CONFIG_PNP */
-
- if (param_nopnp) {
- platform_device_unregister(wbsd_device);
-
- platform_driver_unregister(&wbsd_driver);
- }
-
- DBG("unloaded\n");
-}
-
-module_init(wbsd_drv_init);
-module_exit(wbsd_drv_exit);
-#ifdef CONFIG_PNP
-module_param_named(nopnp, param_nopnp, uint, 0444);
-#endif
-module_param_named(io, param_io, uint, 0444);
-module_param_named(irq, param_irq, uint, 0444);
-module_param_named(dma, param_dma, int, 0444);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>");
-MODULE_DESCRIPTION("Winbond W83L51xD SD/MMC card interface driver");
-
-#ifdef CONFIG_PNP
-MODULE_PARM_DESC(nopnp, "Scan for device instead of relying on PNP. (default 0)");
-#endif
-MODULE_PARM_DESC(io, "I/O base to allocate. Must be 8 byte aligned. (default 0x248)");
-MODULE_PARM_DESC(irq, "IRQ to allocate. (default 6)");
-MODULE_PARM_DESC(dma, "DMA channel to allocate. -1 for no DMA. (default 2)");
diff --git a/ANDROID_3.4.5/drivers/mmc/host/wbsd.h b/ANDROID_3.4.5/drivers/mmc/host/wbsd.h
deleted file mode 100644
index 0877866f..00000000
--- a/ANDROID_3.4.5/drivers/mmc/host/wbsd.h
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * linux/drivers/mmc/host/wbsd.h - Winbond W83L51xD SD/MMC driver
- *
- * Copyright (C) 2004-2007 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.
- */
-
-#define LOCK_CODE 0xAA
-
-#define WBSD_CONF_SWRST 0x02
-#define WBSD_CONF_DEVICE 0x07
-#define WBSD_CONF_ID_HI 0x20
-#define WBSD_CONF_ID_LO 0x21
-#define WBSD_CONF_POWER 0x22
-#define WBSD_CONF_PME 0x23
-#define WBSD_CONF_PMES 0x24
-
-#define WBSD_CONF_ENABLE 0x30
-#define WBSD_CONF_PORT_HI 0x60
-#define WBSD_CONF_PORT_LO 0x61
-#define WBSD_CONF_IRQ 0x70
-#define WBSD_CONF_DRQ 0x74
-
-#define WBSD_CONF_PINS 0xF0
-
-#define DEVICE_SD 0x03
-
-#define WBSD_PINS_DAT3_HI 0x20
-#define WBSD_PINS_DAT3_OUT 0x10
-#define WBSD_PINS_GP11_HI 0x04
-#define WBSD_PINS_DETECT_GP11 0x02
-#define WBSD_PINS_DETECT_DAT3 0x01
-
-#define WBSD_CMDR 0x00
-#define WBSD_DFR 0x01
-#define WBSD_EIR 0x02
-#define WBSD_ISR 0x03
-#define WBSD_FSR 0x04
-#define WBSD_IDXR 0x05
-#define WBSD_DATAR 0x06
-#define WBSD_CSR 0x07
-
-#define WBSD_EINT_CARD 0x40
-#define WBSD_EINT_FIFO_THRE 0x20
-#define WBSD_EINT_CRC 0x10
-#define WBSD_EINT_TIMEOUT 0x08
-#define WBSD_EINT_PROGEND 0x04
-#define WBSD_EINT_BUSYEND 0x02
-#define WBSD_EINT_TC 0x01
-
-#define WBSD_INT_PENDING 0x80
-#define WBSD_INT_CARD 0x40
-#define WBSD_INT_FIFO_THRE 0x20
-#define WBSD_INT_CRC 0x10
-#define WBSD_INT_TIMEOUT 0x08
-#define WBSD_INT_PROGEND 0x04
-#define WBSD_INT_BUSYEND 0x02
-#define WBSD_INT_TC 0x01
-
-#define WBSD_FIFO_EMPTY 0x80
-#define WBSD_FIFO_FULL 0x40
-#define WBSD_FIFO_EMTHRE 0x20
-#define WBSD_FIFO_FUTHRE 0x10
-#define WBSD_FIFO_SZMASK 0x0F
-
-#define WBSD_MSLED 0x20
-#define WBSD_POWER_N 0x10
-#define WBSD_WRPT 0x04
-#define WBSD_CARDPRESENT 0x01
-
-#define WBSD_IDX_CLK 0x01
-#define WBSD_IDX_PBSMSB 0x02
-#define WBSD_IDX_TAAC 0x03
-#define WBSD_IDX_NSAC 0x04
-#define WBSD_IDX_PBSLSB 0x05
-#define WBSD_IDX_SETUP 0x06
-#define WBSD_IDX_DMA 0x07
-#define WBSD_IDX_FIFOEN 0x08
-#define WBSD_IDX_STATUS 0x10
-#define WBSD_IDX_RSPLEN 0x1E
-#define WBSD_IDX_RESP0 0x1F
-#define WBSD_IDX_RESP1 0x20
-#define WBSD_IDX_RESP2 0x21
-#define WBSD_IDX_RESP3 0x22
-#define WBSD_IDX_RESP4 0x23
-#define WBSD_IDX_RESP5 0x24
-#define WBSD_IDX_RESP6 0x25
-#define WBSD_IDX_RESP7 0x26
-#define WBSD_IDX_RESP8 0x27
-#define WBSD_IDX_RESP9 0x28
-#define WBSD_IDX_RESP10 0x29
-#define WBSD_IDX_RESP11 0x2A
-#define WBSD_IDX_RESP12 0x2B
-#define WBSD_IDX_RESP13 0x2C
-#define WBSD_IDX_RESP14 0x2D
-#define WBSD_IDX_RESP15 0x2E
-#define WBSD_IDX_RESP16 0x2F
-#define WBSD_IDX_CRCSTATUS 0x30
-#define WBSD_IDX_ISR 0x3F
-
-#define WBSD_CLK_375K 0x00
-#define WBSD_CLK_12M 0x01
-#define WBSD_CLK_16M 0x02
-#define WBSD_CLK_24M 0x03
-
-#define WBSD_DATA_WIDTH 0x01
-
-#define WBSD_DAT3_H 0x08
-#define WBSD_FIFO_RESET 0x04
-#define WBSD_SOFT_RESET 0x02
-#define WBSD_INC_INDEX 0x01
-
-#define WBSD_DMA_SINGLE 0x02
-#define WBSD_DMA_ENABLE 0x01
-
-#define WBSD_FIFOEN_EMPTY 0x20
-#define WBSD_FIFOEN_FULL 0x10
-#define WBSD_FIFO_THREMASK 0x0F
-
-#define WBSD_BLOCK_READ 0x80
-#define WBSD_BLOCK_WRITE 0x40
-#define WBSD_BUSY 0x20
-#define WBSD_CARDTRAFFIC 0x04
-#define WBSD_SENDCMD 0x02
-#define WBSD_RECVRES 0x01
-
-#define WBSD_RSP_SHORT 0x00
-#define WBSD_RSP_LONG 0x01
-
-#define WBSD_CRC_MASK 0x1F
-#define WBSD_CRC_OK 0x05 /* S010E (00101) */
-#define WBSD_CRC_FAIL 0x0B /* S101E (01011) */
-
-#define WBSD_DMA_SIZE 65536
-
-struct wbsd_host
-{
- struct mmc_host* mmc; /* MMC structure */
-
- spinlock_t lock; /* Mutex */
-
- int flags; /* Driver states */
-
-#define WBSD_FCARD_PRESENT (1<<0) /* Card is present */
-#define WBSD_FIGNORE_DETECT (1<<1) /* Ignore card detection */
-
- struct mmc_request* mrq; /* Current request */
-
- u8 isr; /* Accumulated ISR */
-
- struct scatterlist* cur_sg; /* Current SG entry */
- unsigned int num_sg; /* Number of entries left */
-
- unsigned int offset; /* Offset into current entry */
- unsigned int remain; /* Data left in curren entry */
-
- char* dma_buffer; /* ISA DMA buffer */
- dma_addr_t dma_addr; /* Physical address for same */
-
- int firsterr; /* See fifo functions */
-
- u8 clk; /* Current clock speed */
- unsigned char bus_width; /* Current bus width */
-
- int config; /* Config port */
- u8 unlock_code; /* Code to unlock config */
-
- int chip_id; /* ID of controller */
-
- int base; /* I/O port base */
- int irq; /* Interrupt */
- int dma; /* DMA channel */
-
- struct tasklet_struct card_tasklet; /* Tasklet structures */
- struct tasklet_struct fifo_tasklet;
- struct tasklet_struct crc_tasklet;
- struct tasklet_struct timeout_tasklet;
- struct tasklet_struct finish_tasklet;
-
- struct timer_list ignore_timer; /* Ignore detection timer */
-};