diff options
Diffstat (limited to 'drivers/mmc')
| -rw-r--r-- | drivers/mmc/Kconfig | 115 | ||||
| -rw-r--r-- | drivers/mmc/Makefile | 33 | ||||
| -rw-r--r-- | drivers/mmc/card/Kconfig | 16 | ||||
| -rw-r--r-- | drivers/mmc/card/Makefile | 11 | ||||
| -rw-r--r-- | drivers/mmc/card/block.c (renamed from drivers/mmc/mmc_block.c) | 55 | ||||
| -rw-r--r-- | drivers/mmc/card/queue.c (renamed from drivers/mmc/mmc_queue.c) | 12 | ||||
| -rw-r--r-- | drivers/mmc/card/queue.h (renamed from drivers/mmc/mmc_queue.h) | 0 | ||||
| -rw-r--r-- | drivers/mmc/core/Kconfig | 16 | ||||
| -rw-r--r-- | drivers/mmc/core/Makefile | 11 | ||||
| -rw-r--r-- | drivers/mmc/core/core.c | 729 | ||||
| -rw-r--r-- | drivers/mmc/core/core.h | 70 | ||||
| -rw-r--r-- | drivers/mmc/core/mmc.c | 537 | ||||
| -rw-r--r-- | drivers/mmc/core/mmc_ops.c | 276 | ||||
| -rw-r--r-- | drivers/mmc/core/mmc_ops.h | 27 | ||||
| -rw-r--r-- | drivers/mmc/core/sd.c | 587 | ||||
| -rw-r--r-- | drivers/mmc/core/sd_ops.c | 316 | ||||
| -rw-r--r-- | drivers/mmc/core/sd_ops.h | 25 | ||||
| -rw-r--r-- | drivers/mmc/core/sysfs.c (renamed from drivers/mmc/mmc_sysfs.c) | 11 | ||||
| -rw-r--r-- | drivers/mmc/core/sysfs.h (renamed from drivers/mmc/mmc.h) | 10 | ||||
| -rw-r--r-- | drivers/mmc/host/Kconfig | 102 | ||||
| -rw-r--r-- | drivers/mmc/host/Makefile | 18 | ||||
| -rw-r--r-- | drivers/mmc/host/at91_mci.c (renamed from drivers/mmc/at91_mci.c) | 1 | ||||
| -rw-r--r-- | drivers/mmc/host/au1xmmc.c (renamed from drivers/mmc/au1xmmc.c) | 1 | ||||
| -rw-r--r-- | drivers/mmc/host/au1xmmc.h (renamed from drivers/mmc/au1xmmc.h) | 0 | ||||
| -rw-r--r-- | drivers/mmc/host/imxmmc.c (renamed from drivers/mmc/imxmmc.c) | 1 | ||||
| -rw-r--r-- | drivers/mmc/host/imxmmc.h (renamed from drivers/mmc/imxmmc.h) | 0 | ||||
| -rw-r--r-- | drivers/mmc/host/mmci.c (renamed from drivers/mmc/mmci.c) | 1 | ||||
| -rw-r--r-- | drivers/mmc/host/mmci.h (renamed from drivers/mmc/mmci.h) | 0 | ||||
| -rw-r--r-- | drivers/mmc/host/omap.c (renamed from drivers/mmc/omap.c) | 56 | ||||
| -rw-r--r-- | drivers/mmc/host/pxamci.c (renamed from drivers/mmc/pxamci.c) | 5 | ||||
| -rw-r--r-- | drivers/mmc/host/pxamci.h (renamed from drivers/mmc/pxamci.h) | 0 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci.c (renamed from drivers/mmc/sdhci.c) | 43 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci.h (renamed from drivers/mmc/sdhci.h) | 4 | ||||
| -rw-r--r-- | drivers/mmc/host/tifm_sd.c | 1091 | ||||
| -rw-r--r-- | drivers/mmc/host/wbsd.c (renamed from drivers/mmc/wbsd.c) | 205 | ||||
| -rw-r--r-- | drivers/mmc/host/wbsd.h (renamed from drivers/mmc/wbsd.h) | 9 | ||||
| -rw-r--r-- | drivers/mmc/mmc.c | 1724 | ||||
| -rw-r--r-- | drivers/mmc/tifm_sd.c | 987 | 
38 files changed, 4001 insertions, 3104 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 12af9c71876..c0b41e8bcd9 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -2,10 +2,9 @@  # MMC subsystem configuration  # -menu "MMC/SD Card support" - -config MMC -	tristate "MMC support" +menuconfig MMC +	tristate "MMC/SD card support" +	depends on HAS_IOMEM  	help  	  MMC is the "multi-media card" bus protocol. @@ -19,110 +18,12 @@ config MMC_DEBUG  	  This is an option for use by developers; most people should  	  say N here.  This enables MMC core and driver debugging. -config MMC_BLOCK -	tristate "MMC block device driver" -	depends on MMC && 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_ARMMMCI -	tristate "ARM AMBA Multimedia Card Interface support" -	depends on ARM_AMBA && MMC -	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 && MMC -	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  (EXPERIMENTAL)" -	depends on PCI && MMC && EXPERIMENTAL -	help -	  This select 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. - -	  If unsure, say N. - -config MMC_OMAP -	tristate "TI OMAP Multimedia Card Interface support" -	depends on ARCH_OMAP && MMC -	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_WBSD -	tristate "Winbond W83L51xD SD/MMC Card Interface support" -	depends on MMC && 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 MMC -	  If unsure, say N. +source "drivers/mmc/core/Kconfig" -config MMC_AU1X -	tristate "Alchemy AU1XX0 MMC Card Interface support" -	depends on MMC && SOC_AU1200 -	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. - -config MMC_AT91 -	tristate "AT91 SD/MMC Card Interface support" -	depends on ARCH_AT91 && MMC -	help -	  This selects the AT91 MCI controller. - -	  If unsure, say N. - -config MMC_IMX -	tristate "Motorola i.MX Multimedia Card Interface support" -	depends on ARCH_IMX && MMC -	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_TIFM_SD -	tristate "TI Flash Media MMC/SD Interface support  (EXPERIMENTAL)" -	depends on MMC && 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)'. +source "drivers/mmc/card/Kconfig" -          To compile this driver as a module, choose M here: the -	  module will be called tifm_sd. +source "drivers/mmc/host/Kconfig" -endmenu +endif # MMC diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 83ffb9326a5..9979f5e9765 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -2,32 +2,11 @@  # Makefile for the kernel mmc device drivers.  # -# -# Core -# -obj-$(CONFIG_MMC)		+= mmc_core.o - -# -# Media drivers -# -obj-$(CONFIG_MMC_BLOCK)		+= mmc_block.o - -# -# Host drivers -# -obj-$(CONFIG_MMC_ARMMMCI)	+= mmci.o -obj-$(CONFIG_MMC_PXA)		+= pxamci.o -obj-$(CONFIG_MMC_IMX)		+= imxmmc.o -obj-$(CONFIG_MMC_SDHCI)		+= sdhci.o -obj-$(CONFIG_MMC_WBSD)		+= wbsd.o -obj-$(CONFIG_MMC_AU1X)		+= au1xmmc.o -obj-$(CONFIG_MMC_OMAP)		+= omap.o -obj-$(CONFIG_MMC_AT91)		+= at91_mci.o -obj-$(CONFIG_MMC_TIFM_SD)	+= tifm_sd.o - -mmc_core-y := mmc.o mmc_sysfs.o -mmc_core-$(CONFIG_BLOCK) += mmc_queue.o -  ifeq ($(CONFIG_MMC_DEBUG),y) -EXTRA_CFLAGS += -DDEBUG +	EXTRA_CFLAGS		+= -DDEBUG  endif + +obj-$(CONFIG_MMC)		+= core/ +obj-$(CONFIG_MMC)		+= card/ +obj-$(CONFIG_MMC)		+= host/ + diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig new file mode 100644 index 00000000000..9320a8c7323 --- /dev/null +++ b/drivers/mmc/card/Kconfig @@ -0,0 +1,16 @@ +# +# MMC/SD card drivers +# + +comment "MMC/SD 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. + diff --git a/drivers/mmc/card/Makefile b/drivers/mmc/card/Makefile new file mode 100644 index 00000000000..cf8c939867f --- /dev/null +++ b/drivers/mmc/card/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for MMC/SD card drivers +# + +ifeq ($(CONFIG_MMC_DEBUG),y) +	EXTRA_CFLAGS		+= -DDEBUG +endif + +obj-$(CONFIG_MMC_BLOCK)		+= mmc_block.o +mmc_block-objs			:= block.o queue.o + diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/card/block.c index 86439a0bb27..d24ab234394 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/card/block.c @@ -2,6 +2,7 @@   * Block driver for media (i.e., flash cards)   *   * Copyright 2002 Hewlett-Packard Company + * Copyright 2005-2007 Pierre Ossman   *   * Use consistent with the GNU GPL is permitted,   * provided that this copyright notice is @@ -31,13 +32,13 @@  #include <linux/mmc/card.h>  #include <linux/mmc/host.h> -#include <linux/mmc/protocol.h> -#include <linux/mmc/host.h> +#include <linux/mmc/mmc.h> +#include <linux/mmc/sd.h>  #include <asm/system.h>  #include <asm/uaccess.h> -#include "mmc_queue.h" +#include "queue.h"  /*   * max 8 partitions per card @@ -223,10 +224,9 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)  	struct mmc_blk_data *md = mq->data;  	struct mmc_card *card = md->queue.card;  	struct mmc_blk_request brq; -	int ret = 1; +	int ret = 1, sg_pos, data_size; -	if (mmc_card_claim_host(card)) -		goto flush_queue; +	mmc_claim_host(card->host);  	do {  		struct mmc_command cmd; @@ -283,6 +283,20 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)  		brq.data.sg = mq->sg;  		brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg); +		if (brq.data.blocks != +		    (req->nr_sectors >> (md->block_bits - 9))) { +			data_size = brq.data.blocks * brq.data.blksz; +			for (sg_pos = 0; sg_pos < brq.data.sg_len; sg_pos++) { +				data_size -= mq->sg[sg_pos].length; +				if (data_size <= 0) { +					mq->sg[sg_pos].length += data_size; +					sg_pos++; +					break; +				} +			} +			brq.data.sg_len = sg_pos; +		} +  		mmc_wait_for_req(card->host, &brq.mrq);  		if (brq.cmd.error) {  			printk(KERN_ERR "%s: error %d sending read/write command\n", @@ -342,7 +356,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)  		spin_unlock_irq(&md->lock);  	} while (ret); -	mmc_card_release_host(card); +	mmc_release_host(card->host);  	return 1; @@ -378,9 +392,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)  		spin_unlock_irq(&md->lock);  	} -flush_queue: - -	mmc_card_release_host(card); +	mmc_release_host(card->host);  	spin_lock_irq(&md->lock);  	while (ret) { @@ -477,11 +489,20 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)  	blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits); -	/* -	 * The CSD capacity field is in units of read_blkbits. -	 * set_capacity takes units of 512 bytes. -	 */ -	set_capacity(md->disk, card->csd.capacity << (card->csd.read_blkbits - 9)); +	if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) { +		/* +		 * The EXT_CSD sector count is in number or 512 byte +		 * sectors. +		 */ +		set_capacity(md->disk, card->ext_csd.sectors); +	} else { +		/* +		 * The CSD capacity field is in units of read_blkbits. +		 * set_capacity takes units of 512 bytes. +		 */ +		set_capacity(md->disk, +			card->csd.capacity << (card->csd.read_blkbits - 9)); +	}  	return md;   err_putdisk: @@ -502,12 +523,12 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)  	if (mmc_card_blockaddr(card))  		return 0; -	mmc_card_claim_host(card); +	mmc_claim_host(card->host);  	cmd.opcode = MMC_SET_BLOCKLEN;  	cmd.arg = 1 << md->block_bits;  	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;  	err = mmc_wait_for_cmd(card->host, &cmd, 5); -	mmc_card_release_host(card); +	mmc_release_host(card->host);  	if (err) {  		printk(KERN_ERR "%s: unable to set block size to %d: %d\n", diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/card/queue.c index c27e42645cd..2e77963db33 100644 --- a/drivers/mmc/mmc_queue.c +++ b/drivers/mmc/card/queue.c @@ -1,7 +1,8 @@  /* - *  linux/drivers/mmc/mmc_queue.c + *  linux/drivers/mmc/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 @@ -14,7 +15,7 @@  #include <linux/mmc/card.h>  #include <linux/mmc/host.h> -#include "mmc_queue.h" +#include "queue.h"  #define MMC_QUEUE_SUSPENDED	(1 << 0) @@ -179,7 +180,6 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock  	blk_cleanup_queue(mq->queue);  	return ret;  } -EXPORT_SYMBOL(mmc_init_queue);  void mmc_cleanup_queue(struct mmc_queue *mq)  { @@ -191,6 +191,9 @@ void mmc_cleanup_queue(struct mmc_queue *mq)  	q->queuedata = NULL;  	spin_unlock_irqrestore(q->queue_lock, flags); +	/* Make sure the queue isn't suspended, as that will deadlock */ +	mmc_queue_resume(mq); +  	/* Then terminate our worker thread */  	kthread_stop(mq->thread); @@ -226,7 +229,6 @@ void mmc_queue_suspend(struct mmc_queue *mq)  		down(&mq->thread_sem);  	}  } -EXPORT_SYMBOL(mmc_queue_suspend);  /**   * mmc_queue_resume - resume a previously suspended MMC request queue @@ -247,4 +249,4 @@ void mmc_queue_resume(struct mmc_queue *mq)  		spin_unlock_irqrestore(q->queue_lock, flags);  	}  } -EXPORT_SYMBOL(mmc_queue_resume); + diff --git a/drivers/mmc/mmc_queue.h b/drivers/mmc/card/queue.h index c9f139e764f..c9f139e764f 100644 --- a/drivers/mmc/mmc_queue.h +++ b/drivers/mmc/card/queue.h diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig new file mode 100644 index 00000000000..ab37a6d9d32 --- /dev/null +++ b/drivers/mmc/core/Kconfig @@ -0,0 +1,16 @@ +# +# MMC core configuration +# + +config MMC_UNSAFE_RESUME +	bool "Allow unsafe resume (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. + diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile new file mode 100644 index 00000000000..1075b02ae75 --- /dev/null +++ b/drivers/mmc/core/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for the kernel mmc core. +# + +ifeq ($(CONFIG_MMC_DEBUG),y) +	EXTRA_CFLAGS		+= -DDEBUG +endif + +obj-$(CONFIG_MMC)		+= mmc_core.o +mmc_core-y			:= core.o sysfs.o mmc.o mmc_ops.o sd.o sd_ops.o + diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c new file mode 100644 index 00000000000..7385acfa1dd --- /dev/null +++ b/drivers/mmc/core/core.c @@ -0,0 +1,729 @@ +/* + *  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-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/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 <asm/scatterlist.h> +#include <linux/scatterlist.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 "sysfs.h" + +#include "mmc_ops.h" +#include "sd_ops.h" + +extern int mmc_attach_mmc(struct mmc_host *host, u32 ocr); +extern int mmc_attach_sd(struct mmc_host *host, u32 ocr); + +/** + *	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; + +	pr_debug("%s: req done (CMD%u): %d/%d/%d: %08x %08x %08x %08x\n", +		 mmc_hostname(host), cmd->opcode, err, +		 mrq->data ? mrq->data->error : 0, +		 mrq->stop ? mrq->stop->error : 0, +		 cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); + +	if (err && cmd->retries) { +		cmd->retries--; +		cmd->error = 0; +		host->ops->request(host, mrq); +	} else if (mrq->done) { +		mrq->done(mrq); +	} +} + +EXPORT_SYMBOL(mmc_request_done); + +/** + *	mmc_start_request - start a command on a host + *	@host: MMC host to start command on + *	@mrq: MMC request to start + * + *	Queue a command on the specified host.  We expect the + *	caller to be holding the host lock with interrupts disabled. + */ +void +mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) +{ +#ifdef CONFIG_MMC_DEBUG +	unsigned int i, sz; +#endif + +	pr_debug("%s: starting CMD%u arg %08x flags %08x\n", +		 mmc_hostname(host), mrq->cmd->opcode, +		 mrq->cmd->arg, mrq->cmd->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 (i = 0;i < mrq->data->sg_len;i++) +			sz += mrq->data->sg[i].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; +		} +	} +	host->ops->request(host, mrq); +} + +EXPORT_SYMBOL(mmc_start_request); + +static void mmc_wait_done(struct mmc_request *mrq) +{ +	complete(mrq->done_data); +} + +int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) +{ +	DECLARE_COMPLETION_ONSTACK(complete); + +	mrq->done_data = &complete; +	mrq->done = mmc_wait_done; + +	mmc_start_request(host, mrq); + +	wait_for_completion(&complete); + +	return 0; +} + +EXPORT_SYMBOL(mmc_wait_for_req); + +/** + *	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; + +	BUG_ON(!host->claimed); + +	memset(&mrq, 0, sizeof(struct mmc_request)); + +	memset(cmd->resp, 0, sizeof(cmd->resp)); +	cmd->retries = retries; + +	mrq.cmd = cmd; +	cmd->data = NULL; + +	mmc_wait_for_req(host, &mrq); + +	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 + *	@write: flag to differentiate reads from writes + */ +void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card, +			  int write) +{ +	unsigned int mult; + +	/* +	 * 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 (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; +		timeout_us += data->timeout_clks * 1000 / +			(card->host->ios.clock / 1000); + +		if (write) +			limit_us = 250000; +		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; +		} +	} +} +EXPORT_SYMBOL(mmc_set_data_timeout); + +/** + *	__mmc_claim_host - exclusively claim a host + *	@host: mmc host to claim + *	@card: mmc card to claim host for + * + *	Claim a host for a set of operations.  If a valid card + *	is passed and this wasn't the last card selected, select + *	the card before returning. + * + *	Note: you should use mmc_card_claim_host or mmc_claim_host. + */ +void mmc_claim_host(struct mmc_host *host) +{ +	DECLARE_WAITQUEUE(wait, current); +	unsigned long flags; + +	add_wait_queue(&host->wq, &wait); +	spin_lock_irqsave(&host->lock, flags); +	while (1) { +		set_current_state(TASK_UNINTERRUPTIBLE); +		if (!host->claimed) +			break; +		spin_unlock_irqrestore(&host->lock, flags); +		schedule(); +		spin_lock_irqsave(&host->lock, flags); +	} +	set_current_state(TASK_RUNNING); +	host->claimed = 1; +	spin_unlock_irqrestore(&host->lock, flags); +	remove_wait_queue(&host->wq, &wait); +} + +EXPORT_SYMBOL(mmc_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; + +	BUG_ON(!host->claimed); + +	spin_lock_irqsave(&host->lock, flags); +	host->claimed = 0; +	spin_unlock_irqrestore(&host->lock, flags); + +	wake_up(&host->wq); +} + +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; + +	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); + +	host->ops->set_ios(host, ios); +} + +/* + * Control chip select pin on a host. + */ +void mmc_set_chip_select(struct mmc_host *host, int mode) +{ +	host->ios.chip_select = mode; +	mmc_set_ios(host); +} + +/* + * Sets the host clock to the highest possible frequency that + * is below "hz". + */ +void mmc_set_clock(struct mmc_host *host, unsigned int hz) +{ +	WARN_ON(hz < host->f_min); + +	if (hz > host->f_max) +		hz = host->f_max; + +	host->ios.clock = hz; +	mmc_set_ios(host); +} + +/* + * Change the bus mode (open drain/push-pull) of a host. + */ +void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode) +{ +	host->ios.bus_mode = mode; +	mmc_set_ios(host); +} + +/* + * Change data bus width of a host. + */ +void mmc_set_bus_width(struct mmc_host *host, unsigned int width) +{ +	host->ios.bus_width = width; +	mmc_set_ios(host); +} + +/* + * 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; + +	ocr &= host->ocr_avail; + +	bit = ffs(ocr); +	if (bit) { +		bit -= 1; + +		ocr &= 3 << bit; + +		host->ios.vdd = bit; +		mmc_set_ios(host); +	} else { +		ocr = 0; +	} + +	return ocr; +} + +/* + * Select timing parameters for host. + */ +void mmc_set_timing(struct mmc_host *host, unsigned int timing) +{ +	host->ios.timing = timing; +	mmc_set_ios(host); +} + +/* + * Allocate a new MMC card + */ +struct mmc_card *mmc_alloc_card(struct mmc_host *host) +{ +	struct mmc_card *card; + +	card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL); +	if (!card) +		return ERR_PTR(-ENOMEM); + +	mmc_init_card(card, host); + +	return card; +} + +/* + * 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 = fls(host->ocr_avail) - 1; + +	host->ios.vdd = bit; +	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; +	host->ios.chip_select = MMC_CS_DONTCARE; +	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); + +	mmc_delay(1); + +	host->ios.clock = host->f_min; +	host->ios.power_mode = MMC_POWER_ON; +	mmc_set_ios(host); + +	mmc_delay(2); +} + +static void mmc_power_off(struct mmc_host *host) +{ +	host->ios.clock = 0; +	host->ios.vdd = 0; +	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); +} + +/* + * 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; + +	BUG_ON(!host); +	BUG_ON(!ops); + +	BUG_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); +} + +/* + * Remove the current bus handler from a host. Assumes that there are + * no interesting cards left, so the bus is powered down. + */ +void mmc_detach_bus(struct mmc_host *host) +{ +	unsigned long flags; + +	BUG_ON(!host); + +	BUG_ON(!host->claimed); +	BUG_ON(!host->bus_ops); + +	spin_lock_irqsave(&host->lock, flags); + +	host->bus_dead = 1; + +	spin_unlock_irqrestore(&host->lock, flags); + +	mmc_power_off(host); + +	mmc_bus_put(host); +} + +/* + * Cleanup when the last reference to the bus operator is dropped. + */ +void __mmc_release_bus(struct mmc_host *host) +{ +	BUG_ON(!host); +	BUG_ON(host->bus_refs); +	BUG_ON(!host->bus_dead); + +	host->bus_ops = NULL; +} + +/** + *	mmc_detect_change - process change of state on a MMC socket + *	@host: host which changed state. + *	@delay: optional delay to wait before detection (jiffies) + * + *	All we know is that card(s) have been inserted or removed + *	from the socket(s).  We don't know which socket or cards. + */ +void mmc_detect_change(struct mmc_host *host, unsigned long delay) +{ +#ifdef CONFIG_MMC_DEBUG +	unsigned long flags; +	spin_lock_irqsave(&host->lock, flags); +	BUG_ON(host->removed); +	spin_unlock_irqrestore(&host->lock, flags); +#endif + +	mmc_schedule_delayed_work(&host->detect, delay); +} + +EXPORT_SYMBOL(mmc_detect_change); + + +static void mmc_rescan(struct work_struct *work) +{ +	struct mmc_host *host = +		container_of(work, struct mmc_host, detect.work); +	u32 ocr; +	int err; + +	mmc_bus_get(host); + +	if (host->bus_ops == NULL) { +		/* +		 * Only we can add a new handler, so it's safe to +		 * release the lock here. +		 */ +		mmc_bus_put(host); + +		mmc_claim_host(host); + +		mmc_power_up(host); +		mmc_go_idle(host); + +		mmc_send_if_cond(host, host->ocr_avail); + +		err = mmc_send_app_op_cond(host, 0, &ocr); +		if (err == MMC_ERR_NONE) { +			if (mmc_attach_sd(host, ocr)) +				mmc_power_off(host); +		} else { +			/* +			 * If we fail to detect any SD cards then try +			 * searching for MMC cards. +			 */ +			err = mmc_send_op_cond(host, 0, &ocr); +			if (err == MMC_ERR_NONE) { +				if (mmc_attach_mmc(host, ocr)) +					mmc_power_off(host); +			} else { +				mmc_power_off(host); +				mmc_release_host(host); +			} +		} +	} else { +		if (host->bus_ops->detect && !host->bus_dead) +			host->bus_ops->detect(host); + +		mmc_bus_put(host); +	} +} + + +/** + *	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) +{ +	struct mmc_host *host; + +	host = mmc_alloc_host_sysfs(extra, dev); +	if (host) { +		spin_lock_init(&host->lock); +		init_waitqueue_head(&host->wq); +		INIT_DELAYED_WORK(&host->detect, mmc_rescan); + +		/* +		 * By default, hosts do not support SGIO or large requests. +		 * They have to set these according to their abilities. +		 */ +		host->max_hw_segs = 1; +		host->max_phys_segs = 1; +		host->max_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; +	} + +	return host; +} + +EXPORT_SYMBOL(mmc_alloc_host); + +/** + *	mmc_add_host - initialise host hardware + *	@host: mmc host + */ +int mmc_add_host(struct mmc_host *host) +{ +	int ret; + +	ret = mmc_add_host_sysfs(host); +	if (ret == 0) { +		mmc_power_off(host); +		mmc_detect_change(host, 0); +	} + +	return ret; +} + +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. + */ +void mmc_remove_host(struct mmc_host *host) +{ +#ifdef CONFIG_MMC_DEBUG +	unsigned long flags; +	spin_lock_irqsave(&host->lock, flags); +	host->removed = 1; +	spin_unlock_irqrestore(&host->lock, flags); +#endif + +	mmc_flush_scheduled_work(); + +	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); + +	BUG_ON(host->card); + +	mmc_power_off(host); +	mmc_remove_host_sysfs(host); +} + +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) +{ +	mmc_free_host_sysfs(host); +} + +EXPORT_SYMBOL(mmc_free_host); + +#ifdef CONFIG_PM + +/** + *	mmc_suspend_host - suspend a host + *	@host: mmc host + *	@state: suspend mode (PM_SUSPEND_xxx) + */ +int mmc_suspend_host(struct mmc_host *host, pm_message_t state) +{ +	mmc_flush_scheduled_work(); + +	mmc_bus_get(host); +	if (host->bus_ops && !host->bus_dead) { +		if (host->bus_ops->suspend) +			host->bus_ops->suspend(host); +		if (!host->bus_ops->resume) { +			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); + +	return 0; +} + +EXPORT_SYMBOL(mmc_suspend_host); + +/** + *	mmc_resume_host - resume a previously suspended host + *	@host: mmc host + */ +int mmc_resume_host(struct mmc_host *host) +{ +	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); +	} +	mmc_bus_put(host); + +	/* +	 * We add a slight delay here so that resume can progress +	 * in parallel. +	 */ +	mmc_detect_change(host, 1); + +	return 0; +} + +EXPORT_SYMBOL(mmc_resume_host); + +#endif + +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h new file mode 100644 index 00000000000..177264d090a --- /dev/null +++ b/drivers/mmc/core/core.h @@ -0,0 +1,70 @@ +/* + *  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 { +	void (*remove)(struct mmc_host *); +	void (*detect)(struct mmc_host *); +	void (*suspend)(struct mmc_host *); +	void (*resume)(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_release_bus(struct mmc_host *host); + +static inline void mmc_bus_get(struct mmc_host *host) +{ +	unsigned long flags; + +	spin_lock_irqsave(&host->lock, flags); +	host->bus_refs++; +	spin_unlock_irqrestore(&host->lock, flags); +} + +static inline void mmc_bus_put(struct mmc_host *host) +{ +	unsigned long flags; + +	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); +} + +void mmc_set_chip_select(struct mmc_host *host, int mode); +void mmc_set_clock(struct mmc_host *host, unsigned int hz); +void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode); +void mmc_set_bus_width(struct mmc_host *host, unsigned int width); +u32 mmc_select_voltage(struct mmc_host *host, u32 ocr); +void mmc_set_timing(struct mmc_host *host, unsigned int timing); + +struct mmc_card *mmc_alloc_card(struct mmc_host *host); + +static inline void mmc_delay(unsigned int ms) +{ +	if (ms < 1000 / HZ) { +		cond_resched(); +		mdelay(ms); +	} else { +		msleep(ms); +	} +} + +#endif + diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c new file mode 100644 index 00000000000..42cc2867ed7 --- /dev/null +++ b/drivers/mmc/core/mmc.c @@ -0,0 +1,537 @@ +/* + *  linux/drivers/mmc/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/mmc/host.h> +#include <linux/mmc/card.h> +#include <linux/mmc/mmc.h> + +#include "core.h" +#include "sysfs.h" +#include "mmc_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: +		printk("%s: card has unknown MMCA version %d\n", +			mmc_hostname(card->host), card->csd.mmca_vsn); +		return -EINVAL; +	} + +	return 0; +} + +/* + * 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; + +	/* +	 * We only understand CSD structure v1.1 and v1.2. +	 * v1.2 has extra information in bits 15, 11 and 10. +	 */ +	csd_struct = UNSTUFF_BITS(resp, 126, 2); +	if (csd_struct != 1 && csd_struct != 2) { +		printk("%s: unrecognised CSD structure version %d\n", +			mmc_hostname(card->host), csd_struct); +		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); + +	return 0; +} + +/* + * Read and decode extended CSD. + */ +static int mmc_read_ext_csd(struct mmc_card *card) +{ +	int err; +	u8 *ext_csd; + +	BUG_ON(!card); + +	err = MMC_ERR_FAILED; + +	if (card->csd.mmca_vsn < CSD_SPEC_VER_4) +		return MMC_ERR_NONE; + +	/* +	 * 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) { +		printk(KERN_ERR "%s: could not allocate a buffer to " +			"receive the ext_csd. mmc v4 cards will be " +			"treated as v3.\n", mmc_hostname(card->host)); +		return MMC_ERR_FAILED; +	} + +	err = mmc_send_ext_csd(card, ext_csd); +	if (err != MMC_ERR_NONE) { +		/* +		 * High capacity cards should have this "magic" size +		 * stored in their CSD. +		 */ +		if (card->csd.capacity == (4096 * 512)) { +			printk(KERN_ERR "%s: unable to read EXT_CSD " +				"on a possible high capacity card. " +				"Card will be ignored.\n", +				mmc_hostname(card->host)); +		} else { +			printk(KERN_WARNING "%s: unable to read " +				"EXT_CSD, performance might " +				"suffer.\n", +				mmc_hostname(card->host)); +			err = MMC_ERR_NONE; +		} +		goto out; +	} + +	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; +	if (card->ext_csd.sectors) +		mmc_card_set_blockaddr(card); + +	switch (ext_csd[EXT_CSD_CARD_TYPE]) { +	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 */ +		printk(KERN_WARNING "%s: card is mmc v4 but doesn't " +			"support any high-speed modes.\n", +			mmc_hostname(card->host)); +		goto out; +	} + +out: +	kfree(ext_csd); + +	return err; +} + +/* + * Handle the detection and initialisation of a card. + * + * In the case of a resume, "curcard" 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]; +	unsigned int max_dtr; + +	BUG_ON(!host); +	BUG_ON(!host->claimed); + +	/* +	 * 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); + +	/* The extra bit indicates that we support high capacity */ +	err = mmc_send_op_cond(host, ocr | (1 << 30), NULL); +	if (err != MMC_ERR_NONE) +		goto err; + +	/* +	 * Fetch CID from card. +	 */ +	err = mmc_all_send_cid(host, cid); +	if (err != MMC_ERR_NONE) +		goto err; + +	if (oldcard) { +		if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) +			goto err; + +		card = oldcard; +	} else { +		/* +		 * Allocate card structure. +		 */ +		card = mmc_alloc_card(host); +		if (IS_ERR(card)) +			goto err; + +		card->type = MMC_TYPE_MMC; +		card->rca = 1; +		memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); +	} + +	/* +	 * Set card RCA. +	 */ +	err = mmc_set_relative_addr(card); +	if (err != MMC_ERR_NONE) +		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 != MMC_ERR_NONE) +			goto free_card; + +		err = mmc_decode_csd(card); +		if (err < 0) +			goto free_card; +		err = mmc_decode_cid(card); +		if (err < 0) +			goto free_card; +	} + +	/* +	 * Select card, as all following commands rely on that. +	 */ +	err = mmc_select_card(card); +	if (err != MMC_ERR_NONE) +		goto free_card; + +	if (!oldcard) { +		/* +		 * Fetch and process extened CSD. +		 */ +		err = mmc_read_ext_csd(card); +		if (err != MMC_ERR_NONE) +			goto free_card; +	} + +	/* +	 * Activate high speed (if supported) +	 */ +	if ((card->ext_csd.hs_max_dtr != 0) && +		(host->caps & MMC_CAP_MMC_HIGHSPEED)) { +		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, +			EXT_CSD_HS_TIMING, 1); +		if (err != MMC_ERR_NONE) +			goto free_card; + +		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)) { +		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); + +	/* +	 * Activate wide bus (if supported). +	 */ +	if ((card->csd.mmca_vsn >= CSD_SPEC_VER_4) && +		(host->caps & MMC_CAP_4_BIT_DATA)) { +		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, +			EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4); +		if (err != MMC_ERR_NONE) +			goto free_card; + +		mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); +	} + +	if (!oldcard) +		host->card = card; + +	return MMC_ERR_NONE; + +free_card: +	if (!oldcard) +		mmc_remove_card(card); +err: + +	return MMC_ERR_FAILED; +} + +/* + * 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 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_send_status(host->card, NULL); + +	mmc_release_host(host); + +	if (err != MMC_ERR_NONE) { +		mmc_remove_card(host->card); +		host->card = NULL; + +		mmc_claim_host(host); +		mmc_detach_bus(host); +		mmc_release_host(host); +	} +} + +#ifdef CONFIG_MMC_UNSAFE_RESUME + +/* + * Suspend callback from host. + */ +static void mmc_suspend(struct mmc_host *host) +{ +	BUG_ON(!host); +	BUG_ON(!host->card); + +	mmc_claim_host(host); +	mmc_deselect_cards(host); +	host->card->state &= ~MMC_STATE_HIGHSPEED; +	mmc_release_host(host); +} + +/* + * 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 void mmc_resume(struct mmc_host *host) +{ +	int err; + +	BUG_ON(!host); +	BUG_ON(!host->card); + +	mmc_claim_host(host); + +	err = mmc_sd_init_card(host, host->ocr, host->card); +	if (err != MMC_ERR_NONE) { +		mmc_remove_card(host->card); +		host->card = NULL; + +		mmc_detach_bus(host); +	} + +	mmc_release_host(host); +} + +#else + +#define mmc_suspend NULL +#define mmc_resume NULL + +#endif + +static const struct mmc_bus_ops mmc_ops = { +	.remove = mmc_remove, +	.detect = mmc_detect, +	.suspend = mmc_suspend, +	.resume = mmc_resume, +}; + +/* + * Starting point for MMC card init. + */ +int mmc_attach_mmc(struct mmc_host *host, u32 ocr) +{ +	int err; + +	BUG_ON(!host); +	BUG_ON(!host->claimed); + +	mmc_attach_bus(host, &mmc_ops); + +	/* +	 * Sanity check the voltages that the card claims to +	 * support. +	 */ +	if (ocr & 0x7F) { +		printk(KERN_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) +		goto err; + +	/* +	 * Detect and init the card. +	 */ +	err = mmc_sd_init_card(host, host->ocr, NULL); +	if (err != MMC_ERR_NONE) +		goto err; + +	mmc_release_host(host); + +	err = mmc_register_card(host->card); +	if (err) +		goto reclaim_host; + +	return 0; + +reclaim_host: +	mmc_claim_host(host); +	mmc_remove_card(host->card); +	host->card = NULL; +err: +	mmc_detach_bus(host); +	mmc_release_host(host); + +	return 0; +} + diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c new file mode 100644 index 00000000000..7dd720fa589 --- /dev/null +++ b/drivers/mmc/core/mmc_ops.c @@ -0,0 +1,276 @@ +/* + *  linux/drivers/mmc/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/types.h> +#include <asm/scatterlist.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; + +	BUG_ON(!host); + +	memset(&cmd, 0, sizeof(struct mmc_command)); + +	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 != MMC_ERR_NONE) +		return err; + +	return MMC_ERR_NONE; +} + +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_go_idle(struct mmc_host *host) +{ +	int err; +	struct mmc_command cmd; + +	mmc_set_chip_select(host, MMC_CS_HIGH); + +	mmc_delay(1); + +	memset(&cmd, 0, sizeof(struct mmc_command)); + +	cmd.opcode = MMC_GO_IDLE_STATE; +	cmd.arg = 0; +	cmd.flags = MMC_RSP_NONE | MMC_CMD_BC; + +	err = mmc_wait_for_cmd(host, &cmd, 0); + +	mmc_delay(1); + +	mmc_set_chip_select(host, MMC_CS_DONTCARE); + +	mmc_delay(1); + +	return err; +} + +int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) +{ +	struct mmc_command cmd; +	int i, err = 0; + +	BUG_ON(!host); + +	memset(&cmd, 0, sizeof(struct mmc_command)); + +	cmd.opcode = MMC_SEND_OP_COND; +	cmd.arg = ocr; +	cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; + +	for (i = 100; i; i--) { +		err = mmc_wait_for_cmd(host, &cmd, 0); +		if (err != MMC_ERR_NONE) +			break; + +		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) +			break; + +		err = MMC_ERR_TIMEOUT; + +		mmc_delay(10); +	} + +	if (rocr) +		*rocr = cmd.resp[0]; + +	return err; +} + +int mmc_all_send_cid(struct mmc_host *host, u32 *cid) +{ +	int err; +	struct mmc_command cmd; + +	BUG_ON(!host); +	BUG_ON(!cid); + +	memset(&cmd, 0, sizeof(struct mmc_command)); + +	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 != MMC_ERR_NONE) +		return err; + +	memcpy(cid, cmd.resp, sizeof(u32) * 4); + +	return MMC_ERR_NONE; +} + +int mmc_set_relative_addr(struct mmc_card *card) +{ +	int err; +	struct mmc_command cmd; + +	BUG_ON(!card); +	BUG_ON(!card->host); + +	memset(&cmd, 0, sizeof(struct mmc_command)); + +	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 != MMC_ERR_NONE) +		return err; + +	return MMC_ERR_NONE; +} + +int mmc_send_csd(struct mmc_card *card, u32 *csd) +{ +	int err; +	struct mmc_command cmd; + +	BUG_ON(!card); +	BUG_ON(!card->host); +	BUG_ON(!csd); + +	memset(&cmd, 0, sizeof(struct mmc_command)); + +	cmd.opcode = MMC_SEND_CSD; +	cmd.arg = card->rca << 16; +	cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; + +	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); +	if (err != MMC_ERR_NONE) +		return err; + +	memcpy(csd, cmd.resp, sizeof(u32) * 4); + +	return MMC_ERR_NONE; +} + +int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd) +{ +	struct mmc_request mrq; +	struct mmc_command cmd; +	struct mmc_data data; +	struct scatterlist sg; + +	BUG_ON(!card); +	BUG_ON(!card->host); +	BUG_ON(!ext_csd); + +	memset(&mrq, 0, sizeof(struct mmc_request)); +	memset(&cmd, 0, sizeof(struct mmc_command)); +	memset(&data, 0, sizeof(struct mmc_data)); + +	mrq.cmd = &cmd; +	mrq.data = &data; + +	cmd.opcode = MMC_SEND_EXT_CSD; +	cmd.arg = 0; +	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; + +	data.blksz = 512; +	data.blocks = 1; +	data.flags = MMC_DATA_READ; +	data.sg = &sg; +	data.sg_len = 1; + +	sg_init_one(&sg, ext_csd, 512); + +	mmc_set_data_timeout(&data, card, 0); + +	mmc_wait_for_req(card->host, &mrq); + +	if (cmd.error != MMC_ERR_NONE) +		return cmd.error; +	if (data.error != MMC_ERR_NONE) +		return data.error; + +	return MMC_ERR_NONE; +} + +int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value) +{ +	int err; +	struct mmc_command cmd; + +	BUG_ON(!card); +	BUG_ON(!card->host); + +	memset(&cmd, 0, sizeof(struct mmc_command)); + +	cmd.opcode = MMC_SWITCH; +	cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | +		  (index << 16) | +		  (value << 8) | +		  set; +	cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; + +	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); +	if (err != MMC_ERR_NONE) +		return err; + +	return MMC_ERR_NONE; +} + +int mmc_send_status(struct mmc_card *card, u32 *status) +{ +	int err; +	struct mmc_command cmd; + +	BUG_ON(!card); +	BUG_ON(!card->host); + +	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; + +	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES); +	if (err != MMC_ERR_NONE) +		return err; + +	if (status) +		*status = cmd.resp[0]; + +	return MMC_ERR_NONE; +} + diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h new file mode 100644 index 00000000000..7a481e8ca5e --- /dev/null +++ b/drivers/mmc/core/mmc_ops.h @@ -0,0 +1,27 @@ +/* + *  linux/drivers/mmc/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_switch(struct mmc_card *card, u8 set, u8 index, u8 value); +int mmc_send_status(struct mmc_card *card, u32 *status); + +#endif + diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c new file mode 100644 index 00000000000..c1dfd03d559 --- /dev/null +++ b/drivers/mmc/core/sd.c @@ -0,0 +1,587 @@ +/* + *  linux/drivers/mmc/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/mmc/host.h> +#include <linux/mmc/card.h> +#include <linux/mmc/mmc.h> + +#include "core.h" +#include "sysfs.h" +#include "mmc_ops.h" +#include "sd_ops.h" + +#include "core.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 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); +		break; +	case 1: +		/* +		 * This is a block-addressed SDHC 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); + +		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; +		break; +	default: +		printk("%s: unrecognised CSD structure version %d\n", +			mmc_hostname(card->host), csd_struct); +		return -EINVAL; +	} + +	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]; + +	BUG_ON(!mmc_card_sd(card)); + +	resp[3] = card->raw_scr[1]; +	resp[2] = card->raw_scr[0]; + +	scr_struct = UNSTUFF_BITS(resp, 60, 4); +	if (scr_struct != 0) { +		printk("%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); + +	return 0; +} + +/* + * Fetches and decodes switch information + */ +static int mmc_read_switch(struct mmc_card *card) +{ +	int err; +	u8 *status; + +	err = MMC_ERR_FAILED; + +	status = kmalloc(64, GFP_KERNEL); +	if (!status) { +		printk("%s: could not allocate a buffer for switch " +		       "capabilities.\n", +			mmc_hostname(card->host)); +		return err; +	} + +	err = mmc_sd_switch(card, 0, 0, 1, status); +	if (err != MMC_ERR_NONE) { +		/* +		 * Card not supporting high-speed will ignore the +		 * command. +		 */ +		err = MMC_ERR_NONE; +		goto out; +	} + +	if (status[13] & 0x02) +		card->sw_caps.hs_max_dtr = 50000000; + +out: +	kfree(status); + +	return err; +} + +/* + * Test if the card supports high-speed mode and, if so, switch to it. + */ +static int mmc_switch_hs(struct mmc_card *card) +{ +	int err; +	u8 *status; + +	if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED)) +		return MMC_ERR_NONE; + +	if (card->sw_caps.hs_max_dtr == 0) +		return MMC_ERR_NONE; + +	err = MMC_ERR_FAILED; + +	status = kmalloc(64, GFP_KERNEL); +	if (!status) { +		printk("%s: could not allocate a buffer for switch " +		       "capabilities.\n", +			mmc_hostname(card->host)); +		return err; +	} + +	err = mmc_sd_switch(card, 1, 0, 1, status); +	if (err != MMC_ERR_NONE) +		goto out; + +	if ((status[16] & 0xF) != 1) { +		printk(KERN_WARNING "%s: Problem switching card " +			"into high-speed mode!\n", +			mmc_hostname(card->host)); +	} else { +		mmc_card_set_highspeed(card); +		mmc_set_timing(card->host, MMC_TIMING_SD_HS); +	} + +out: +	kfree(status); + +	return err; +} + +/* + * Handle the detection and initialisation of a card. + * + * In the case of a resume, "curcard" 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]; +	unsigned int max_dtr; + +	BUG_ON(!host); +	BUG_ON(!host->claimed); + +	/* +	 * 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 == MMC_ERR_NONE) +		ocr |= 1 << 30; + +	err = mmc_send_app_op_cond(host, ocr, NULL); +	if (err != MMC_ERR_NONE) +		goto err; + +	/* +	 * Fetch CID from card. +	 */ +	err = mmc_all_send_cid(host, cid); +	if (err != MMC_ERR_NONE) +		goto err; + +	if (oldcard) { +		if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) +			goto err; + +		card = oldcard; +	} else { +		/* +		 * Allocate card structure. +		 */ +		card = mmc_alloc_card(host); +		if (IS_ERR(card)) +			goto err; + +		card->type = MMC_TYPE_SD; +		memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); +	} + +	/* +	 * Set card RCA. +	 */ +	err = mmc_send_relative_addr(host, &card->rca); +	if (err != MMC_ERR_NONE) +		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 != MMC_ERR_NONE) +			goto free_card; + +		err = mmc_decode_csd(card); +		if (err < 0) +			goto free_card; + +		mmc_decode_cid(card); +	} + +	/* +	 * Select card, as all following commands rely on that. +	 */ +	err = mmc_select_card(card); +	if (err != MMC_ERR_NONE) +		goto free_card; + +	if (!oldcard) { +		/* +		 * Fetch SCR from card. +		 */ +		err = mmc_app_send_scr(card, card->raw_scr); +		if (err != MMC_ERR_NONE) +			goto free_card; + +		err = mmc_decode_scr(card); +		if (err < 0) +			goto free_card; + +		/* +		 * Fetch switch information from card. +		 */ +		err = mmc_read_switch(card); +		if (err != MMC_ERR_NONE) +			goto free_card; +	} + +	/* +	 * Attempt to change to high-speed (if supported) +	 */ +	err = mmc_switch_hs(card); +	if (err != MMC_ERR_NONE) +		goto free_card; + +	/* +	 * Compute bus speed. +	 */ +	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; +	} + +	mmc_set_clock(host, max_dtr); + +	/* +	 * 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 != MMC_ERR_NONE) +			goto free_card; + +		mmc_set_bus_width(host, MMC_BUS_WIDTH_4); +	} + +	if (!oldcard) +		host->card = card; + +	return MMC_ERR_NONE; + +free_card: +	if (!oldcard) +		mmc_remove_card(card); +err: + +	return MMC_ERR_FAILED; +} + +/* + * 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 callback from host. + */ +static void mmc_sd_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_send_status(host->card, NULL); + +	mmc_release_host(host); + +	if (err != MMC_ERR_NONE) { +		mmc_remove_card(host->card); +		host->card = NULL; + +		mmc_claim_host(host); +		mmc_detach_bus(host); +		mmc_release_host(host); +	} +} + +#ifdef CONFIG_MMC_UNSAFE_RESUME + +/* + * Suspend callback from host. + */ +static void mmc_sd_suspend(struct mmc_host *host) +{ +	BUG_ON(!host); +	BUG_ON(!host->card); + +	mmc_claim_host(host); +	mmc_deselect_cards(host); +	host->card->state &= ~MMC_STATE_HIGHSPEED; +	mmc_release_host(host); +} + +/* + * 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 void mmc_sd_resume(struct mmc_host *host) +{ +	int err; + +	BUG_ON(!host); +	BUG_ON(!host->card); + +	mmc_claim_host(host); + +	err = mmc_sd_init_card(host, host->ocr, host->card); +	if (err != MMC_ERR_NONE) { +		mmc_remove_card(host->card); +		host->card = NULL; + +		mmc_detach_bus(host); +	} + +	mmc_release_host(host); +} + +#else + +#define mmc_sd_suspend NULL +#define mmc_sd_resume NULL + +#endif + +static const struct mmc_bus_ops mmc_sd_ops = { +	.remove = mmc_sd_remove, +	.detect = mmc_sd_detect, +	.suspend = mmc_sd_suspend, +	.resume = mmc_sd_resume, +}; + +/* + * Starting point for SD card init. + */ +int mmc_attach_sd(struct mmc_host *host, u32 ocr) +{ +	int err; + +	BUG_ON(!host); +	BUG_ON(!host->claimed); + +	mmc_attach_bus(host, &mmc_sd_ops); + +	/* +	 * Sanity check the voltages that the card claims to +	 * support. +	 */ +	if (ocr & 0x7F) { +		printk(KERN_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) { +		printk(KERN_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) +		goto err; + +	/* +	 * Detect and init the card. +	 */ +	err = mmc_sd_init_card(host, host->ocr, NULL); +	if (err != MMC_ERR_NONE) +		goto err; + +	mmc_release_host(host); + +	err = mmc_register_card(host->card); +	if (err) +		goto reclaim_host; + +	return 0; + +reclaim_host: +	mmc_claim_host(host); +	mmc_remove_card(host->card); +	host->card = NULL; +err: +	mmc_detach_bus(host); +	mmc_release_host(host); + +	return 0; +} + diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c new file mode 100644 index 00000000000..9697ce58110 --- /dev/null +++ b/drivers/mmc/core/sd_ops.c @@ -0,0 +1,316 @@ +/* + *  linux/drivers/mmc/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/types.h> +#include <asm/scatterlist.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" + +/** + *	mmc_wait_for_app_cmd - start an application command and wait for + 			       completion + *	@host: MMC host to start command + *	@rca: RCA 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; + +	int i, err; + +	BUG_ON(!cmd); +	BUG_ON(retries < 0); + +	err = MMC_ERR_INVALID; + +	/* +	 * 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++) { +		memset(&mrq, 0, sizeof(struct mmc_request)); + +		err = mmc_app_cmd(host, card); +		if (err != MMC_ERR_NONE) +			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 == MMC_ERR_NONE) +			break; +	} + +	return err; +} + +EXPORT_SYMBOL(mmc_wait_for_app_cmd); + +int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) +{ +	int err; +	struct mmc_command cmd; + +	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_R1 | MMC_CMD_AC; +	} else { +		cmd.arg = 0; +		cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR; +	} + +	err = mmc_wait_for_cmd(host, &cmd, 0); +	if (err != MMC_ERR_NONE) +		return err; + +	/* Check that card supported application commands */ +	if (!(cmd.resp[0] & R1_APP_CMD)) +		return MMC_ERR_FAILED; + +	return MMC_ERR_NONE; +} + +int mmc_app_set_bus_width(struct mmc_card *card, int width) +{ +	int err; +	struct mmc_command cmd; + +	BUG_ON(!card); +	BUG_ON(!card->host); + +	memset(&cmd, 0, sizeof(struct mmc_command)); + +	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 MMC_ERR_INVALID; +	} + +	err = mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES); +	if (err != MMC_ERR_NONE) +		return err; + +	return MMC_ERR_NONE; +} + +int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) +{ +	struct mmc_command cmd; +	int i, err = 0; + +	BUG_ON(!host); + +	memset(&cmd, 0, sizeof(struct mmc_command)); + +	cmd.opcode = SD_APP_OP_COND; +	cmd.arg = ocr; +	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 != MMC_ERR_NONE) +			break; + +		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) +			break; + +		err = MMC_ERR_TIMEOUT; + +		mmc_delay(10); +	} + +	if (rocr) +		*rocr = cmd.resp[0]; + +	return err; +} + +int mmc_send_if_cond(struct mmc_host *host, u32 ocr) +{ +	struct mmc_command cmd; +	int err; +	static const u8 test_pattern = 0xAA; + +	/* +	 * 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_R7 | MMC_CMD_BCR; + +	err = mmc_wait_for_cmd(host, &cmd, 0); +	if (err != MMC_ERR_NONE) +		return err; + +	if ((cmd.resp[0] & 0xFF) != test_pattern) +		return MMC_ERR_FAILED; + +	return MMC_ERR_NONE; +} + +int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca) +{ +	int err; +	struct mmc_command cmd; + +	BUG_ON(!host); +	BUG_ON(!rca); + +	memset(&cmd, 0, sizeof(struct mmc_command)); + +	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 != MMC_ERR_NONE) +		return err; + +	*rca = cmd.resp[0] >> 16; + +	return MMC_ERR_NONE; +} + +int mmc_app_send_scr(struct mmc_card *card, u32 *scr) +{ +	int err; +	struct mmc_request mrq; +	struct mmc_command cmd; +	struct mmc_data data; +	struct scatterlist sg; + +	BUG_ON(!card); +	BUG_ON(!card->host); +	BUG_ON(!scr); + +	err = mmc_app_cmd(card->host, card); +	if (err != MMC_ERR_NONE) +		return err; + +	memset(&mrq, 0, sizeof(struct mmc_request)); +	memset(&cmd, 0, sizeof(struct mmc_command)); +	memset(&data, 0, sizeof(struct mmc_data)); + +	mrq.cmd = &cmd; +	mrq.data = &data; + +	cmd.opcode = SD_APP_SEND_SCR; +	cmd.arg = 0; +	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, scr, 8); + +	mmc_set_data_timeout(&data, card, 0); + +	mmc_wait_for_req(card->host, &mrq); + +	if (cmd.error != MMC_ERR_NONE) +		return cmd.error; +	if (data.error != MMC_ERR_NONE) +		return data.error; + +	scr[0] = ntohl(scr[0]); +	scr[1] = ntohl(scr[1]); + +	return MMC_ERR_NONE; +} + +int mmc_sd_switch(struct mmc_card *card, int mode, int group, +	u8 value, u8 *resp) +{ +	struct mmc_request mrq; +	struct mmc_command cmd; +	struct mmc_data data; +	struct scatterlist sg; + +	BUG_ON(!card); +	BUG_ON(!card->host); + +	mode = !!mode; +	value &= 0xF; + +	memset(&mrq, 0, sizeof(struct mmc_request)); +	memset(&cmd, 0, sizeof(struct mmc_command)); +	memset(&data, 0, sizeof(struct mmc_data)); + +	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_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, 0); + +	mmc_wait_for_req(card->host, &mrq); + +	if (cmd.error != MMC_ERR_NONE) +		return cmd.error; +	if (data.error != MMC_ERR_NONE) +		return data.error; + +	return MMC_ERR_NONE; +} + diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h new file mode 100644 index 00000000000..1240fddba5e --- /dev/null +++ b/drivers/mmc/core/sd_ops.h @@ -0,0 +1,25 @@ +/* + *  linux/drivers/mmc/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_cmd(struct mmc_host *host, struct mmc_card *card); +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); + +#endif + diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/core/sysfs.c index e0e82d849d5..843b1fbba55 100644 --- a/drivers/mmc/mmc_sysfs.c +++ b/drivers/mmc/core/sysfs.c @@ -1,5 +1,5 @@  /* - *  linux/drivers/mmc/mmc_sysfs.c + *  linux/drivers/mmc/core/sysfs.c   *   *  Copyright (C) 2003 Russell King, All Rights Reserved.   * @@ -18,7 +18,7 @@  #include <linux/mmc/card.h>  #include <linux/mmc/host.h> -#include "mmc.h" +#include "sysfs.h"  #define dev_to_mmc_card(d)	container_of(d, struct mmc_card, dev)  #define to_mmc_driver(d)	container_of(d, struct mmc_driver, drv) @@ -72,12 +72,11 @@ static void mmc_release_card(struct device *dev)  /*   * This currently matches any MMC driver to any MMC card - drivers   * themselves make the decision whether to drive this card in their - * probe method.  However, we force "bad" cards to fail. + * probe method.   */  static int mmc_bus_match(struct device *dev, struct device_driver *drv)  { -	struct mmc_card *card = dev_to_mmc_card(dev); -	return !mmc_card_bad(card); +	return 1;  }  static int @@ -217,6 +216,8 @@ int mmc_register_card(struct mmc_card *card)  				device_del(&card->dev);  		}  	} +	if (ret == 0) +		mmc_card_set_present(card);  	return ret;  } diff --git a/drivers/mmc/mmc.h b/drivers/mmc/core/sysfs.h index 149affe0b68..80e29b35828 100644 --- a/drivers/mmc/mmc.h +++ b/drivers/mmc/core/sysfs.h @@ -1,15 +1,16 @@  /* - *  linux/drivers/mmc/mmc.h + *  linux/drivers/mmc/core/sysfs.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_H -#define _MMC_H -/* core-internal functions */ +#ifndef _MMC_CORE_SYSFS_H +#define _MMC_CORE_SYSFS_H +  void mmc_init_card(struct mmc_card *card, struct mmc_host *host);  int mmc_register_card(struct mmc_card *card);  void mmc_remove_card(struct mmc_card *card); @@ -22,4 +23,5 @@ void mmc_free_host_sysfs(struct mmc_host *host);  int mmc_schedule_work(struct work_struct *work);  int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay);  void mmc_flush_scheduled_work(void); +  #endif diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig new file mode 100644 index 00000000000..e23082fe88d --- /dev/null +++ b/drivers/mmc/host/Kconfig @@ -0,0 +1,102 @@ +# +# MMC/SD host controller drivers +# + +comment "MMC/SD 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  (EXPERIMENTAL)" +	depends on PCI && EXPERIMENTAL +	help +	  This select 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. + +	  If unsure, say N. + +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_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 SOC_AU1200 +	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. + +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_IMX +	tristate "Motorola i.MX Multimedia Card Interface support" +	depends on ARCH_IMX +	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_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. + diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile new file mode 100644 index 00000000000..6685f64345b --- /dev/null +++ b/drivers/mmc/host/Makefile @@ -0,0 +1,18 @@ +# +# Makefile for MMC/SD host controller drivers +# + +ifeq ($(CONFIG_MMC_DEBUG),y) +	EXTRA_CFLAGS		+= -DDEBUG +endif + +obj-$(CONFIG_MMC_ARMMMCI)	+= mmci.o +obj-$(CONFIG_MMC_PXA)		+= pxamci.o +obj-$(CONFIG_MMC_IMX)		+= imxmmc.o +obj-$(CONFIG_MMC_SDHCI)		+= sdhci.o +obj-$(CONFIG_MMC_WBSD)		+= wbsd.o +obj-$(CONFIG_MMC_AU1X)		+= au1xmmc.o +obj-$(CONFIG_MMC_OMAP)		+= omap.o +obj-$(CONFIG_MMC_AT91)		+= at91_mci.o +obj-$(CONFIG_MMC_TIFM_SD)	+= tifm_sd.o + diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/host/at91_mci.c index 459f4b4fede..e37943c314c 100644 --- a/drivers/mmc/at91_mci.c +++ b/drivers/mmc/host/at91_mci.c @@ -67,7 +67,6 @@  #include <linux/atmel_pdc.h>  #include <linux/mmc/host.h> -#include <linux/mmc/protocol.h>  #include <asm/io.h>  #include <asm/irq.h> diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index b834be261ab..b7156a4555b 100644 --- a/drivers/mmc/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -42,7 +42,6 @@  #include <linux/dma-mapping.h>  #include <linux/mmc/host.h> -#include <linux/mmc/protocol.h>  #include <asm/io.h>  #include <asm/mach-au1x00/au1000.h>  #include <asm/mach-au1x00/au1xxx_dbdma.h> diff --git a/drivers/mmc/au1xmmc.h b/drivers/mmc/host/au1xmmc.h index 341cbdf0bac..341cbdf0bac 100644 --- a/drivers/mmc/au1xmmc.h +++ b/drivers/mmc/host/au1xmmc.h diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/host/imxmmc.c index 0de5c9e94e7..7ee2045acbe 100644 --- a/drivers/mmc/imxmmc.c +++ b/drivers/mmc/host/imxmmc.c @@ -41,7 +41,6 @@  #include <linux/dma-mapping.h>  #include <linux/mmc/host.h>  #include <linux/mmc/card.h> -#include <linux/mmc/protocol.h>  #include <linux/delay.h>  #include <asm/dma.h> diff --git a/drivers/mmc/imxmmc.h b/drivers/mmc/host/imxmmc.h index e5339e334db..e5339e334db 100644 --- a/drivers/mmc/imxmmc.h +++ b/drivers/mmc/host/imxmmc.h diff --git a/drivers/mmc/mmci.c b/drivers/mmc/host/mmci.c index 5941dd951e8..d11c2d23cee 100644 --- a/drivers/mmc/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -17,7 +17,6 @@  #include <linux/err.h>  #include <linux/highmem.h>  #include <linux/mmc/host.h> -#include <linux/mmc/protocol.h>  #include <linux/amba/bus.h>  #include <linux/clk.h> diff --git a/drivers/mmc/mmci.h b/drivers/mmc/host/mmci.h index 6d7eadc9a67..6d7eadc9a67 100644 --- a/drivers/mmc/mmci.h +++ b/drivers/mmc/host/mmci.h diff --git a/drivers/mmc/omap.c b/drivers/mmc/host/omap.c index 1e96a2f6502..1914e65d4db 100644 --- a/drivers/mmc/omap.c +++ b/drivers/mmc/host/omap.c @@ -22,7 +22,6 @@  #include <linux/spinlock.h>  #include <linux/timer.h>  #include <linux/mmc/host.h> -#include <linux/mmc/protocol.h>  #include <linux/mmc/card.h>  #include <linux/clk.h> @@ -605,7 +604,7 @@ static void mmc_omap_switch_handler(struct work_struct *work)  	}  	if (mmc_omap_cover_is_open(host)) {  		if (!complained) { -			dev_info(mmc_dev(host->mmc), "cover is open"); +			dev_info(mmc_dev(host->mmc), "cover is open\n");  			complained = 1;  		}  		if (mmc_omap_enable_poll) @@ -937,48 +936,55 @@ static void mmc_omap_power(struct mmc_omap_host *host, int on)  	}  } -static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +static int mmc_omap_calc_divisor(struct mmc_host *mmc, struct mmc_ios *ios)  {  	struct mmc_omap_host *host = mmc_priv(mmc); +	int func_clk_rate = clk_get_rate(host->fclk);  	int dsor; -	int realclock, i; - -	realclock = ios->clock;  	if (ios->clock == 0) -		dsor = 0; -	else { -		int func_clk_rate = clk_get_rate(host->fclk); - -		dsor = func_clk_rate / realclock; -		if (dsor < 1) -			dsor = 1; +		return 0; -		if (func_clk_rate / dsor > realclock) -			dsor++; +	dsor = func_clk_rate / ios->clock; +	if (dsor < 1) +		dsor = 1; -		if (dsor > 250) -			dsor = 250; +	if (func_clk_rate / dsor > ios->clock)  		dsor++; -		if (ios->bus_width == MMC_BUS_WIDTH_4) -			dsor |= 1 << 15; -	} +	if (dsor > 250) +		dsor = 250; +	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_host *host = mmc_priv(mmc); +	int dsor; +	int i; + +	dsor = mmc_omap_calc_divisor(mmc, ios); +	host->bus_mode = ios->bus_mode; +	host->hw_bus_mode = host->bus_mode;  	switch (ios->power_mode) {  	case MMC_POWER_OFF:  		mmc_omap_power(host, 0);  		break;  	case MMC_POWER_UP: -	case MMC_POWER_ON: +		/* Cannot touch dsor yet, just power up MMC */  		mmc_omap_power(host, 1); +		return; +	case MMC_POWER_ON:  		dsor |= 1 << 11;  		break;  	} -	host->bus_mode = ios->bus_mode; -	host->hw_bus_mode = host->bus_mode; -  	clk_enable(host->fclk);  	/* On insanely high arm_per frequencies something sometimes @@ -987,7 +993,7 @@ static void mmc_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  	 * Writing to the CON register twice seems to do the trick. */  	for (i = 0; i < 2; i++)  		OMAP_MMC_WRITE(host, CON, dsor); -	if (ios->power_mode == MMC_POWER_UP) { +	if (ios->power_mode == MMC_POWER_ON) {  		/* Send clock cycles, poll completion */  		OMAP_MMC_WRITE(host, IE, 0);  		OMAP_MMC_WRITE(host, STAT, 0xffff); diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/host/pxamci.c index 9774fc68b61..d97d3864b57 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -24,7 +24,6 @@  #include <linux/interrupt.h>  #include <linux/dma-mapping.h>  #include <linux/mmc/host.h> -#include <linux/mmc/protocol.h>  #include <asm/dma.h>  #include <asm/io.h> @@ -369,14 +368,14 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  		if (CLOCKRATE / clk > ios->clock)  			clk <<= 1;  		host->clkrt = fls(clk) - 1; -		pxa_set_cken(CKEN12_MMC, 1); +		pxa_set_cken(CKEN_MMC, 1);  		/*  		 * we write clkrt on the next command  		 */  	} else {  		pxamci_stop_clock(host); -		pxa_set_cken(CKEN12_MMC, 0); +		pxa_set_cken(CKEN_MMC, 0);  	}  	if (host->power_mode != ios->power_mode) { diff --git a/drivers/mmc/pxamci.h b/drivers/mmc/host/pxamci.h index 1b163220df2..1b163220df2 100644 --- a/drivers/mmc/pxamci.h +++ b/drivers/mmc/host/pxamci.h diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/host/sdhci.c index d749f08601b..ff5bf73cdd2 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1,7 +1,7 @@  /*   *  linux/drivers/mmc/sdhci.c - Secure Digital Host Controller Interface driver   * - *  Copyright (C) 2005-2006 Pierre Ossman, 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 as published by @@ -15,7 +15,6 @@  #include <linux/dma-mapping.h>  #include <linux/mmc/host.h> -#include <linux/mmc/protocol.h>  #include <asm/scatterlist.h> @@ -247,14 +246,13 @@ static void sdhci_read_block_pio(struct sdhci_host *host)  			chunk_remain = min(blksize, 4);  		} -		size = min(host->size, host->remain); -		size = min(size, chunk_remain); +		size = min(host->remain, chunk_remain);  		chunk_remain -= size;  		blksize -= size;  		host->offset += size;  		host->remain -= size; -		host->size -= size; +  		while (size) {  			*buffer = data & 0xFF;  			buffer++; @@ -289,14 +287,13 @@ static void sdhci_write_block_pio(struct sdhci_host *host)  	buffer = sdhci_sg_to_buffer(host) + host->offset;  	while (blksize) { -		size = min(host->size, host->remain); -		size = min(size, chunk_remain); +		size = min(host->remain, chunk_remain);  		chunk_remain -= size;  		blksize -= size;  		host->offset += size;  		host->remain -= size; -		host->size -= size; +  		while (size) {  			data >>= 8;  			data |= (u32)*buffer << 24; @@ -325,7 +322,7 @@ static void sdhci_transfer_pio(struct sdhci_host *host)  	BUG_ON(!host->data); -	if (host->size == 0) +	if (host->num_sg == 0)  		return;  	if (host->data->flags & MMC_DATA_READ) @@ -339,10 +336,8 @@ static void sdhci_transfer_pio(struct sdhci_host *host)  		else  			sdhci_write_block_pio(host); -		if (host->size == 0) +		if (host->num_sg == 0)  			break; - -		BUG_ON(host->num_sg == 0);  	}  	DBG("PIO transfer complete.\n"); @@ -408,8 +403,6 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)  		writel(sg_dma_address(data->sg), host->ioaddr + SDHCI_DMA_ADDRESS);  	} else { -		host->size = data->blksz * data->blocks; -  		host->cur_sg = data->sg;  		host->num_sg = data->sg_len; @@ -473,10 +466,6 @@ static void sdhci_finish_data(struct sdhci_host *host)  			"though there were blocks left.\n",  			mmc_hostname(host->mmc));  		data->error = MMC_ERR_FAILED; -	} else if (host->size != 0) { -		printk(KERN_ERR "%s: %d bytes were left untransferred.\n", -			mmc_hostname(host->mmc), host->size); -		data->error = MMC_ERR_FAILED;  	}  	DBG("Ending data transfer (%d bytes)\n", data->bytes_xfered); @@ -669,20 +658,16 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)  	pwr = SDHCI_POWER_ON; -	switch (power) { -	case MMC_VDD_170: -	case MMC_VDD_180: -	case MMC_VDD_190: +	switch (1 << power) { +	case MMC_VDD_165_195:  		pwr |= SDHCI_POWER_180;  		break; -	case MMC_VDD_290: -	case MMC_VDD_300: -	case MMC_VDD_310: +	case MMC_VDD_29_30: +	case MMC_VDD_30_31:  		pwr |= SDHCI_POWER_300;  		break; -	case MMC_VDD_320: -	case MMC_VDD_330: -	case MMC_VDD_340: +	case MMC_VDD_32_33: +	case MMC_VDD_33_34:  		pwr |= SDHCI_POWER_330;  		break;  	default: @@ -1294,7 +1279,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)  	if (caps & SDHCI_CAN_VDD_300)  		mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;  	if (caps & SDHCI_CAN_VDD_180) -		mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19; +		mmc->ocr_avail |= MMC_VDD_165_195;  	if (mmc->ocr_avail == 0) {  		printk(KERN_ERR "%s: Hardware doesn't report any " diff --git a/drivers/mmc/sdhci.h b/drivers/mmc/host/sdhci.h index e324f0a623d..7400f4bc114 100644 --- a/drivers/mmc/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -1,7 +1,7 @@  /*   *  linux/drivers/mmc/sdhci.h - Secure Digital Host Controller Interface driver   * - *  Copyright (C) 2005 Pierre Ossman, 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 as published by @@ -187,8 +187,6 @@ struct sdhci_host {  	int			offset;		/* Offset into current sg */  	int			remain;		/* Bytes left in current */ -	int			size;		/* Remaining bytes in transfer */ -  	char			slot_descr[20];	/* Name for reservations */  	int			irq;		/* Device IRQ */ diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c new file mode 100644 index 00000000000..8b736e96844 --- /dev/null +++ b/drivers/mmc/host/tifm_sd.c @@ -0,0 +1,1091 @@ +/* + *  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 <asm/io.h> + +#define DRIVER_NAME "tifm_sd" +#define DRIVER_VERSION "0.8" + +static int no_dma = 0; +static int 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, KM_BIO_DST_IRQ) + 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, KM_BIO_DST_IRQ); +} + +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, KM_BIO_SRC_IRQ) + 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, KM_BIO_SRC_IRQ); +} + +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) +				    && 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[host->sg_pos].page, 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, KM_BIO_SRC_IRQ) + src_off; +	unsigned char *dst_buf = kmap_atomic(dst, KM_BIO_DST_IRQ) + dst_off; + +	memcpy(dst_buf, src_buf, count); + +	kunmap_atomic(dst_buf - dst_off, KM_BIO_DST_IRQ); +	kunmap_atomic(src_buf - src_off, KM_BIO_SRC_IRQ); +} + +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[host->sg_pos].page, 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(host->bounce_buf.page, +					  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, host->bounce_buf.page, +					  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 != MMC_ERR_NONE) +		goto finish_request; + +	if (!(host->cmd_flags & CMD_READY)) +		return; + +	if (cmd->data) { +		if (cmd->data->error != MMC_ERR_NONE) { +			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 = MMC_ERR_NONE; +	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 = MMC_ERR_TIMEOUT; +			else if (host_status & TIFM_MMCSD_CCRC) +				cmd_error = MMC_ERR_BADCRC; + +			if (cmd->data) { +				if (host_status & TIFM_MMCSD_DTO) +					cmd->data->error = MMC_ERR_TIMEOUT; +				else if (host_status & TIFM_MMCSD_DCRC) +					cmd->data->error = MMC_ERR_BADCRC; +			} + +			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) { +		spin_unlock_irqrestore(&sock->lock, flags); +		goto err_out; +	} + +	if (host->req) { +		printk(KERN_ERR "%s : unfinished request detected\n", +		       sock->dev.bus_id); +		spin_unlock_irqrestore(&sock->lock, flags); +		goto err_out; +	} + +	host->cmd_flags = 0; +	host->block_pos = 0; +	host->sg_pos = 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)) { +				printk(KERN_ERR "%s : scatterlist map failed\n", +				       sock->dev.bus_id); +				spin_unlock_irqrestore(&sock->lock, flags); +				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) { +				printk(KERN_ERR "%s : scatterlist map failed\n", +				       sock->dev.bus_id); +				tifm_unmap_sg(sock, &host->bounce_buf, 1, +					      r_data->flags & MMC_DATA_WRITE +					      ? PCI_DMA_TODEVICE +					      : PCI_DMA_FROMDEVICE); +				spin_unlock_irqrestore(&sock->lock, flags); +				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: +	mrq->cmd->error = MMC_ERR_TIMEOUT; +	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) { +		printk(KERN_ERR " %s : no request to complete?\n", +		       sock->dev.bus_id); +		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; + +	printk(KERN_ERR +	       "%s : card failed to respond for a long period of time " +	       "(%x, %x)\n", +	       host->dev->dev.bus_id, 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) { +		printk(KERN_ERR "%s : controller failed to reset\n", +		       sock->dev.bus_id); +		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) { +		printk(KERN_ERR +		       "%s : card not ready - probe failed on initialization\n", +		       sock->dev.bus_id); +		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))) { +		printk(KERN_WARNING "%s : card gone, unexpectedly\n", +		       sock->dev.bus_id); +		return rc; +	} + +	mmc = mmc_alloc_host(sizeof(struct tifm_sd), &sock->dev); +	if (!mmc) +		return -ENOMEM; + +	host = mmc_priv(mmc); +	host->no_dma = no_dma; +	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_CAP_MULTIWRITE; +	mmc->f_min = 20000000 / 60; +	mmc->f_max = 24000000; + +	mmc->max_blk_count = 2048; +	mmc->max_hw_segs = mmc->max_blk_count; +	mmc->max_blk_size = min(TIFM_MMCSD_MAX_BLOCK_SIZE, PAGE_SIZE); +	mmc->max_seg_size = mmc->max_blk_count * mmc->max_blk_size; +	mmc->max_req_size = mmc->max_seg_size; +	mmc->max_phys_segs = mmc->max_hw_segs; + +	sock->card_event = tifm_sd_card_event; +	sock->data_event = tifm_sd_data_event; +	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 = MMC_ERR_TIMEOUT; +		if (host->req->stop) +			host->req->stop->error = MMC_ERR_TIMEOUT; +		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), state); +} + +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/drivers/mmc/wbsd.c b/drivers/mmc/host/wbsd.c index 05ccfc43168..867ca6a6929 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -1,7 +1,7 @@  /*   *  linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver   * - *  Copyright (C) 2004-2006 Pierre Ossman, All Rights Reserved. + *  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 @@ -33,7 +33,6 @@  #include <linux/pnp.h>  #include <linux/highmem.h>  #include <linux/mmc/host.h> -#include <linux/mmc/protocol.h>  #include <asm/io.h>  #include <asm/dma.h> @@ -178,9 +177,8 @@ static void wbsd_init_device(struct wbsd_host *host)  	ier = 0;  	ier |= WBSD_EINT_CARD;  	ier |= WBSD_EINT_FIFO_THRE; -	ier |= WBSD_EINT_CCRC; -	ier |= WBSD_EINT_TIMEOUT;  	ier |= WBSD_EINT_CRC; +	ier |= WBSD_EINT_TIMEOUT;  	ier |= WBSD_EINT_TC;  	outb(ier, host->base + WBSD_EIR); @@ -278,90 +276,36 @@ static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)  static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)  { -	unsigned int len, i, size; +	unsigned int len, i;  	struct scatterlist *sg;  	char *dmabuf = host->dma_buffer;  	char *sgbuf; -	size = host->size; -  	sg = data->sg;  	len = data->sg_len; -	/* -	 * 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++) {  		sgbuf = page_address(sg[i].page) + sg[i].offset; -		if (size < sg[i].length) -			memcpy(dmabuf, sgbuf, size); -		else -			memcpy(dmabuf, sgbuf, sg[i].length); +		memcpy(dmabuf, sgbuf, sg[i].length);  		dmabuf += sg[i].length; - -		if (size < sg[i].length) -			size = 0; -		else -			size -= sg[i].length; - -		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); - -	host->size -= size;  }  static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)  { -	unsigned int len, i, size; +	unsigned int len, i;  	struct scatterlist *sg;  	char *dmabuf = host->dma_buffer;  	char *sgbuf; -	size = host->size; -  	sg = data->sg;  	len = data->sg_len; -	/* -	 * 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++) {  		sgbuf = page_address(sg[i].page) + sg[i].offset; -		if (size < sg[i].length) -			memcpy(sgbuf, dmabuf, size); -		else -			memcpy(sgbuf, dmabuf, sg[i].length); +		memcpy(sgbuf, dmabuf, sg[i].length);  		dmabuf += sg[i].length; - -		if (size < sg[i].length) -			size = 0; -		else -			size -= sg[i].length; - -		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); - -	host->size -= size;  }  /* @@ -484,7 +428,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)  	/*  	 * Handle excessive data.  	 */ -	if (data->bytes_xfered == host->size) +	if (host->num_sg == 0)  		return;  	buffer = wbsd_sg_to_buffer(host) + host->offset; @@ -514,31 +458,14 @@ static void wbsd_empty_fifo(struct wbsd_host *host)  			data->bytes_xfered++;  			/* -			 * Transfer done? -			 */ -			if (data->bytes_xfered == host->size) -				return; - -			/*  			 * End of scatter list entry?  			 */  			if (host->remain == 0) {  				/*  				 * Get next entry. Check if last.  				 */ -				if (!wbsd_next_sg(host)) { -					/* -					 * We should never reach this point. -					 * It means that we're trying to -					 * transfer more blocks than can fit -					 * into the scatter list. -					 */ -					BUG_ON(1); - -					host->size = data->bytes_xfered; - +				if (!wbsd_next_sg(host))  					return; -				}  				buffer = wbsd_sg_to_buffer(host);  			} @@ -550,7 +477,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)  	 * hardware problem. The chip doesn't trigger  	 * FIFO threshold interrupts properly.  	 */ -	if ((host->size - data->bytes_xfered) < 16) +	if ((data->blocks * data->blksz - data->bytes_xfered) < 16)  		tasklet_schedule(&host->fifo_tasklet);  } @@ -564,7 +491,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)  	 * Check that we aren't being called after the  	 * entire buffer has been transfered.  	 */ -	if (data->bytes_xfered == host->size) +	if (host->num_sg == 0)  		return;  	buffer = wbsd_sg_to_buffer(host) + host->offset; @@ -594,31 +521,14 @@ static void wbsd_fill_fifo(struct wbsd_host *host)  			data->bytes_xfered++;  			/* -			 * Transfer done? -			 */ -			if (data->bytes_xfered == host->size) -				return; - -			/*  			 * End of scatter list entry?  			 */  			if (host->remain == 0) {  				/*  				 * Get next entry. Check if last.  				 */ -				if (!wbsd_next_sg(host)) { -					/* -					 * We should never reach this point. -					 * It means that we're trying to -					 * transfer more blocks than can fit -					 * into the scatter list. -					 */ -					BUG_ON(1); - -					host->size = data->bytes_xfered; - +				if (!wbsd_next_sg(host))  					return; -				}  				buffer = wbsd_sg_to_buffer(host);  			} @@ -638,6 +548,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)  	u16 blksize;  	u8 setup;  	unsigned long dmaflags; +	unsigned int size;  	DBGF("blksz %04x blks %04x flags %08x\n",  		data->blksz, data->blocks, data->flags); @@ -647,7 +558,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)  	/*  	 * Calculate size.  	 */ -	host->size = data->blocks * data->blksz; +	size = data->blocks * data->blksz;  	/*  	 * Check timeout values for overflow. @@ -705,8 +616,8 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)  		/*  		 * The buffer for DMA is only 64 kB.  		 */ -		BUG_ON(host->size > 0x10000); -		if (host->size > 0x10000) { +		BUG_ON(size > 0x10000); +		if (size > 0x10000) {  			data->error = MMC_ERR_INVALID;  			return;  		} @@ -729,7 +640,7 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)  		else  			set_dma_mode(host->dma, DMA_MODE_WRITE & ~0x40);  		set_dma_addr(host->dma, host->dma_addr); -		set_dma_count(host->dma, host->size); +		set_dma_count(host->dma, size);  		enable_dma(host->dma);  		release_dma_lock(dmaflags); @@ -812,6 +723,10 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)  		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?  		 */ @@ -820,7 +735,8 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)  				"%d bytes left.\n",  				mmc_hostname(host->mmc), count); -			data->error = MMC_ERR_FAILED; +			if (data->error == MMC_ERR_NONE) +				data->error = MMC_ERR_FAILED;  		} else {  			/*  			 * Transfer data from DMA buffer to @@ -828,8 +744,11 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)  			 */  			if (data->flags & MMC_DATA_READ)  				wbsd_dma_to_sg(host, data); +		} -			data->bytes_xfered = host->size; +		if (data->error != MMC_ERR_NONE) { +			if (data->bytes_xfered) +				data->bytes_xfered -= data->blksz;  		}  	} @@ -869,24 +788,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)  		goto done;  	} -	/* -	 * Does the request include data? -	 */  	if (cmd->data) { -		wbsd_prepare_data(host, cmd->data); - -		if (cmd->data->error != MMC_ERR_NONE) -			goto done; -	} - -	wbsd_send_command(host, cmd); - -	/* -	 * If this is a data transfer the request -	 * will be finished after the data has -	 * transfered. -	 */ -	if (cmd->data && (cmd->error == MMC_ERR_NONE)) {  		/*  		 * The hardware is so delightfully stupid that it has a list  		 * of "data" commands. If a command isn't on this list, it'll @@ -918,14 +820,30 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)  				"supported by this controller.\n",  				mmc_hostname(host->mmc), cmd->opcode);  #endif -			cmd->data->error = MMC_ERR_INVALID; - -			if (cmd->data->stop) -				wbsd_send_command(host, cmd->data->stop); +			cmd->error = MMC_ERR_INVALID;  			goto done;  		}; +	} + +	/* +	 * Does the request include data? +	 */ +	if (cmd->data) { +		wbsd_prepare_data(host, cmd->data); + +		if (cmd->data->error != MMC_ERR_NONE) +			goto done; +	} + +	wbsd_send_command(host, cmd); +	/* +	 * If this is a data transfer the request +	 * will be finished after the data has +	 * transfered. +	 */ +	if (cmd->data && (cmd->error == MMC_ERR_NONE)) {  		/*  		 * Dirty fix for hardware bug.  		 */ @@ -1167,7 +1085,7 @@ static void wbsd_tasklet_fifo(unsigned long param)  	/*  	 * Done?  	 */ -	if (host->size == data->bytes_xfered) { +	if (host->num_sg == 0) {  		wbsd_write_index(host, WBSD_IDX_FIFOEN, 0);  		tasklet_schedule(&host->finish_tasklet);  	} @@ -1245,30 +1163,6 @@ end:  	spin_unlock(&host->lock);  } -static void wbsd_tasklet_block(unsigned long param) -{ -	struct wbsd_host *host = (struct wbsd_host *)param; -	struct mmc_data *data; - -	spin_lock(&host->lock); - -	if ((wbsd_read_index(host, WBSD_IDX_CRCSTATUS) & WBSD_CRC_MASK) != -		WBSD_CRC_OK) { -		data = wbsd_get_data(host); -		if (!data) -			goto end; - -		DBGF("CRC error\n"); - -		data->error = MMC_ERR_BADCRC; - -		tasklet_schedule(&host->finish_tasklet); -	} - -end: -	spin_unlock(&host->lock); -} -  /*   * Interrupt handling   */ @@ -1299,8 +1193,6 @@ static irqreturn_t wbsd_irq(int irq, void *dev_id)  		tasklet_hi_schedule(&host->crc_tasklet);  	if (isr & WBSD_INT_TIMEOUT)  		tasklet_hi_schedule(&host->timeout_tasklet); -	if (isr & WBSD_INT_BUSYEND) -		tasklet_hi_schedule(&host->block_tasklet);  	if (isr & WBSD_INT_TC)  		tasklet_schedule(&host->finish_tasklet); @@ -1601,8 +1493,6 @@ static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq)  			(unsigned long)host);  	tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish,  			(unsigned long)host); -	tasklet_init(&host->block_tasklet, wbsd_tasklet_block, -			(unsigned long)host);  	return 0;  } @@ -1621,7 +1511,6 @@ static void __devexit wbsd_release_irq(struct wbsd_host *host)  	tasklet_kill(&host->crc_tasklet);  	tasklet_kill(&host->timeout_tasklet);  	tasklet_kill(&host->finish_tasklet); -	tasklet_kill(&host->block_tasklet);  }  /* diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/host/wbsd.h index d06718b0e2a..873bda1e59b 100644 --- a/drivers/mmc/wbsd.h +++ b/drivers/mmc/host/wbsd.h @@ -1,7 +1,7 @@  /*   *  linux/drivers/mmc/wbsd.h - Winbond W83L51xD SD/MMC driver   * - *  Copyright (C) 2004-2005 Pierre Ossman, All Rights Reserved. + *  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 @@ -46,10 +46,10 @@  #define WBSD_EINT_CARD		0x40  #define WBSD_EINT_FIFO_THRE	0x20 -#define WBSD_EINT_CCRC		0x10 +#define WBSD_EINT_CRC		0x10  #define WBSD_EINT_TIMEOUT	0x08  #define WBSD_EINT_PROGEND	0x04 -#define WBSD_EINT_CRC		0x02 +#define WBSD_EINT_BUSYEND	0x02  #define WBSD_EINT_TC		0x01  #define WBSD_INT_PENDING	0x80 @@ -158,8 +158,6 @@ struct wbsd_host  	unsigned int		offset;		/* Offset into current entry */  	unsigned int		remain;		/* Data left in curren entry */ -	int			size;		/* Total size of transfer */ -  	char*			dma_buffer;	/* ISA DMA buffer */  	dma_addr_t		dma_addr;	/* Physical address for same */ @@ -182,7 +180,6 @@ struct wbsd_host  	struct tasklet_struct	crc_tasklet;  	struct tasklet_struct	timeout_tasklet;  	struct tasklet_struct	finish_tasklet; -	struct tasklet_struct	block_tasklet;  	struct timer_list	ignore_timer;	/* Ignore detection timer */  }; diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c deleted file mode 100644 index 4a73e8b2428..00000000000 --- a/drivers/mmc/mmc.c +++ /dev/null @@ -1,1724 +0,0 @@ -/* - *  linux/drivers/mmc/mmc.c - * - *  Copyright (C) 2003-2004 Russell King, All Rights Reserved. - *  SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. - *  SD support Copyright (C) 2005 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 <asm/scatterlist.h> -#include <linux/scatterlist.h> - -#include <linux/mmc/card.h> -#include <linux/mmc/host.h> -#include <linux/mmc/protocol.h> - -#include "mmc.h" - -#define CMD_RETRIES	3 - -/* - * OCR Bit positions to 10s of Vdd mV. - */ -static const unsigned short mmc_ocr_bit_to_vdd[] = { -	150,	155,	160,	165,	170,	180,	190,	200, -	210,	220,	230,	240,	250,	260,	270,	280, -	290,	300,	310,	320,	330,	340,	350,	360 -}; - -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, -}; - - -/** - *	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; - -	pr_debug("%s: req done (CMD%u): %d/%d/%d: %08x %08x %08x %08x\n", -		 mmc_hostname(host), cmd->opcode, err, -		 mrq->data ? mrq->data->error : 0, -		 mrq->stop ? mrq->stop->error : 0, -		 cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); - -	if (err && cmd->retries) { -		cmd->retries--; -		cmd->error = 0; -		host->ops->request(host, mrq); -	} else if (mrq->done) { -		mrq->done(mrq); -	} -} - -EXPORT_SYMBOL(mmc_request_done); - -/** - *	mmc_start_request - start a command on a host - *	@host: MMC host to start command on - *	@mrq: MMC request to start - * - *	Queue a command on the specified host.  We expect the - *	caller to be holding the host lock with interrupts disabled. - */ -void -mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) -{ -	pr_debug("%s: starting CMD%u arg %08x flags %08x\n", -		 mmc_hostname(host), mrq->cmd->opcode, -		 mrq->cmd->arg, mrq->cmd->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); - -		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; -		} -	} -	host->ops->request(host, mrq); -} - -EXPORT_SYMBOL(mmc_start_request); - -static void mmc_wait_done(struct mmc_request *mrq) -{ -	complete(mrq->done_data); -} - -int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) -{ -	DECLARE_COMPLETION_ONSTACK(complete); - -	mrq->done_data = &complete; -	mrq->done = mmc_wait_done; - -	mmc_start_request(host, mrq); - -	wait_for_completion(&complete); - -	return 0; -} - -EXPORT_SYMBOL(mmc_wait_for_req); - -/** - *	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; - -	BUG_ON(!host->claimed); - -	memset(&mrq, 0, sizeof(struct mmc_request)); - -	memset(cmd->resp, 0, sizeof(cmd->resp)); -	cmd->retries = retries; - -	mrq.cmd = cmd; -	cmd->data = NULL; - -	mmc_wait_for_req(host, &mrq); - -	return cmd->error; -} - -EXPORT_SYMBOL(mmc_wait_for_cmd); - -/** - *	mmc_wait_for_app_cmd - start an application command and wait for - 			       completion - *	@host: MMC host to start command - *	@rca: RCA 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, unsigned int rca, -	struct mmc_command *cmd, int retries) -{ -	struct mmc_request mrq; -	struct mmc_command appcmd; - -	int i, err; - -	BUG_ON(!host->claimed); -	BUG_ON(retries < 0); - -	err = MMC_ERR_INVALID; - -	/* -	 * 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++) { -		memset(&mrq, 0, sizeof(struct mmc_request)); - -		appcmd.opcode = MMC_APP_CMD; -		appcmd.arg = rca << 16; -		appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC; -		appcmd.retries = 0; -		memset(appcmd.resp, 0, sizeof(appcmd.resp)); -		appcmd.data = NULL; - -		mrq.cmd = &appcmd; -		appcmd.data = NULL; - -		mmc_wait_for_req(host, &mrq); - -		if (appcmd.error) { -			err = appcmd.error; -			continue; -		} - -		/* Check that card supported application commands */ -		if (!(appcmd.resp[0] & R1_APP_CMD)) -			return MMC_ERR_FAILED; - -		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 == MMC_ERR_NONE) -			break; -	} - -	return err; -} - -EXPORT_SYMBOL(mmc_wait_for_app_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 - *	@write: flag to differentiate reads from writes - */ -void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card, -			  int write) -{ -	unsigned int mult; - -	/* -	 * 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 (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; -		timeout_us += data->timeout_clks * 1000 / -			(card->host->ios.clock / 1000); - -		if (write) -			limit_us = 250000; -		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; -		} -	} -} -EXPORT_SYMBOL(mmc_set_data_timeout); - -static int mmc_select_card(struct mmc_host *host, struct mmc_card *card); - -/** - *	__mmc_claim_host - exclusively claim a host - *	@host: mmc host to claim - *	@card: mmc card to claim host for - * - *	Claim a host for a set of operations.  If a valid card - *	is passed and this wasn't the last card selected, select - *	the card before returning. - * - *	Note: you should use mmc_card_claim_host or mmc_claim_host. - */ -int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card) -{ -	DECLARE_WAITQUEUE(wait, current); -	unsigned long flags; -	int err = 0; - -	add_wait_queue(&host->wq, &wait); -	spin_lock_irqsave(&host->lock, flags); -	while (1) { -		set_current_state(TASK_UNINTERRUPTIBLE); -		if (!host->claimed) -			break; -		spin_unlock_irqrestore(&host->lock, flags); -		schedule(); -		spin_lock_irqsave(&host->lock, flags); -	} -	set_current_state(TASK_RUNNING); -	host->claimed = 1; -	spin_unlock_irqrestore(&host->lock, flags); -	remove_wait_queue(&host->wq, &wait); - -	if (card != (void *)-1) { -		err = mmc_select_card(host, card); -		if (err != MMC_ERR_NONE) -			return err; -	} - -	return err; -} - -EXPORT_SYMBOL(__mmc_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; - -	BUG_ON(!host->claimed); - -	spin_lock_irqsave(&host->lock, flags); -	host->claimed = 0; -	spin_unlock_irqrestore(&host->lock, flags); - -	wake_up(&host->wq); -} - -EXPORT_SYMBOL(mmc_release_host); - -static inline void mmc_set_ios(struct mmc_host *host) -{ -	struct mmc_ios *ios = &host->ios; - -	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); - -	host->ops->set_ios(host, ios); -} - -static int mmc_select_card(struct mmc_host *host, struct mmc_card *card) -{ -	int err; -	struct mmc_command cmd; - -	BUG_ON(!host->claimed); - -	if (host->card_selected == card) -		return MMC_ERR_NONE; - -	host->card_selected = card; - -	cmd.opcode = MMC_SELECT_CARD; -	cmd.arg = card->rca << 16; -	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - -	err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); -	if (err != MMC_ERR_NONE) -		return err; - -	/* -	 * We can only change the bus width of SD cards when -	 * they are selected so we have to put the handling -	 * here. -	 * -	 * The card is in 1 bit mode by default so -	 * we only need to change if it supports the -	 * wider version. -	 */ -	if (mmc_card_sd(card) && -		(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { - -		/* -		* Default bus width is 1 bit. -		*/ -		host->ios.bus_width = MMC_BUS_WIDTH_1; - -		if (host->caps & MMC_CAP_4_BIT_DATA) { -			struct mmc_command cmd; -			cmd.opcode = SD_APP_SET_BUS_WIDTH; -			cmd.arg = SD_BUS_WIDTH_4; -			cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - -			err = mmc_wait_for_app_cmd(host, card->rca, &cmd, -				CMD_RETRIES); -			if (err != MMC_ERR_NONE) -				return err; - -			host->ios.bus_width = MMC_BUS_WIDTH_4; -		} -	} - -	mmc_set_ios(host); - -	return MMC_ERR_NONE; -} - -/* - * Ensure that no card is selected. - */ -static void mmc_deselect_cards(struct mmc_host *host) -{ -	struct mmc_command cmd; - -	if (host->card_selected) { -		host->card_selected = NULL; - -		cmd.opcode = MMC_SELECT_CARD; -		cmd.arg = 0; -		cmd.flags = MMC_RSP_NONE | MMC_CMD_AC; - -		mmc_wait_for_cmd(host, &cmd, 0); -	} -} - - -static inline void mmc_delay(unsigned int ms) -{ -	if (ms < 1000 / HZ) { -		cond_resched(); -		mdelay(ms); -	} else { -		msleep(ms); -	} -} - -/* - * Mask off any voltages we don't support and select - * the lowest voltage - */ -static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) -{ -	int bit; - -	ocr &= host->ocr_avail; - -	bit = ffs(ocr); -	if (bit) { -		bit -= 1; - -		ocr &= 3 << bit; - -		host->ios.vdd = bit; -		mmc_set_ios(host); -	} else { -		ocr = 0; -	} - -	return ocr; -} - -#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 void mmc_decode_cid(struct mmc_card *card) -{ -	u32 *resp = card->raw_cid; - -	memset(&card->cid, 0, sizeof(struct mmc_cid)); - -	if (mmc_card_sd(card)) { -		/* -		 * 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 */ -	} else { -		/* -		 * 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: -			printk("%s: card has unknown MMCA version %d\n", -				mmc_hostname(card->host), card->csd.mmca_vsn); -			mmc_card_set_bad(card); -			break; -		} -	} -} - -/* - * Given a 128-bit response, decode to our card CSD structure. - */ -static void mmc_decode_csd(struct mmc_card *card) -{ -	struct mmc_csd *csd = &card->csd; -	unsigned int e, m, csd_struct; -	u32 *resp = card->raw_csd; - -	if (mmc_card_sd(card)) { -		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); -			break; -		case 1: -			/* -			 * This is a block-addressed SDHC 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); - -			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; -			break; -		default: -			printk("%s: unrecognised CSD structure version %d\n", -				mmc_hostname(card->host), csd_struct); -			mmc_card_set_bad(card); -			return; -		} -	} else { -		/* -		 * We only understand CSD structure v1.1 and v1.2. -		 * v1.2 has extra information in bits 15, 11 and 10. -		 */ -		csd_struct = UNSTUFF_BITS(resp, 126, 2); -		if (csd_struct != 1 && csd_struct != 2) { -			printk("%s: unrecognised CSD structure version %d\n", -				mmc_hostname(card->host), csd_struct); -			mmc_card_set_bad(card); -			return; -		} - -		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); -	} -} - -/* - * Given a 64-bit response, decode to our card SCR structure. - */ -static void mmc_decode_scr(struct mmc_card *card) -{ -	struct sd_scr *scr = &card->scr; -	unsigned int scr_struct; -	u32 resp[4]; - -	BUG_ON(!mmc_card_sd(card)); - -	resp[3] = card->raw_scr[1]; -	resp[2] = card->raw_scr[0]; - -	scr_struct = UNSTUFF_BITS(resp, 60, 4); -	if (scr_struct != 0) { -		printk("%s: unrecognised SCR structure version %d\n", -			mmc_hostname(card->host), scr_struct); -		mmc_card_set_bad(card); -		return; -	} - -	scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4); -	scr->bus_widths = UNSTUFF_BITS(resp, 48, 4); -} - -/* - * Locate a MMC card on this MMC host given a raw CID. - */ -static struct mmc_card *mmc_find_card(struct mmc_host *host, u32 *raw_cid) -{ -	struct mmc_card *card; - -	list_for_each_entry(card, &host->cards, node) { -		if (memcmp(card->raw_cid, raw_cid, sizeof(card->raw_cid)) == 0) -			return card; -	} -	return NULL; -} - -/* - * Allocate a new MMC card, and assign a unique RCA. - */ -static struct mmc_card * -mmc_alloc_card(struct mmc_host *host, u32 *raw_cid, unsigned int *frca) -{ -	struct mmc_card *card, *c; -	unsigned int rca = *frca; - -	card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL); -	if (!card) -		return ERR_PTR(-ENOMEM); - -	mmc_init_card(card, host); -	memcpy(card->raw_cid, raw_cid, sizeof(card->raw_cid)); - - again: -	list_for_each_entry(c, &host->cards, node) -		if (c->rca == rca) { -			rca++; -			goto again; -		} - -	card->rca = rca; - -	*frca = rca; - -	return card; -} - -/* - * Tell attached cards to go to IDLE state - */ -static void mmc_idle_cards(struct mmc_host *host) -{ -	struct mmc_command cmd; - -	host->ios.chip_select = MMC_CS_HIGH; -	mmc_set_ios(host); - -	mmc_delay(1); - -	cmd.opcode = MMC_GO_IDLE_STATE; -	cmd.arg = 0; -	cmd.flags = MMC_RSP_NONE | MMC_CMD_BC; - -	mmc_wait_for_cmd(host, &cmd, 0); - -	mmc_delay(1); - -	host->ios.chip_select = MMC_CS_DONTCARE; -	mmc_set_ios(host); - -	mmc_delay(1); -} - -/* - * 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 = fls(host->ocr_avail) - 1; - -	host->ios.vdd = bit; -	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; -	host->ios.chip_select = MMC_CS_DONTCARE; -	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); - -	mmc_delay(1); - -	host->ios.clock = host->f_min; -	host->ios.power_mode = MMC_POWER_ON; -	mmc_set_ios(host); - -	mmc_delay(2); -} - -static void mmc_power_off(struct mmc_host *host) -{ -	host->ios.clock = 0; -	host->ios.vdd = 0; -	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); -} - -static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) -{ -	struct mmc_command cmd; -	int i, err = 0; - -	cmd.opcode = MMC_SEND_OP_COND; -	cmd.arg = ocr; -	cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; - -	for (i = 100; i; i--) { -		err = mmc_wait_for_cmd(host, &cmd, 0); -		if (err != MMC_ERR_NONE) -			break; - -		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) -			break; - -		err = MMC_ERR_TIMEOUT; - -		mmc_delay(10); -	} - -	if (rocr) -		*rocr = cmd.resp[0]; - -	return err; -} - -static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) -{ -	struct mmc_command cmd; -	int i, err = 0; - -	cmd.opcode = SD_APP_OP_COND; -	cmd.arg = ocr; -	cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR; - -	for (i = 100; i; i--) { -		err = mmc_wait_for_app_cmd(host, 0, &cmd, CMD_RETRIES); -		if (err != MMC_ERR_NONE) -			break; - -		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0) -			break; - -		err = MMC_ERR_TIMEOUT; - -		mmc_delay(10); -	} - -	if (rocr) -		*rocr = cmd.resp[0]; - -	return err; -} - -static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2) -{ -	struct mmc_command cmd; -	int err, sd2; -	static const u8 test_pattern = 0xAA; - -	/* -	* 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_R7 | MMC_CMD_BCR; - -	err = mmc_wait_for_cmd(host, &cmd, 0); -	if (err == MMC_ERR_NONE) { -		if ((cmd.resp[0] & 0xFF) == test_pattern) { -			sd2 = 1; -		} else { -			sd2 = 0; -			err = MMC_ERR_FAILED; -		} -	} else { -		/* -		 * Treat errors as SD 1.0 card. -		 */ -		sd2 = 0; -		err = MMC_ERR_NONE; -	} -	if (rsd2) -		*rsd2 = sd2; -	return err; -} - -/* - * Discover cards by requesting their CID.  If this command - * times out, it is not an error; there are no further cards - * to be discovered.  Add new cards to the list. - * - * Create a mmc_card entry for each discovered card, assigning - * it an RCA, and save the raw CID for decoding later. - */ -static void mmc_discover_cards(struct mmc_host *host) -{ -	struct mmc_card *card; -	unsigned int first_rca = 1, err; - -	while (1) { -		struct mmc_command cmd; - -		cmd.opcode = MMC_ALL_SEND_CID; -		cmd.arg = 0; -		cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR; - -		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); -		if (err == MMC_ERR_TIMEOUT) { -			err = MMC_ERR_NONE; -			break; -		} -		if (err != MMC_ERR_NONE) { -			printk(KERN_ERR "%s: error requesting CID: %d\n", -				mmc_hostname(host), err); -			break; -		} - -		card = mmc_find_card(host, cmd.resp); -		if (!card) { -			card = mmc_alloc_card(host, cmd.resp, &first_rca); -			if (IS_ERR(card)) { -				err = PTR_ERR(card); -				break; -			} -			list_add(&card->node, &host->cards); -		} - -		card->state &= ~MMC_STATE_DEAD; - -		if (host->mode == MMC_MODE_SD) { -			mmc_card_set_sd(card); - -			cmd.opcode = SD_SEND_RELATIVE_ADDR; -			cmd.arg = 0; -			cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; - -			err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); -			if (err != MMC_ERR_NONE) -				mmc_card_set_dead(card); -			else { -				card->rca = cmd.resp[0] >> 16; - -				if (!host->ops->get_ro) { -					printk(KERN_WARNING "%s: host does not " -						"support reading read-only " -						"switch. assuming write-enable.\n", -						mmc_hostname(host)); -				} else { -					if (host->ops->get_ro(host)) -						mmc_card_set_readonly(card); -				} -			} -		} else { -			cmd.opcode = MMC_SET_RELATIVE_ADDR; -			cmd.arg = card->rca << 16; -			cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - -			err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); -			if (err != MMC_ERR_NONE) -				mmc_card_set_dead(card); -		} -	} -} - -static void mmc_read_csds(struct mmc_host *host) -{ -	struct mmc_card *card; - -	list_for_each_entry(card, &host->cards, node) { -		struct mmc_command cmd; -		int err; - -		if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) -			continue; - -		cmd.opcode = MMC_SEND_CSD; -		cmd.arg = card->rca << 16; -		cmd.flags = MMC_RSP_R2 | MMC_CMD_AC; - -		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); -		if (err != MMC_ERR_NONE) { -			mmc_card_set_dead(card); -			continue; -		} - -		memcpy(card->raw_csd, cmd.resp, sizeof(card->raw_csd)); - -		mmc_decode_csd(card); -		mmc_decode_cid(card); -	} -} - -static void mmc_process_ext_csds(struct mmc_host *host) -{ -	int err; -	struct mmc_card *card; - -	struct mmc_request mrq; -	struct mmc_command cmd; -	struct mmc_data data; - -	struct scatterlist sg; - -	/* -	 * As the ext_csd is so large and mostly unused, we don't store the -	 * raw block in mmc_card. -	 */ -	u8 *ext_csd; -	ext_csd = kmalloc(512, GFP_KERNEL); -	if (!ext_csd) { -		printk("%s: could not allocate a buffer to receive the ext_csd." -		       "mmc v4 cards will be treated as v3.\n", -			mmc_hostname(host)); -		return; -	} - -	list_for_each_entry(card, &host->cards, node) { -		if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) -			continue; -		if (mmc_card_sd(card)) -			continue; -		if (card->csd.mmca_vsn < CSD_SPEC_VER_4) -			continue; - -		err = mmc_select_card(host, card); -		if (err != MMC_ERR_NONE) { -			mmc_card_set_dead(card); -			continue; -		} - -		memset(&cmd, 0, sizeof(struct mmc_command)); - -		cmd.opcode = MMC_SEND_EXT_CSD; -		cmd.arg = 0; -		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - -		memset(&data, 0, sizeof(struct mmc_data)); - -		mmc_set_data_timeout(&data, card, 0); - -		data.blksz = 512; -		data.blocks = 1; -		data.flags = MMC_DATA_READ; -		data.sg = &sg; -		data.sg_len = 1; - -		memset(&mrq, 0, sizeof(struct mmc_request)); - -		mrq.cmd = &cmd; -		mrq.data = &data; - -		sg_init_one(&sg, ext_csd, 512); - -		mmc_wait_for_req(host, &mrq); - -		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { -			printk("%s: unable to read EXT_CSD, performance " -				"might suffer.\n", mmc_hostname(card->host)); -			continue; -		} - -		switch (ext_csd[EXT_CSD_CARD_TYPE]) { -		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 */ -			printk("%s: card is mmc v4 but doesn't support " -			       "any high-speed modes.\n", -				mmc_hostname(card->host)); -			continue; -		} - -		if (host->caps & MMC_CAP_MMC_HIGHSPEED) { -			/* Activate highspeed support. */ -			cmd.opcode = MMC_SWITCH; -			cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | -				  (EXT_CSD_HS_TIMING << 16) | -				  (1 << 8) | -				  EXT_CSD_CMD_SET_NORMAL; -			cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; - -			err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); -			if (err != MMC_ERR_NONE) { -				printk("%s: failed to switch card to mmc v4 " -				       "high-speed mode.\n", -				       mmc_hostname(card->host)); -				continue; -			} - -			mmc_card_set_highspeed(card); - -			host->ios.timing = MMC_TIMING_SD_HS; -			mmc_set_ios(host); -		} - -		/* Check for host support for wide-bus modes. */ -		if (host->caps & MMC_CAP_4_BIT_DATA) { -			/* Activate 4-bit support. */ -			cmd.opcode = MMC_SWITCH; -			cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | -				  (EXT_CSD_BUS_WIDTH << 16) | -				  (EXT_CSD_BUS_WIDTH_4 << 8) | -				  EXT_CSD_CMD_SET_NORMAL; -			cmd.flags = MMC_RSP_R1B | MMC_CMD_AC; - -			err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); -			if (err != MMC_ERR_NONE) { -				printk("%s: failed to switch card to " -				       "mmc v4 4-bit bus mode.\n", -				       mmc_hostname(card->host)); -				continue; -			} - -			host->ios.bus_width = MMC_BUS_WIDTH_4; -			mmc_set_ios(host); -		} -	} - -	kfree(ext_csd); - -	mmc_deselect_cards(host); -} - -static void mmc_read_scrs(struct mmc_host *host) -{ -	int err; -	struct mmc_card *card; -	struct mmc_request mrq; -	struct mmc_command cmd; -	struct mmc_data data; -	struct scatterlist sg; - -	list_for_each_entry(card, &host->cards, node) { -		if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) -			continue; -		if (!mmc_card_sd(card)) -			continue; - -		err = mmc_select_card(host, card); -		if (err != MMC_ERR_NONE) { -			mmc_card_set_dead(card); -			continue; -		} - -		memset(&cmd, 0, sizeof(struct mmc_command)); - -		cmd.opcode = MMC_APP_CMD; -		cmd.arg = card->rca << 16; -		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - -		err = mmc_wait_for_cmd(host, &cmd, 0); -		if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) { -			mmc_card_set_dead(card); -			continue; -		} - -		memset(&cmd, 0, sizeof(struct mmc_command)); - -		cmd.opcode = SD_APP_SEND_SCR; -		cmd.arg = 0; -		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - -		memset(&data, 0, sizeof(struct mmc_data)); - -		mmc_set_data_timeout(&data, card, 0); - -		data.blksz = 1 << 3; -		data.blocks = 1; -		data.flags = MMC_DATA_READ; -		data.sg = &sg; -		data.sg_len = 1; - -		memset(&mrq, 0, sizeof(struct mmc_request)); - -		mrq.cmd = &cmd; -		mrq.data = &data; - -		sg_init_one(&sg, (u8*)card->raw_scr, 8); - -		mmc_wait_for_req(host, &mrq); - -		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { -			mmc_card_set_dead(card); -			continue; -		} - -		card->raw_scr[0] = ntohl(card->raw_scr[0]); -		card->raw_scr[1] = ntohl(card->raw_scr[1]); - -		mmc_decode_scr(card); -	} - -	mmc_deselect_cards(host); -} - -static void mmc_read_switch_caps(struct mmc_host *host) -{ -	int err; -	struct mmc_card *card; -	struct mmc_request mrq; -	struct mmc_command cmd; -	struct mmc_data data; -	unsigned char *status; -	struct scatterlist sg; - -	if (!(host->caps & MMC_CAP_SD_HIGHSPEED)) -		return; - -	status = kmalloc(64, GFP_KERNEL); -	if (!status) { -		printk(KERN_WARNING "%s: Unable to allocate buffer for " -			"reading switch capabilities.\n", -			mmc_hostname(host)); -		return; -	} - -	list_for_each_entry(card, &host->cards, node) { -		if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT)) -			continue; -		if (!mmc_card_sd(card)) -			continue; -		if (card->scr.sda_vsn < SCR_SPEC_VER_1) -			continue; - -		err = mmc_select_card(host, card); -		if (err != MMC_ERR_NONE) { -			mmc_card_set_dead(card); -			continue; -		} - -		memset(&cmd, 0, sizeof(struct mmc_command)); - -		cmd.opcode = SD_SWITCH; -		cmd.arg = 0x00FFFFF1; -		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - -		memset(&data, 0, sizeof(struct mmc_data)); - -		mmc_set_data_timeout(&data, card, 0); - -		data.blksz = 64; -		data.blocks = 1; -		data.flags = MMC_DATA_READ; -		data.sg = &sg; -		data.sg_len = 1; - -		memset(&mrq, 0, sizeof(struct mmc_request)); - -		mrq.cmd = &cmd; -		mrq.data = &data; - -		sg_init_one(&sg, status, 64); - -		mmc_wait_for_req(host, &mrq); - -		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) { -			printk("%s: unable to read switch capabilities, " -				"performance might suffer.\n", -				mmc_hostname(card->host)); -			continue; -		} - -		if (status[13] & 0x02) -			card->sw_caps.hs_max_dtr = 50000000; - -		memset(&cmd, 0, sizeof(struct mmc_command)); - -		cmd.opcode = SD_SWITCH; -		cmd.arg = 0x80FFFFF1; -		cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC; - -		memset(&data, 0, sizeof(struct mmc_data)); - -		mmc_set_data_timeout(&data, card, 0); - -		data.blksz = 64; -		data.blocks = 1; -		data.flags = MMC_DATA_READ; -		data.sg = &sg; -		data.sg_len = 1; - -		memset(&mrq, 0, sizeof(struct mmc_request)); - -		mrq.cmd = &cmd; -		mrq.data = &data; - -		sg_init_one(&sg, status, 64); - -		mmc_wait_for_req(host, &mrq); - -		if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE || -			(status[16] & 0xF) != 1) { -			printk(KERN_WARNING "%s: Problem switching card " -				"into high-speed mode!\n", -				mmc_hostname(host)); -			continue; -		} - -		mmc_card_set_highspeed(card); - -		host->ios.timing = MMC_TIMING_SD_HS; -		mmc_set_ios(host); -	} - -	kfree(status); - -	mmc_deselect_cards(host); -} - -static unsigned int mmc_calculate_clock(struct mmc_host *host) -{ -	struct mmc_card *card; -	unsigned int max_dtr = host->f_max; - -	list_for_each_entry(card, &host->cards, node) -		if (!mmc_card_dead(card)) { -			if (mmc_card_highspeed(card) && mmc_card_sd(card)) { -				if (max_dtr > card->sw_caps.hs_max_dtr) -					max_dtr = card->sw_caps.hs_max_dtr; -			} else if (mmc_card_highspeed(card) && !mmc_card_sd(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; -			} -		} - -	pr_debug("%s: selected %d.%03dMHz transfer rate\n", -		 mmc_hostname(host), -		 max_dtr / 1000000, (max_dtr / 1000) % 1000); - -	return max_dtr; -} - -/* - * Check whether cards we already know about are still present. - * We do this by requesting status, and checking whether a card - * responds. - * - * A request for status does not cause a state change in data - * transfer mode. - */ -static void mmc_check_cards(struct mmc_host *host) -{ -	struct list_head *l, *n; - -	mmc_deselect_cards(host); - -	list_for_each_safe(l, n, &host->cards) { -		struct mmc_card *card = mmc_list_to_card(l); -		struct mmc_command cmd; -		int err; - -		cmd.opcode = MMC_SEND_STATUS; -		cmd.arg = card->rca << 16; -		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - -		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES); -		if (err == MMC_ERR_NONE) -			continue; - -		mmc_card_set_dead(card); -	} -} - -static void mmc_setup(struct mmc_host *host) -{ -	if (host->ios.power_mode != MMC_POWER_ON) { -		int err; -		u32 ocr; - -		host->mode = MMC_MODE_SD; - -		mmc_power_up(host); -		mmc_idle_cards(host); - -		err = mmc_send_if_cond(host, host->ocr_avail, NULL); -		if (err != MMC_ERR_NONE) { -			return; -		} -		err = mmc_send_app_op_cond(host, 0, &ocr); - -		/* -		 * If we fail to detect any SD cards then try -		 * searching for MMC cards. -		 */ -		if (err != MMC_ERR_NONE) { -			host->mode = MMC_MODE_MMC; - -			err = mmc_send_op_cond(host, 0, &ocr); -			if (err != MMC_ERR_NONE) -				return; -		} - -		host->ocr = mmc_select_voltage(host, ocr); - -		/* -		 * 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. -		 */ -		if (host->ocr) -			mmc_idle_cards(host); -	} else { -		host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; -		host->ios.clock = host->f_min; -		mmc_set_ios(host); - -		/* -		 * We should remember the OCR mask from the existing -		 * cards, and detect the new cards OCR mask, combine -		 * the two and re-select the VDD.  However, if we do -		 * change VDD, we should do an idle, and then do a -		 * full re-initialisation.  We would need to notify -		 * drivers so that they can re-setup the cards as -		 * well, while keeping their queues at bay. -		 * -		 * For the moment, we take the easy way out - if the -		 * new cards don't like our currently selected VDD, -		 * they drop off the bus. -		 */ -	} - -	if (host->ocr == 0) -		return; - -	/* -	 * Send the selected OCR multiple times... until the cards -	 * all get the idea that they should be ready for CMD2. -	 * (My SanDisk card seems to need this.) -	 */ -	if (host->mode == MMC_MODE_SD) { -		int err, sd2; -		err = mmc_send_if_cond(host, host->ocr, &sd2); -		if (err == MMC_ERR_NONE) { -			/* -			* 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. -			*/ -			mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL); -		} -	} else { -		mmc_send_op_cond(host, host->ocr, NULL); -	} - -	mmc_discover_cards(host); - -	/* -	 * Ok, now switch to push-pull mode. -	 */ -	host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; -	mmc_set_ios(host); - -	mmc_read_csds(host); - -	if (host->mode == MMC_MODE_SD) { -		mmc_read_scrs(host); -		mmc_read_switch_caps(host); -	} else -		mmc_process_ext_csds(host); -} - - -/** - *	mmc_detect_change - process change of state on a MMC socket - *	@host: host which changed state. - *	@delay: optional delay to wait before detection (jiffies) - * - *	All we know is that card(s) have been inserted or removed - *	from the socket(s).  We don't know which socket or cards. - */ -void mmc_detect_change(struct mmc_host *host, unsigned long delay) -{ -	mmc_schedule_delayed_work(&host->detect, delay); -} - -EXPORT_SYMBOL(mmc_detect_change); - - -static void mmc_rescan(struct work_struct *work) -{ -	struct mmc_host *host = -		container_of(work, struct mmc_host, detect.work); -	struct list_head *l, *n; -	unsigned char power_mode; - -	mmc_claim_host(host); - -	/* -	 * Check for removed cards and newly inserted ones. We check for -	 * removed cards first so we can intelligently re-select the VDD. -	 */ -	power_mode = host->ios.power_mode; -	if (power_mode == MMC_POWER_ON) -		mmc_check_cards(host); - -	mmc_setup(host); - -	/* -	 * Some broken cards process CMD1 even in stand-by state. There is -	 * no reply, but an ILLEGAL_COMMAND error is cached and returned -	 * after next command. We poll for card status here to clear any -	 * possibly pending error. -	 */ -	if (power_mode == MMC_POWER_ON) -		mmc_check_cards(host); - -	if (!list_empty(&host->cards)) { -		/* -		 * (Re-)calculate the fastest clock rate which the -		 * attached cards and the host support. -		 */ -		host->ios.clock = mmc_calculate_clock(host); -		mmc_set_ios(host); -	} - -	mmc_release_host(host); - -	list_for_each_safe(l, n, &host->cards) { -		struct mmc_card *card = mmc_list_to_card(l); - -		/* -		 * If this is a new and good card, register it. -		 */ -		if (!mmc_card_present(card) && !mmc_card_dead(card)) { -			if (mmc_register_card(card)) -				mmc_card_set_dead(card); -			else -				mmc_card_set_present(card); -		} - -		/* -		 * If this card is dead, destroy it. -		 */ -		if (mmc_card_dead(card)) { -			list_del(&card->node); -			mmc_remove_card(card); -		} -	} - -	/* -	 * If we discover that there are no cards on the -	 * bus, turn off the clock and power down. -	 */ -	if (list_empty(&host->cards)) -		mmc_power_off(host); -} - - -/** - *	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) -{ -	struct mmc_host *host; - -	host = mmc_alloc_host_sysfs(extra, dev); -	if (host) { -		spin_lock_init(&host->lock); -		init_waitqueue_head(&host->wq); -		INIT_LIST_HEAD(&host->cards); -		INIT_DELAYED_WORK(&host->detect, mmc_rescan); - -		/* -		 * By default, hosts do not support SGIO or large requests. -		 * They have to set these according to their abilities. -		 */ -		host->max_hw_segs = 1; -		host->max_phys_segs = 1; -		host->max_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; -	} - -	return host; -} - -EXPORT_SYMBOL(mmc_alloc_host); - -/** - *	mmc_add_host - initialise host hardware - *	@host: mmc host - */ -int mmc_add_host(struct mmc_host *host) -{ -	int ret; - -	ret = mmc_add_host_sysfs(host); -	if (ret == 0) { -		mmc_power_off(host); -		mmc_detect_change(host, 0); -	} - -	return ret; -} - -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. - */ -void mmc_remove_host(struct mmc_host *host) -{ -	struct list_head *l, *n; - -	list_for_each_safe(l, n, &host->cards) { -		struct mmc_card *card = mmc_list_to_card(l); - -		mmc_remove_card(card); -	} - -	mmc_power_off(host); -	mmc_remove_host_sysfs(host); -} - -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) -{ -	mmc_flush_scheduled_work(); -	mmc_free_host_sysfs(host); -} - -EXPORT_SYMBOL(mmc_free_host); - -#ifdef CONFIG_PM - -/** - *	mmc_suspend_host - suspend a host - *	@host: mmc host - *	@state: suspend mode (PM_SUSPEND_xxx) - */ -int mmc_suspend_host(struct mmc_host *host, pm_message_t state) -{ -	mmc_claim_host(host); -	mmc_deselect_cards(host); -	mmc_power_off(host); -	mmc_release_host(host); - -	return 0; -} - -EXPORT_SYMBOL(mmc_suspend_host); - -/** - *	mmc_resume_host - resume a previously suspended host - *	@host: mmc host - */ -int mmc_resume_host(struct mmc_host *host) -{ -	mmc_rescan(&host->detect.work); - -	return 0; -} - -EXPORT_SYMBOL(mmc_resume_host); - -#endif - -MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c deleted file mode 100644 index 0581d09c58f..00000000000 --- a/drivers/mmc/tifm_sd.c +++ /dev/null @@ -1,987 +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. - * - */ - - -#include <linux/tifm.h> -#include <linux/mmc/protocol.h> -#include <linux/mmc/host.h> -#include <linux/highmem.h> -#include <asm/io.h> - -#define DRIVER_NAME "tifm_sd" -#define DRIVER_VERSION "0.7" - -static int no_dma = 0; -static int 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_DATAMASK   0x401d   /* set bits: CERR, EOFB, BRS, CB, EOC */ -#define TIFM_MMCSD_ERRMASK    0x01e0   /* set bits: CCRC, CTO, DCRC, DTO */ -#define TIFM_MMCSD_EOC        0x0001   /* end of command phase  */ -#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_CERR       0x4000   /* card status error     */ - -#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 - -typedef enum { -	IDLE = 0, -	CMD,    /* main command ended                   */ -	BRS,    /* block transfer finished              */ -	SCMD,   /* stop command ended                   */ -	CARD,   /* card left busy state                 */ -	FIFO,   /* FIFO operation completed (uncertain) */ -	READY -} card_state_t; - -enum { -	FIFO_RDY   = 0x0001,     /* hardware dependent value */ -	EJECT      = 0x0004, -	EJECT_DONE = 0x0008, -	CARD_BUSY  = 0x0010, -	OPENDRAIN  = 0x0040,     /* hardware dependent value */ -	CARD_EVENT = 0x0100,     /* hardware dependent value */ -	CARD_RO    = 0x0200,     /* hardware dependent value */ -	FIFO_EVENT = 0x10000 };  /* hardware dependent value */ - -struct tifm_sd { -	struct tifm_dev     *dev; - -	unsigned int        flags; -	card_state_t        state; -	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; -	wait_queue_head_t     notify; - -	size_t                written_blocks; -	size_t                buffer_size; -	size_t                buffer_pos; - -}; - -static char* tifm_sd_data_buffer(struct mmc_data *data) -{ -	return page_address(data->sg->page) + data->sg->offset; -} - -static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host, -				 unsigned int host_status) -{ -	struct mmc_command *cmd = host->req->cmd; -	unsigned int t_val = 0, cnt = 0; -	char *buffer; - -	if (host_status & TIFM_MMCSD_BRS) { -		/* in non-dma rx mode BRS fires when fifo is still not empty */ -		if (no_dma && (cmd->data->flags & MMC_DATA_READ)) { -			buffer = tifm_sd_data_buffer(host->req->data); -			while (host->buffer_size > host->buffer_pos) { -				t_val = readl(sock->addr + SOCK_MMCSD_DATA); -				buffer[host->buffer_pos++] = t_val & 0xff; -				buffer[host->buffer_pos++] = -							(t_val >> 8) & 0xff; -			} -		} -		return 1; -	} else if (no_dma) { -		buffer = tifm_sd_data_buffer(host->req->data); -		if ((cmd->data->flags & MMC_DATA_READ) && -				(host_status & TIFM_MMCSD_AF)) { -			for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) { -				t_val = readl(sock->addr + SOCK_MMCSD_DATA); -				if (host->buffer_size > host->buffer_pos) { -					buffer[host->buffer_pos++] = -							t_val & 0xff; -					buffer[host->buffer_pos++] = -							(t_val >> 8) & 0xff; -				} -			} -		} else if ((cmd->data->flags & MMC_DATA_WRITE) -			   && (host_status & TIFM_MMCSD_AE)) { -			for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) { -				if (host->buffer_size > host->buffer_pos) { -					t_val = buffer[host->buffer_pos++] -						& 0x00ff; -					t_val |= ((buffer[host->buffer_pos++]) -						  << 8) & 0xff00; -					writel(t_val, -					       sock->addr + SOCK_MMCSD_DATA); -				} -			} -		} -	} -	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) | -				(host->flags & OPENDRAIN); - -	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_process_cmd(struct tifm_dev *sock, struct tifm_sd *host, -				       unsigned int host_status) -{ -	struct mmc_command *cmd = host->req->cmd; - -change_state: -	switch (host->state) { -	case IDLE: -		return; -	case CMD: -		if (host_status & (TIFM_MMCSD_EOC | TIFM_MMCSD_CERR)) { -			tifm_sd_fetch_resp(cmd, sock); -			if (cmd->data) { -				host->state = BRS; -			} else { -				host->state = READY; -			} -			goto change_state; -		} -		break; -	case BRS: -		if (tifm_sd_transfer_data(sock, host, host_status)) { -			if (cmd->data->flags & MMC_DATA_WRITE) { -				host->state = CARD; -			} else { -				if (no_dma) { -					if (host->req->stop) { -						tifm_sd_exec(host, host->req->stop); -						host->state = SCMD; -					} else { -						host->state = READY; -					} -				} else { -					host->state = FIFO; -				} -			} -			goto change_state; -		} -		break; -	case SCMD: -		if (host_status & TIFM_MMCSD_EOC) { -			tifm_sd_fetch_resp(host->req->stop, sock); -			host->state = READY; -			goto change_state; -		} -		break; -	case CARD: -		dev_dbg(&sock->dev, "waiting for CARD, have %zd blocks\n", -			host->written_blocks); -		if (!(host->flags & CARD_BUSY) -		    && (host->written_blocks == cmd->data->blocks)) { -			if (no_dma) { -				if (host->req->stop) { -					tifm_sd_exec(host, host->req->stop); -					host->state = SCMD; -				} else { -					host->state = READY; -				} -			} else { -				host->state = FIFO; -			} -			goto change_state; -		} -		break; -	case FIFO: -		if (host->flags & FIFO_RDY) { -			host->flags &= ~FIFO_RDY; -			if (host->req->stop) { -				tifm_sd_exec(host, host->req->stop); -				host->state = SCMD; -			} else { -				host->state = READY; -			} -			goto change_state; -		} -		break; -	case READY: -		tasklet_schedule(&host->finish_tasklet); -		return; -	} - -} - -/* Called from interrupt handler */ -static void tifm_sd_signal_irq(struct tifm_dev *sock, -			       unsigned int sock_irq_status) -{ -	struct tifm_sd *host; -	unsigned int host_status = 0, fifo_status = 0; -	int error_code = 0; - -	spin_lock(&sock->lock); -	host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock)); - -	if (sock_irq_status & FIFO_EVENT) { -		fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS); -		writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS); - -		host->flags |= fifo_status & FIFO_RDY; -	} - -	if (sock_irq_status & CARD_EVENT) { -		host_status = readl(sock->addr + SOCK_MMCSD_STATUS); -		writel(host_status, sock->addr + SOCK_MMCSD_STATUS); - -		if (!host->req) -			goto done; - -		if (host_status & TIFM_MMCSD_ERRMASK) { -			if (host_status & (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO)) -				error_code = MMC_ERR_TIMEOUT; -			else if (host_status -				 & (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC)) -				error_code = MMC_ERR_BADCRC; - -			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->state == SCMD) { -					host->req->stop->error = error_code; -				} else if (host->state == BRS -					   || host->state == CARD -					   || host->state == FIFO) { -					host->req->cmd->error = error_code; -					tifm_sd_exec(host, host->req->stop); -					host->state = SCMD; -					goto done; -				} else { -					host->req->cmd->error = error_code; -				} -			} else { -				host->req->cmd->error = error_code; -			} -			host->state = READY; -		} - -		if (host_status & TIFM_MMCSD_CB) -			host->flags |= CARD_BUSY; -		if ((host_status & TIFM_MMCSD_EOFB) -		    && (host->flags & CARD_BUSY)) { -			host->written_blocks++; -			host->flags &= ~CARD_BUSY; -		} -        } - -	if (host->req) -		tifm_sd_process_cmd(sock, host, host_status); -done: -	dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n", -		host_status, fifo_status); -	spin_unlock(&sock->lock); -} - -static void tifm_sd_prepare_data(struct tifm_sd *host, struct mmc_command *cmd) -{ -	struct tifm_dev *sock = host->dev; -	unsigned int dest_cnt; - -	/* DMA style IO */ -	dev_dbg(&sock->dev, "setting dma for %d blocks\n", -		cmd->data->blocks); -	writel(TIFM_FIFO_INT_SETALL, -	       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR); -	writel(ilog2(cmd->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); - -	dest_cnt = (cmd->data->blocks) << 8; - -	writel(sg_dma_address(cmd->data->sg), sock->addr + SOCK_DMA_ADDRESS); - -	writel(cmd->data->blocks - 1, sock->addr + SOCK_MMCSD_NUM_BLOCKS); -	writel(cmd->data->blksz - 1, sock->addr + SOCK_MMCSD_BLOCK_LEN); - -	if (cmd->data->flags & MMC_DATA_WRITE) { -		writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); -		writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN, -		       sock->addr + SOCK_DMA_CONTROL); -	} else { -		writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG); -		writel(dest_cnt | TIFM_DMA_EN, sock->addr + SOCK_DMA_CONTROL); -	} -} - -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; -	int sg_count = 0; -	struct mmc_data *r_data = mrq->cmd->data; - -	spin_lock_irqsave(&sock->lock, flags); -	if (host->flags & EJECT) { -		spin_unlock_irqrestore(&sock->lock, flags); -		goto err_out; -	} - -	if (host->req) { -		printk(KERN_ERR DRIVER_NAME ": unfinished request detected\n"); -		spin_unlock_irqrestore(&sock->lock, flags); -		goto err_out; -	} - -	if (r_data) { -		tifm_sd_set_data_timeout(host, r_data); - -		sg_count = tifm_map_sg(sock, r_data->sg, r_data->sg_len, -				       mrq->cmd->flags & MMC_DATA_WRITE -				       ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); -		if (sg_count != 1) { -			printk(KERN_ERR DRIVER_NAME -				": scatterlist map failed\n"); -			spin_unlock_irqrestore(&sock->lock, flags); -			goto err_out; -		} - -		host->written_blocks = 0; -		host->flags &= ~CARD_BUSY; -		tifm_sd_prepare_data(host, mrq->cmd); -	} - -	host->req = mrq; -	mod_timer(&host->timer, jiffies + host->timeout_jiffies); -	host->state = CMD; -	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: -	if (sg_count > 0) -		tifm_unmap_sg(sock, r_data->sg, r_data->sg_len, -			      (r_data->flags & MMC_DATA_WRITE) -			      ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - -	mrq->cmd->error = MMC_ERR_TIMEOUT; -	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; -	host->state = IDLE; - -	if (!mrq) { -		printk(KERN_ERR DRIVER_NAME ": no request to complete?\n"); -		spin_unlock_irqrestore(&sock->lock, flags); -		return; -	} - -	r_data = mrq->cmd->data; -	if (r_data) { -		if (r_data->flags & MMC_DATA_WRITE) { -			r_data->bytes_xfered = host->written_blocks -					       * r_data->blksz; -		} else { -			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; -		} -		tifm_unmap_sg(sock, r_data->sg, r_data->sg_len, -			      (r_data->flags & MMC_DATA_WRITE) -			      ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); -	} - -	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_request_nodma(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->flags & EJECT) { -		spin_unlock_irqrestore(&sock->lock, flags); -		goto err_out; -	} - -	if (host->req) { -		printk(KERN_ERR DRIVER_NAME ": unfinished request detected\n"); -		spin_unlock_irqrestore(&sock->lock, flags); -		goto err_out; -	} - -	if (r_data) { -		tifm_sd_set_data_timeout(host, r_data); - -		host->buffer_size = mrq->cmd->data->blocks -				    * mrq->cmd->data->blksz; - -		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->written_blocks = 0; -		host->flags &= ~CARD_BUSY; -		host->buffer_pos = 0; -		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); -	host->state = CMD; -	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: -	mrq->cmd->error = MMC_ERR_TIMEOUT; -	mmc_request_done(mmc, mrq); -} - -static void tifm_sd_end_cmd_nodma(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; -	host->state = IDLE; - -	if (!mrq) { -		printk(KERN_ERR DRIVER_NAME ": no request to complete?\n"); -		spin_unlock_irqrestore(&sock->lock, flags); -		return; -	} - -	r_data = mrq->cmd->data; -	if (r_data) { -		writel((~TIFM_MMCSD_BUFINT) & -			readl(sock->addr + SOCK_MMCSD_INT_ENABLE), -			sock->addr + SOCK_MMCSD_INT_ENABLE); - -		if (r_data->flags & MMC_DATA_WRITE) { -			r_data->bytes_xfered = host->written_blocks -					       * r_data->blksz; -		} else { -			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; -		} -		host->buffer_pos = 0; -		host->buffer_size = 0; -	} - -	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_terminate(struct tifm_sd *host) -{ -	struct tifm_dev *sock = host->dev; -	unsigned long flags; - -	writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE); -	mmiowb(); -	spin_lock_irqsave(&sock->lock, flags); -	host->flags |= EJECT; -	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); -		tasklet_schedule(&host->finish_tasklet); -	} -	spin_unlock_irqrestore(&sock->lock, flags); -} - -static void tifm_sd_abort(unsigned long data) -{ -	struct tifm_sd *host = (struct tifm_sd*)data; - -	printk(KERN_ERR DRIVER_NAME -	       ": card failed to respond for a long period of time"); - -	tifm_sd_terminate(host); -	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, "Setting bus width %d, power %d\n", ios->bus_width, -		ios->power_mode); -	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); - -	if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) -		host->flags |= OPENDRAIN; -	else -		host->flags &= ~OPENDRAIN; - -	/* chip_select : maybe later */ -	//vdd -	//power is set before probe / after remove -	//I believe, power_off when already marked for eject is sufficient to -	// allow removal. -	if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) { -		host->flags |= EJECT_DONE; -		wake_up_all(&host->notify); -	} - -	spin_unlock_irqrestore(&sock->lock, flags); -} - -static int tifm_sd_ro(struct mmc_host *mmc) -{ -	int rc; -	struct tifm_sd *host = mmc_priv(mmc); -	struct tifm_dev *sock = host->dev; -	unsigned long flags; - -	spin_lock_irqsave(&sock->lock, flags); - -	host->flags |= (CARD_RO & readl(sock->addr + SOCK_PRESENT_STATE)); -	rc = (host->flags & CARD_RO) ? 1 : 0; - -	spin_unlock_irqrestore(&sock->lock, flags); -	return rc; -} - -static 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 = 2; rc <= 256; rc <<= 1) { -		if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) { -			rc = 0; -			break; -		} -		msleep(rc); -	} - -	if (rc) { -		printk(KERN_ERR DRIVER_NAME -		       ": controller failed to reset\n"); -		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); - -	/* INAB should take much less than reset */ -	for (rc = 1; rc <= 16; 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) { -		printk(KERN_ERR DRIVER_NAME -		       ": card not ready - probe failed on initialization\n"); -		return -ENODEV; -	} - -	writel(TIFM_MMCSD_DATAMASK | 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))) { -		printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n"); -		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); - -	init_waitqueue_head(&host->notify); -	tasklet_init(&host->finish_tasklet, -		     no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd, -		     (unsigned long)host); -	setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host); - -	tifm_sd_ops.request = no_dma ? tifm_sd_request_nodma : tifm_sd_request; -	mmc->ops = &tifm_sd_ops; -	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; -	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE; -	mmc->f_min = 20000000 / 60; -	mmc->f_max = 24000000; -	mmc->max_hw_segs = 1; -	mmc->max_phys_segs = 1; -	// limited by DMA counter - it's safer to stick with -	// block counter has 11 bits though -	mmc->max_blk_count = 256; -	// 2k maximum hw block length -	mmc->max_blk_size = 2048; -	mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; -	mmc->max_seg_size = mmc->max_req_size; -	sock->signal_irq = tifm_sd_signal_irq; -	rc = tifm_sd_initialize_host(host); - -	if (!rc) -		rc = mmc_add_host(mmc); -	if (rc) -		goto out_free_mmc; - -	return 0; -out_free_mmc: -	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); - -	del_timer_sync(&host->timer); -	tifm_sd_terminate(host); -	wait_event_timeout(host->notify, host->flags & EJECT_DONE, -			   host->timeout_jiffies); -	tasklet_kill(&host->finish_tasklet); -	mmc_remove_host(mmc); - -	/* The meaning of the bit majority in this constant is unknown. */ -	writel(0xfff8 & readl(sock->addr + SOCK_CONTROL), -	       sock->addr + SOCK_CONTROL); - -	tifm_set_drvdata(sock, NULL); -	mmc_free_host(mmc); -} - -#ifdef CONFIG_PM - -static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state) -{ -	struct mmc_host *mmc = tifm_get_drvdata(sock); -	int rc; - -	rc = mmc_suspend_host(mmc, state); -	/* The meaning of the bit majority in this constant is unknown. */ -	writel(0xfff8 & readl(sock->addr + SOCK_CONTROL), -	       sock->addr + SOCK_CONTROL); -	return rc; -} - -static int tifm_sd_resume(struct tifm_dev *sock) -{ -	struct mmc_host *mmc = tifm_get_drvdata(sock); -	struct tifm_sd *host = mmc_priv(mmc); - -	if (sock->media_id != FM_SD -	    || tifm_sd_initialize_host(host)) { -		tifm_eject(sock); -		return 0; -	} else { -		return mmc_resume_host(mmc); -	} -} - -#else - -#define tifm_sd_suspend NULL -#define tifm_sd_resume NULL - -#endif /* CONFIG_PM */ - -static tifm_media_id tifm_sd_id_tbl[] = { -	FM_SD, 0 -}; - -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);  | 
