diff options
Diffstat (limited to 'drivers/mmc')
38 files changed, 2154 insertions, 1743 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 172a768036d..21056b9ef0a 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -57,6 +57,7 @@ MODULE_ALIAS("mmc:block");  #define INAND_CMD38_ARG_SECERASE 0x80  #define INAND_CMD38_ARG_SECTRIM1 0x81  #define INAND_CMD38_ARG_SECTRIM2 0x88 +#define MMC_BLK_TIMEOUT_MS  (10 * 60 * 1000)        /* 10 minute timeout */  static DEFINE_MUTEX(block_mutex); @@ -126,6 +127,10 @@ enum mmc_blk_status {  module_param(perdev_minors, int, 0444);  MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device"); +static inline int mmc_blk_part_switch(struct mmc_card *card, +				      struct mmc_blk_data *md); +static int get_card_status(struct mmc_card *card, u32 *status, int retries); +  static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)  {  	struct mmc_blk_data *md; @@ -357,6 +362,38 @@ out:  	return ERR_PTR(err);  } +static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status, +				       u32 retries_max) +{ +	int err; +	u32 retry_count = 0; + +	if (!status || !retries_max) +		return -EINVAL; + +	do { +		err = get_card_status(card, status, 5); +		if (err) +			break; + +		if (!R1_STATUS(*status) && +				(R1_CURRENT_STATE(*status) != R1_STATE_PRG)) +			break; /* RPMB programming operation complete */ + +		/* +		 * Rechedule to give the MMC device a chance to continue +		 * processing the previous command without being polled too +		 * frequently. +		 */ +		usleep_range(1000, 5000); +	} while (++retry_count < retries_max); + +	if (retry_count == retries_max) +		err = -EPERM; + +	return err; +} +  static int mmc_blk_ioctl_cmd(struct block_device *bdev,  	struct mmc_ioc_cmd __user *ic_ptr)  { @@ -368,6 +405,8 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,  	struct mmc_request mrq = {NULL};  	struct scatterlist sg;  	int err; +	int is_rpmb = false; +	u32 status = 0;  	/*  	 * The caller must have CAP_SYS_RAWIO, and must be calling this on the @@ -387,6 +426,9 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,  		goto cmd_err;  	} +	if (md->area_type & MMC_BLK_DATA_AREA_RPMB) +		is_rpmb = true; +  	card = md->queue.card;  	if (IS_ERR(card)) {  		err = PTR_ERR(card); @@ -437,12 +479,23 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,  	mmc_claim_host(card->host); +	err = mmc_blk_part_switch(card, md); +	if (err) +		goto cmd_rel_host; +  	if (idata->ic.is_acmd) {  		err = mmc_app_cmd(card->host, card);  		if (err)  			goto cmd_rel_host;  	} +	if (is_rpmb) { +		err = mmc_set_blockcount(card, data.blocks, +			idata->ic.write_flag & (1 << 31)); +		if (err) +			goto cmd_rel_host; +	} +  	mmc_wait_for_req(card->host, &mrq);  	if (cmd.error) { @@ -478,6 +531,18 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,  		}  	} +	if (is_rpmb) { +		/* +		 * Ensure RPMB command has completed by polling CMD13 +		 * "Send Status". +		 */ +		err = ioctl_rpmb_card_status_poll(card, &status, 5); +		if (err) +			dev_err(mmc_dev(card->host), +					"%s: Card Status=0x%08X, error %d\n", +					__func__, status, err); +	} +  cmd_rel_host:  	mmc_release_host(card->host); @@ -1034,6 +1099,9 @@ static int mmc_blk_err_check(struct mmc_card *card,  	 */  	if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {  		u32 status; +		unsigned long timeout; + +		timeout = jiffies + msecs_to_jiffies(MMC_BLK_TIMEOUT_MS);  		do {  			int err = get_card_status(card, &status, 5);  			if (err) { @@ -1041,6 +1109,17 @@ static int mmc_blk_err_check(struct mmc_card *card,  				       req->rq_disk->disk_name, err);  				return MMC_BLK_CMD_ERR;  			} + +			/* Timeout if the device never becomes ready for data +			 * and never leaves the program state. +			 */ +			if (time_after(jiffies, timeout)) { +				pr_err("%s: Card stuck in programming state!"\ +					" %s %s\n", mmc_hostname(card->host), +					req->rq_disk->disk_name, __func__); + +				return MMC_BLK_CMD_ERR; +			}  			/*  			 * Some cards mishandle the status bits,  			 * so make sure to check both the busy @@ -1504,6 +1583,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,  	md->disk->queue = md->queue.queue;  	md->disk->driverfs_dev = parent;  	set_disk_ro(md->disk, md->read_only || default_ro); +	if (area_type & MMC_BLK_DATA_AREA_RPMB) +		md->disk->flags |= GENHD_FL_NO_PART_SCAN;  	/*  	 * As discussed on lkml, GENHD_FL_REMOVABLE should: diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index e360a979857..fadf52eb5d7 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -68,6 +68,16 @@ static int mmc_queue_thread(void *d)  		if (req || mq->mqrq_prev->req) {  			set_current_state(TASK_RUNNING);  			mq->issue_fn(mq, req); + +			/* +			 * Current request becomes previous request +			 * and vice versa. +			 */ +			mq->mqrq_prev->brq.mrq.data = NULL; +			mq->mqrq_prev->req = NULL; +			tmp = mq->mqrq_prev; +			mq->mqrq_prev = mq->mqrq_cur; +			mq->mqrq_cur = tmp;  		} else {  			if (kthread_should_stop()) {  				set_current_state(TASK_RUNNING); @@ -77,13 +87,6 @@ static int mmc_queue_thread(void *d)  			schedule();  			down(&mq->thread_sem);  		} - -		/* Current request becomes previous request and vice versa. */ -		mq->mqrq_prev->brq.mrq.data = NULL; -		mq->mqrq_prev->req = NULL; -		tmp = mq->mqrq_prev; -		mq->mqrq_prev = mq->mqrq_cur; -		mq->mqrq_cur = tmp;  	} while (1);  	up(&mq->thread_sem); diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 9b68933f27e..420cb6753c1 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -225,8 +225,7 @@ static void mmc_release_card(struct device *dev)  	sdio_free_common_cis(card); -	if (card->info) -		kfree(card->info); +	kfree(card->info);  	kfree(card);  } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 06c42cfb7c3..aaed7687cf0 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -42,6 +42,9 @@  #include "sd_ops.h"  #include "sdio_ops.h" +/* If the device is not responding */ +#define MMC_CORE_TIMEOUT_MS	(10 * 60 * 1000) /* 10 minute timeout */ +  /*   * Background operations can take a long time, depending on the housekeeping   * operations the card has to perform. @@ -1631,6 +1634,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,  {  	struct mmc_command cmd = {0};  	unsigned int qty = 0; +	unsigned long timeout;  	int err;  	/* @@ -1708,6 +1712,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,  	if (mmc_host_is_spi(card->host))  		goto out; +	timeout = jiffies + msecs_to_jiffies(MMC_CORE_TIMEOUT_MS);  	do {  		memset(&cmd, 0, sizeof(struct mmc_command));  		cmd.opcode = MMC_SEND_STATUS; @@ -1721,8 +1726,19 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,  			err = -EIO;  			goto out;  		} + +		/* Timeout if the device never becomes ready for data and +		 * never leaves the program state. +		 */ +		if (time_after(jiffies, timeout)) { +			pr_err("%s: Card stuck in programming state! %s\n", +				mmc_hostname(card->host), __func__); +			err =  -EIO; +			goto out; +		} +  	} while (!(cmd.resp[0] & R1_READY_FOR_DATA) || -		 R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG); +		 (R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG));  out:  	return err;  } @@ -1942,6 +1958,20 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)  }  EXPORT_SYMBOL(mmc_set_blocklen); +int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount, +			bool is_rel_write) +{ +	struct mmc_command cmd = {0}; + +	cmd.opcode = MMC_SET_BLOCK_COUNT; +	cmd.arg = blockcount & 0x0000FFFF; +	if (is_rel_write) +		cmd.arg |= 1 << 31; +	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; +	return mmc_wait_for_cmd(card->host, &cmd, 5); +} +EXPORT_SYMBOL(mmc_set_blockcount); +  static void mmc_hw_reset_for_init(struct mmc_host *host)  {  	if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index d96c643dde1..35c2f85b195 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -144,6 +144,22 @@ static int mmc_ios_show(struct seq_file *s, void *data)  	}  	seq_printf(s, "timing spec:\t%u (%s)\n", ios->timing, str); +	switch (ios->signal_voltage) { +	case MMC_SIGNAL_VOLTAGE_330: +		str = "3.30 V"; +		break; +	case MMC_SIGNAL_VOLTAGE_180: +		str = "1.80 V"; +		break; +	case MMC_SIGNAL_VOLTAGE_120: +		str = "1.20 V"; +		break; +	default: +		str = "invalid"; +		break; +	} +	seq_printf(s, "signal voltage:\t%u (%s)\n", ios->chip_select, str); +  	return 0;  } diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 7cc46382fd6..e6e39111e05 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -239,7 +239,7 @@ static void mmc_select_card_type(struct mmc_card *card)  {  	struct mmc_host *host = card->host;  	u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK; -	unsigned int caps = host->caps, caps2 = host->caps2; +	u32 caps = host->caps, caps2 = host->caps2;  	unsigned int hs_max_dtr = 0;  	if (card_type & EXT_CSD_CARD_TYPE_26) @@ -491,6 +491,17 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)  		card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];  		card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; + +		/* +		 * RPMB regions are defined in multiples of 128K. +		 */ +		card->ext_csd.raw_rpmb_size_mult = ext_csd[EXT_CSD_RPMB_MULT]; +		if (ext_csd[EXT_CSD_RPMB_MULT]) { +			mmc_part_add(card, ext_csd[EXT_CSD_RPMB_MULT] << 17, +				EXT_CSD_PART_CONFIG_ACC_RPMB, +				"rpmb", 0, false, +				MMC_BLK_DATA_AREA_RPMB); +		}  	}  	card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT]; @@ -615,6 +626,8 @@ MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);  MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",  		card->ext_csd.enhanced_area_offset);  MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size); +MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult); +MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);  static struct attribute *mmc_std_attrs[] = {  	&dev_attr_cid.attr, @@ -630,6 +643,8 @@ static struct attribute *mmc_std_attrs[] = {  	&dev_attr_serial.attr,  	&dev_attr_enhanced_area_offset.attr,  	&dev_attr_enhanced_area_size.attr, +	&dev_attr_raw_rpmb_size_mult.attr, +	&dev_attr_rel_sectors.attr,  	NULL,  }; @@ -1051,6 +1066,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,  	if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {  		if (max_dtr > card->ext_csd.hs_max_dtr)  			max_dtr = card->ext_csd.hs_max_dtr; +		if (mmc_card_highspeed(card) && (max_dtr > 52000000)) +			max_dtr = 52000000;  	} else if (max_dtr > card->csd.max_dtr) {  		max_dtr = card->csd.max_dtr;  	} diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index a0e172042e6..6d8f7012d73 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -21,6 +21,8 @@  #include "core.h"  #include "mmc_ops.h" +#define MMC_OPS_TIMEOUT_MS	(10 * 60 * 1000) /* 10 minute timeout */ +  static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)  {  	int err; @@ -409,6 +411,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,  {  	int err;  	struct mmc_command cmd = {0}; +	unsigned long timeout;  	u32 status;  	BUG_ON(!card); @@ -437,6 +440,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,  		return 0;  	/* Must check status to be sure of no errors */ +	timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);  	do {  		err = mmc_send_status(card, &status);  		if (err) @@ -445,6 +449,13 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,  			break;  		if (mmc_host_is_spi(card->host))  			break; + +		/* Timeout if the device never leaves the program state. */ +		if (time_after(jiffies, timeout)) { +			pr_err("%s: Card stuck in programming state! %s\n", +				mmc_hostname(card->host), __func__); +			return -ETIMEDOUT; +		}  	} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);  	if (mmc_host_is_spi(card->host)) { diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 6bf68799fe9..5e57048e2c1 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -193,7 +193,21 @@ static int sdio_bus_remove(struct device *dev)  }  #ifdef CONFIG_PM + +#ifdef CONFIG_PM_SLEEP +static int pm_no_operation(struct device *dev) +{ +	/* +	 * Prevent the PM core from calling SDIO device drivers' suspend +	 * callback routines, which it is not supposed to do, by using this +	 * empty function as the bus type suspend callaback for SDIO. +	 */ +	return 0; +} +#endif +  static const struct dev_pm_ops sdio_bus_pm_ops = { +	SET_SYSTEM_SLEEP_PM_OPS(pm_no_operation, pm_no_operation)  	SET_RUNTIME_PM_OPS(  		pm_generic_runtime_suspend,  		pm_generic_runtime_resume, @@ -258,8 +272,7 @@ static void sdio_release_func(struct device *dev)  	sdio_free_func_cis(func); -	if (func->info) -		kfree(func->info); +	kfree(func->info);  	kfree(func);  } diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c index 8f6f5ac131f..78cb4d5d9d5 100644 --- a/drivers/mmc/core/sdio_io.c +++ b/drivers/mmc/core/sdio_io.c @@ -188,8 +188,7 @@ EXPORT_SYMBOL_GPL(sdio_set_block_size);   */  static inline unsigned int sdio_max_byte_size(struct sdio_func *func)  { -	unsigned mval =	min(func->card->host->max_seg_size, -			    func->card->host->max_blk_size); +	unsigned mval =	func->card->host->max_blk_size;  	if (mmc_blksz_for_byte_mode(func->card))  		mval = min(mval, func->cur_blksize); @@ -311,11 +310,8 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,  	/* Do the bulk of the transfer using block mode (if supported). */  	if (func->card->cccr.multi_block && (size > sdio_max_byte_size(func))) {  		/* Blocks per command is limited by host count, host transfer -		 * size (we only use a single sg entry) and the maximum for -		 * IO_RW_EXTENDED of 511 blocks. */ -		max_blocks = min(func->card->host->max_blk_count, -			func->card->host->max_seg_size / func->cur_blksize); -		max_blocks = min(max_blocks, 511u); +		 * size and the maximum for IO_RW_EXTENDED of 511 blocks. */ +		max_blocks = min(func->card->host->max_blk_count, 511u);  		while (remainder >= func->cur_blksize) {  			unsigned blocks; diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c index d29e20630ee..62508b457c4 100644 --- a/drivers/mmc/core/sdio_ops.c +++ b/drivers/mmc/core/sdio_ops.c @@ -124,7 +124,10 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,  	struct mmc_request mrq = {NULL};  	struct mmc_command cmd = {0};  	struct mmc_data data = {0}; -	struct scatterlist sg; +	struct scatterlist sg, *sg_ptr; +	struct sg_table sgtable; +	unsigned int nents, left_size, i; +	unsigned int seg_size = card->host->max_seg_size;  	BUG_ON(!card);  	BUG_ON(fn > 7); @@ -152,15 +155,36 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,  	/* Code in host drivers/fwk assumes that "blocks" always is >=1 */  	data.blocks = blocks ? blocks : 1;  	data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; -	data.sg = &sg; -	data.sg_len = 1; -	sg_init_one(&sg, buf, data.blksz * data.blocks); +	left_size = data.blksz * data.blocks; +	nents = (left_size - 1) / seg_size + 1; +	if (nents > 1) { +		if (sg_alloc_table(&sgtable, nents, GFP_KERNEL)) +			return -ENOMEM; + +		data.sg = sgtable.sgl; +		data.sg_len = nents; + +		for_each_sg(data.sg, sg_ptr, data.sg_len, i) { +			sg_set_page(sg_ptr, virt_to_page(buf + (i * seg_size)), +					min(seg_size, left_size), +					offset_in_page(buf + (i * seg_size))); +			left_size = left_size - seg_size; +		} +	} else { +		data.sg = &sg; +		data.sg_len = 1; + +		sg_init_one(&sg, buf, left_size); +	}  	mmc_set_data_timeout(&data, card);  	mmc_wait_for_req(card->host, &mrq); +	if (nents > 1) +		sg_free_table(&sgtable); +  	if (cmd.error)  		return cmd.error;  	if (data.error) diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 08c6b3dfe08..16a1c0b6f26 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -27,7 +27,13 @@ struct mmc_gpio {  static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)  {  	/* Schedule a card detection after a debounce timeout */ -	mmc_detect_change(dev_id, msecs_to_jiffies(100)); +	struct mmc_host *host = dev_id; + +	if (host->ops->card_event) +		host->ops->card_event(host); + +	mmc_detect_change(host, msecs_to_jiffies(200)); +  	return IRQ_HANDLED;  } diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 9bf10e7bbfa..bebbe167fd8 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -81,6 +81,18 @@ config MMC_RICOH_MMC  	  If unsure, say Y. +config MMC_SDHCI_ACPI +	tristate "SDHCI support for ACPI enumerated SDHCI controllers" +	depends on MMC_SDHCI && ACPI +	help +	  This selects support for ACPI enumerated SDHCI controllers, +	  identified by ACPI Compatibility ID PNP0D40 or specific +	  ACPI Hardware IDs. + +	  If you have a controller with this interface, say Y or M here. + +	  If unsure, say N. +  config MMC_SDHCI_PLTFM  	tristate "SDHCI platform and OF driver helper"  	depends on MMC_SDHCI @@ -270,26 +282,8 @@ config MMC_AU1X  	  If unsure, say N. -choice -	prompt "Atmel SD/MMC Driver" -	depends on AVR32 || ARCH_AT91 -	default MMC_ATMELMCI if AVR32 -	help -	  Choose which driver to use for the Atmel MCI Silicon - -config MMC_AT91 -	tristate "AT91 SD/MMC Card Interface support (DEPRECATED)" -	depends on ARCH_AT91 -	help -	  This selects the AT91 MCI controller. This driver will -	  be removed soon (for more information have a look to -	  Documentation/feature-removal-schedule.txt). Please use -	  MMC_ATMEL_MCI. - -	  If unsure, say N. -  config MMC_ATMELMCI -	tristate "Atmel Multimedia Card Interface support" +	tristate "Atmel SD/MMC Driver (Multimedia Card Interface)"  	depends on AVR32 || ARCH_AT91  	help  	  This selects the Atmel Multimedia Card Interface driver. If @@ -298,8 +292,6 @@ config MMC_ATMELMCI  	  If unsure, say N. -endchoice -  config MMC_ATMELMCI_DMA  	bool "Atmel MCI DMA support"  	depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE @@ -621,3 +613,14 @@ config MMC_USHC  	  Note: These controllers only support SDIO cards and do not  	  support MMC or SD memory cards. + +config MMC_WMT +	tristate "Wondermedia SD/MMC Host Controller support" +	depends on ARCH_VT8500 +	default y +	help +	  This selects support for the SD/MMC Host Controller on +	  Wondermedia WM8505/WM8650 based SoCs. + +	  To compile this driver as a module, choose M here: the +	  module will be called wmt-sdmmc. diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 17ad0a7ba40..c5eddc1b483 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_MMC_MXS)		+= mxs-mmc.o  obj-$(CONFIG_MMC_SDHCI)		+= sdhci.o  obj-$(CONFIG_MMC_SDHCI_PCI)	+= sdhci-pci.o  obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI))	+= sdhci-pci-data.o +obj-$(CONFIG_MMC_SDHCI_ACPI)	+= sdhci-acpi.o  obj-$(CONFIG_MMC_SDHCI_PXAV3)	+= sdhci-pxav3.o  obj-$(CONFIG_MMC_SDHCI_PXAV2)	+= sdhci-pxav2.o  obj-$(CONFIG_MMC_SDHCI_S3C)	+= sdhci-s3c.o @@ -17,7 +18,6 @@ obj-$(CONFIG_MMC_WBSD)		+= wbsd.o  obj-$(CONFIG_MMC_AU1X)		+= au1xmmc.o  obj-$(CONFIG_MMC_OMAP)		+= omap.o  obj-$(CONFIG_MMC_OMAP_HS)	+= omap_hsmmc.o -obj-$(CONFIG_MMC_AT91)		+= at91_mci.o  obj-$(CONFIG_MMC_ATMELMCI)	+= atmel-mci.o  obj-$(CONFIG_MMC_TIFM_SD)	+= tifm_sd.o  obj-$(CONFIG_MMC_MSM)		+= msm_sdcc.o @@ -45,6 +45,7 @@ obj-$(CONFIG_MMC_SH_MMCIF)	+= sh_mmcif.o  obj-$(CONFIG_MMC_JZ4740)	+= jz4740_mmc.o  obj-$(CONFIG_MMC_VUB300)	+= vub300.o  obj-$(CONFIG_MMC_USHC)		+= ushc.o +obj-$(CONFIG_MMC_WMT)		+= wmt-sdmmc.o  obj-$(CONFIG_MMC_SDHCI_PLTFM)		+= sdhci-pltfm.o  obj-$(CONFIG_MMC_SDHCI_CNS3XXX)		+= sdhci-cns3xxx.o diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c deleted file mode 100644 index 74bed0fc23e..00000000000 --- a/drivers/mmc/host/at91_mci.c +++ /dev/null @@ -1,1219 +0,0 @@ -/* - *  linux/drivers/mmc/host/at91_mci.c - ATMEL AT91 MCI Driver - * - *  Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved - * - *  Copyright (C) 2006 Malcolm Noyes - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* -   This is the AT91 MCI driver that has been tested with both MMC cards -   and SD-cards.  Boards that support write protect are now supported. -   The CCAT91SBC001 board does not support SD cards. - -   The three entry points are at91_mci_request, at91_mci_set_ios -   and at91_mci_get_ro. - -   SET IOS -     This configures the device to put it into the correct mode and clock speed -     required. - -   MCI REQUEST -     MCI request processes the commands sent in the mmc_request structure. This -     can consist of a processing command and a stop command in the case of -     multiple block transfers. - -     There are three main types of request, commands, reads and writes. - -     Commands are straight forward. The command is submitted to the controller and -     the request function returns. When the controller generates an interrupt to indicate -     the command is finished, the response to the command are read and the mmc_request_done -     function called to end the request. - -     Reads and writes work in a similar manner to normal commands but involve the PDC (DMA) -     controller to manage the transfers. - -     A read is done from the controller directly to the scatterlist passed in from the request. -     Due to a bug in the AT91RM9200 controller, when a read is completed, all the words are byte -     swapped in the scatterlist buffers.  AT91SAM926x are not affected by this bug. - -     The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY - -     A write is slightly different in that the bytes to write are read from the scatterlist -     into a dma memory buffer (this is in case the source buffer should be read only). The -     entire write buffer is then done from this single dma memory buffer. - -     The sequence of write interrupts is: ENDTX, TXBUFE, NOTBUSY, CMDRDY - -   GET RO -     Gets the status of the write protect pin, if available. -*/ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/platform_device.h> -#include <linux/interrupt.h> -#include <linux/blkdev.h> -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/dma-mapping.h> -#include <linux/clk.h> -#include <linux/atmel_pdc.h> -#include <linux/gfp.h> -#include <linux/highmem.h> - -#include <linux/mmc/host.h> -#include <linux/mmc/sdio.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/gpio.h> - -#include <mach/board.h> -#include <mach/cpu.h> - -#include "at91_mci.h" - -#define DRIVER_NAME "at91_mci" - -static inline int at91mci_is_mci1rev2xx(void) -{ -	return (   cpu_is_at91sam9260() -		|| cpu_is_at91sam9263() -		|| cpu_is_at91sam9rl() -		|| cpu_is_at91sam9g10() -		|| cpu_is_at91sam9g20() -		); -} - -#define FL_SENT_COMMAND	(1 << 0) -#define FL_SENT_STOP	(1 << 1) - -#define AT91_MCI_ERRORS	(AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE	\ -		| AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE		\ -		| AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE) - -#define at91_mci_read(host, reg)	__raw_readl((host)->baseaddr + (reg)) -#define at91_mci_write(host, reg, val)	__raw_writel((val), (host)->baseaddr + (reg)) - -#define MCI_BLKSIZE 		512 -#define MCI_MAXBLKSIZE 		4095 -#define MCI_BLKATONCE 		256 -#define MCI_BUFSIZE 		(MCI_BLKSIZE * MCI_BLKATONCE) - -/* - * Low level type for this driver - */ -struct at91mci_host -{ -	struct mmc_host *mmc; -	struct mmc_command *cmd; -	struct mmc_request *request; - -	void __iomem *baseaddr; -	int irq; - -	struct at91_mmc_data *board; -	int present; - -	struct clk *mci_clk; - -	/* -	 * Flag indicating when the command has been sent. This is used to -	 * work out whether or not to send the stop -	 */ -	unsigned int flags; -	/* flag for current bus settings */ -	u32 bus_mode; - -	/* DMA buffer used for transmitting */ -	unsigned int* buffer; -	dma_addr_t physical_address; -	unsigned int total_length; - -	/* Latest in the scatterlist that has been enabled for transfer, but not freed */ -	int in_use_index; - -	/* Latest in the scatterlist that has been enabled for transfer */ -	int transfer_index; - -	/* Timer for timeouts */ -	struct timer_list timer; -}; - -/* - * Reset the controller and restore most of the state - */ -static void at91_reset_host(struct at91mci_host *host) -{ -	unsigned long flags; -	u32 mr; -	u32 sdcr; -	u32 dtor; -	u32 imr; - -	local_irq_save(flags); -	imr = at91_mci_read(host, AT91_MCI_IMR); - -	at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); - -	/* save current state */ -	mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff; -	sdcr = at91_mci_read(host, AT91_MCI_SDCR); -	dtor = at91_mci_read(host, AT91_MCI_DTOR); - -	/* reset the controller */ -	at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST); - -	/* restore state */ -	at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN); -	at91_mci_write(host, AT91_MCI_MR, mr); -	at91_mci_write(host, AT91_MCI_SDCR, sdcr); -	at91_mci_write(host, AT91_MCI_DTOR, dtor); -	at91_mci_write(host, AT91_MCI_IER, imr); - -	/* make sure sdio interrupts will fire */ -	at91_mci_read(host, AT91_MCI_SR); - -	local_irq_restore(flags); -} - -static void at91_timeout_timer(unsigned long data) -{ -	struct at91mci_host *host; - -	host = (struct at91mci_host *)data; - -	if (host->request) { -		dev_err(host->mmc->parent, "Timeout waiting end of packet\n"); - -		if (host->cmd && host->cmd->data) { -			host->cmd->data->error = -ETIMEDOUT; -		} else { -			if (host->cmd) -				host->cmd->error = -ETIMEDOUT; -			else -				host->request->cmd->error = -ETIMEDOUT; -		} - -		at91_reset_host(host); -		mmc_request_done(host->mmc, host->request); -	} -} - -/* - * Copy from sg to a dma block - used for transfers - */ -static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data) -{ -	unsigned int len, i, size; -	unsigned *dmabuf = host->buffer; - -	size = data->blksz * data->blocks; -	len = data->sg_len; - -	/* MCI1 rev2xx Data Write Operation and number of bytes erratum */ -	if (at91mci_is_mci1rev2xx()) -		if (host->total_length == 12) -			memset(dmabuf, 0, 12); - -	/* -	 * Just loop through all entries. Size might not -	 * be the entire list though so make sure that -	 * we do not transfer too much. -	 */ -	for (i = 0; i < len; i++) { -		struct scatterlist *sg; -		int amount; -		unsigned int *sgbuffer; - -		sg = &data->sg[i]; - -		sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset; -		amount = min(size, sg->length); -		size -= amount; - -		if (cpu_is_at91rm9200()) {	/* AT91RM9200 errata */ -			int index; - -			for (index = 0; index < (amount / 4); index++) -				*dmabuf++ = swab32(sgbuffer[index]); -		} else { -			char *tmpv = (char *)dmabuf; -			memcpy(tmpv, sgbuffer, amount); -			tmpv += amount; -			dmabuf = (unsigned *)tmpv; -		} - -		kunmap_atomic(sgbuffer); - -		if (size == 0) -			break; -	} - -	/* -	 * Check that we didn't get a request to transfer -	 * more data than can fit into the SG list. -	 */ -	BUG_ON(size != 0); -} - -/* - * Handle after a dma read - */ -static void at91_mci_post_dma_read(struct at91mci_host *host) -{ -	struct mmc_command *cmd; -	struct mmc_data *data; -	unsigned int len, i, size; -	unsigned *dmabuf = host->buffer; - -	pr_debug("post dma read\n"); - -	cmd = host->cmd; -	if (!cmd) { -		pr_debug("no command\n"); -		return; -	} - -	data = cmd->data; -	if (!data) { -		pr_debug("no data\n"); -		return; -	} - -	size = data->blksz * data->blocks; -	len = data->sg_len; - -	at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_ENDRX); -	at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF); - -	for (i = 0; i < len; i++) { -		struct scatterlist *sg; -		int amount; -		unsigned int *sgbuffer; - -		sg = &data->sg[i]; - -		sgbuffer = kmap_atomic(sg_page(sg)) + sg->offset; -		amount = min(size, sg->length); -		size -= amount; - -		if (cpu_is_at91rm9200()) {	/* AT91RM9200 errata */ -			int index; -			for (index = 0; index < (amount / 4); index++) -				sgbuffer[index] = swab32(*dmabuf++); -		} else { -			char *tmpv = (char *)dmabuf; -			memcpy(sgbuffer, tmpv, amount); -			tmpv += amount; -			dmabuf = (unsigned *)tmpv; -		} - -		flush_kernel_dcache_page(sg_page(sg)); -		kunmap_atomic(sgbuffer); -		data->bytes_xfered += amount; -		if (size == 0) -			break; -	} - -	pr_debug("post dma read done\n"); -} - -/* - * Handle transmitted data - */ -static void at91_mci_handle_transmitted(struct at91mci_host *host) -{ -	struct mmc_command *cmd; -	struct mmc_data *data; - -	pr_debug("Handling the transmit\n"); - -	/* Disable the transfer */ -	at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); - -	/* Now wait for cmd ready */ -	at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE); - -	cmd = host->cmd; -	if (!cmd) return; - -	data = cmd->data; -	if (!data) return; - -	if (cmd->data->blocks > 1) { -		pr_debug("multiple write : wait for BLKE...\n"); -		at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE); -	} else -		at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY); -} - -/* - * Update bytes transfered count during a write operation - */ -static void at91_mci_update_bytes_xfered(struct at91mci_host *host) -{ -	struct mmc_data *data; - -	/* always deal with the effective request (and not the current cmd) */ - -	if (host->request->cmd && host->request->cmd->error != 0) -		return; - -	if (host->request->data) { -		data = host->request->data; -		if (data->flags & MMC_DATA_WRITE) { -			/* card is in IDLE mode now */ -			pr_debug("-> bytes_xfered %d, total_length = %d\n", -				data->bytes_xfered, host->total_length); -			data->bytes_xfered = data->blksz * data->blocks; -		} -	} -} - - -/*Handle after command sent ready*/ -static int at91_mci_handle_cmdrdy(struct at91mci_host *host) -{ -	if (!host->cmd) -		return 1; -	else if (!host->cmd->data) { -		if (host->flags & FL_SENT_STOP) { -			/*After multi block write, we must wait for NOTBUSY*/ -			at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY); -		} else return 1; -	} else if (host->cmd->data->flags & MMC_DATA_WRITE) { -		/*After sendding multi-block-write command, start DMA transfer*/ -		at91_mci_write(host, AT91_MCI_IER, AT91_MCI_TXBUFE | AT91_MCI_BLKE); -		at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); -	} - -	/* command not completed, have to wait */ -	return 0; -} - - -/* - * Enable the controller - */ -static void at91_mci_enable(struct at91mci_host *host) -{ -	unsigned int mr; - -	at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN); -	at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); -	at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC); -	mr = AT91_MCI_PDCMODE | 0x34a; - -	if (at91mci_is_mci1rev2xx()) -		mr |= AT91_MCI_RDPROOF | AT91_MCI_WRPROOF; - -	at91_mci_write(host, AT91_MCI_MR, mr); - -	/* use Slot A or B (only one at same time) */ -	at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b); -} - -/* - * Disable the controller - */ -static void at91_mci_disable(struct at91mci_host *host) -{ -	at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST); -} - -/* - * Send a command - */ -static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd) -{ -	unsigned int cmdr, mr; -	unsigned int block_length; -	struct mmc_data *data = cmd->data; - -	unsigned int blocks; -	unsigned int ier = 0; - -	host->cmd = cmd; - -	/* Needed for leaving busy state before CMD1 */ -	if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) { -		pr_debug("Clearing timeout\n"); -		at91_mci_write(host, AT91_MCI_ARGR, 0); -		at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD); -		while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) { -			/* spin */ -			pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR)); -		} -	} - -	cmdr = cmd->opcode; - -	if (mmc_resp_type(cmd) == MMC_RSP_NONE) -		cmdr |= AT91_MCI_RSPTYP_NONE; -	else { -		/* if a response is expected then allow maximum response latancy */ -		cmdr |= AT91_MCI_MAXLAT; -		/* set 136 bit response for R2, 48 bit response otherwise */ -		if (mmc_resp_type(cmd) == MMC_RSP_R2) -			cmdr |= AT91_MCI_RSPTYP_136; -		else -			cmdr |= AT91_MCI_RSPTYP_48; -	} - -	if (data) { - -		if (cpu_is_at91rm9200() || cpu_is_at91sam9261()) { -			if (data->blksz & 0x3) { -				pr_debug("Unsupported block size\n"); -				cmd->error = -EINVAL; -				mmc_request_done(host->mmc, host->request); -				return; -			} -			if (data->flags & MMC_DATA_STREAM) { -				pr_debug("Stream commands not supported\n"); -				cmd->error = -EINVAL; -				mmc_request_done(host->mmc, host->request); -				return; -			} -		} - -		block_length = data->blksz; -		blocks = data->blocks; - -		/* always set data start - also set direction flag for read */ -		if (data->flags & MMC_DATA_READ) -			cmdr |= (AT91_MCI_TRDIR | AT91_MCI_TRCMD_START); -		else if (data->flags & MMC_DATA_WRITE) -			cmdr |= AT91_MCI_TRCMD_START; - -		if (cmd->opcode == SD_IO_RW_EXTENDED) { -			cmdr |= AT91_MCI_TRTYP_SDIO_BLOCK; -		} else { -			if (data->flags & MMC_DATA_STREAM) -				cmdr |= AT91_MCI_TRTYP_STREAM; -			if (data->blocks > 1) -				cmdr |= AT91_MCI_TRTYP_MULTIPLE; -		} -	} -	else { -		block_length = 0; -		blocks = 0; -	} - -	if (host->flags & FL_SENT_STOP) -		cmdr |= AT91_MCI_TRCMD_STOP; - -	if (host->bus_mode == MMC_BUSMODE_OPENDRAIN) -		cmdr |= AT91_MCI_OPDCMD; - -	/* -	 * Set the arguments and send the command -	 */ -	pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n", -		cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR)); - -	if (!data) { -		at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS); -		at91_mci_write(host, ATMEL_PDC_RPR, 0); -		at91_mci_write(host, ATMEL_PDC_RCR, 0); -		at91_mci_write(host, ATMEL_PDC_RNPR, 0); -		at91_mci_write(host, ATMEL_PDC_RNCR, 0); -		at91_mci_write(host, ATMEL_PDC_TPR, 0); -		at91_mci_write(host, ATMEL_PDC_TCR, 0); -		at91_mci_write(host, ATMEL_PDC_TNPR, 0); -		at91_mci_write(host, ATMEL_PDC_TNCR, 0); -		ier = AT91_MCI_CMDRDY; -	} else { -		/* zero block length and PDC mode */ -		mr = at91_mci_read(host, AT91_MCI_MR) & 0x5fff; -		mr |= (data->blksz & 0x3) ? AT91_MCI_PDCFBYTE : 0; -		mr |= (block_length << 16); -		mr |= AT91_MCI_PDCMODE; -		at91_mci_write(host, AT91_MCI_MR, mr); - -		if (!(cpu_is_at91rm9200() || cpu_is_at91sam9261())) -			at91_mci_write(host, AT91_MCI_BLKR, -				AT91_MCI_BLKR_BCNT(blocks) | -				AT91_MCI_BLKR_BLKLEN(block_length)); - -		/* -		 * Disable the PDC controller -		 */ -		at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); - -		if (cmdr & AT91_MCI_TRCMD_START) { -			data->bytes_xfered = 0; -			host->transfer_index = 0; -			host->in_use_index = 0; -			if (cmdr & AT91_MCI_TRDIR) { -				/* -				 * Handle a read -				 */ -				host->total_length = 0; - -				at91_mci_write(host, ATMEL_PDC_RPR, host->physical_address); -				at91_mci_write(host, ATMEL_PDC_RCR, (data->blksz & 0x3) ? -					(blocks * block_length) : (blocks * block_length) / 4); -				at91_mci_write(host, ATMEL_PDC_RNPR, 0); -				at91_mci_write(host, ATMEL_PDC_RNCR, 0); - -				ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */; -			} -			else { -				/* -				 * Handle a write -				 */ -				host->total_length = block_length * blocks; -				/* -				 * MCI1 rev2xx Data Write Operation and -				 * number of bytes erratum -				 */ -				if (at91mci_is_mci1rev2xx()) -					if (host->total_length < 12) -						host->total_length = 12; - -				at91_mci_sg_to_dma(host, data); - -				pr_debug("Transmitting %d bytes\n", host->total_length); - -				at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address); -				at91_mci_write(host, ATMEL_PDC_TCR, (data->blksz & 0x3) ? -						host->total_length : host->total_length / 4); - -				ier = AT91_MCI_CMDRDY; -			} -		} -	} - -	/* -	 * Send the command and then enable the PDC - not the other way round as -	 * the data sheet says -	 */ - -	at91_mci_write(host, AT91_MCI_ARGR, cmd->arg); -	at91_mci_write(host, AT91_MCI_CMDR, cmdr); - -	if (cmdr & AT91_MCI_TRCMD_START) { -		if (cmdr & AT91_MCI_TRDIR) -			at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); -	} - -	/* Enable selected interrupts */ -	at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier); -} - -/* - * Process the next step in the request - */ -static void at91_mci_process_next(struct at91mci_host *host) -{ -	if (!(host->flags & FL_SENT_COMMAND)) { -		host->flags |= FL_SENT_COMMAND; -		at91_mci_send_command(host, host->request->cmd); -	} -	else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) { -		host->flags |= FL_SENT_STOP; -		at91_mci_send_command(host, host->request->stop); -	} else { -		del_timer(&host->timer); -		/* the at91rm9200 mci controller hangs after some transfers, -		 * and the workaround is to reset it after each transfer. -		 */ -		if (cpu_is_at91rm9200()) -			at91_reset_host(host); -		mmc_request_done(host->mmc, host->request); -	} -} - -/* - * Handle a command that has been completed - */ -static void at91_mci_completed_command(struct at91mci_host *host, unsigned int status) -{ -	struct mmc_command *cmd = host->cmd; -	struct mmc_data *data = cmd->data; - -	at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB)); - -	cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0)); -	cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1)); -	cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2)); -	cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3)); - -	pr_debug("Status = %08X/%08x [%08X %08X %08X %08X]\n", -		 status, at91_mci_read(host, AT91_MCI_SR), -		 cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]); - -	if (status & AT91_MCI_ERRORS) { -		if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) { -			cmd->error = 0; -		} -		else { -			if (status & (AT91_MCI_DTOE | AT91_MCI_DCRCE)) { -				if (data) { -					if (status & AT91_MCI_DTOE) -						data->error = -ETIMEDOUT; -					else if (status & AT91_MCI_DCRCE) -						data->error = -EILSEQ; -				} -			} else { -				if (status & AT91_MCI_RTOE) -					cmd->error = -ETIMEDOUT; -				else if (status & AT91_MCI_RCRCE) -					cmd->error = -EILSEQ; -				else -					cmd->error = -EIO; -			} - -			pr_debug("Error detected and set to %d/%d (cmd = %d, retries = %d)\n", -				cmd->error, data ? data->error : 0, -				 cmd->opcode, cmd->retries); -		} -	} -	else -		cmd->error = 0; - -	at91_mci_process_next(host); -} - -/* - * Handle an MMC request - */ -static void at91_mci_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ -	struct at91mci_host *host = mmc_priv(mmc); -	host->request = mrq; -	host->flags = 0; - -	/* more than 1s timeout needed with slow SD cards */ -	mod_timer(&host->timer, jiffies +  msecs_to_jiffies(2000)); - -	at91_mci_process_next(host); -} - -/* - * Set the IOS - */ -static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ -	int clkdiv; -	struct at91mci_host *host = mmc_priv(mmc); -	unsigned long at91_master_clock = clk_get_rate(host->mci_clk); - -	host->bus_mode = ios->bus_mode; - -	if (ios->clock == 0) { -		/* Disable the MCI controller */ -		at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS); -		clkdiv = 0; -	} -	else { -		/* Enable the MCI controller */ -		at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN); - -		if ((at91_master_clock % (ios->clock * 2)) == 0) -			clkdiv = ((at91_master_clock / ios->clock) / 2) - 1; -		else -			clkdiv = (at91_master_clock / ios->clock) / 2; - -		pr_debug("clkdiv = %d. mcck = %ld\n", clkdiv, -			at91_master_clock / (2 * (clkdiv + 1))); -	} -	if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) { -		pr_debug("MMC: Setting controller bus width to 4\n"); -		at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) | AT91_MCI_SDCBUS); -	} -	else { -		pr_debug("MMC: Setting controller bus width to 1\n"); -		at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS); -	} - -	/* Set the clock divider */ -	at91_mci_write(host, AT91_MCI_MR, (at91_mci_read(host, AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv); - -	/* maybe switch power to the card */ -	if (gpio_is_valid(host->board->vcc_pin)) { -		switch (ios->power_mode) { -			case MMC_POWER_OFF: -				gpio_set_value(host->board->vcc_pin, 0); -				break; -			case MMC_POWER_UP: -				gpio_set_value(host->board->vcc_pin, 1); -				break; -			case MMC_POWER_ON: -				break; -			default: -				WARN_ON(1); -		} -	} -} - -/* - * Handle an interrupt - */ -static irqreturn_t at91_mci_irq(int irq, void *devid) -{ -	struct at91mci_host *host = devid; -	int completed = 0; -	unsigned int int_status, int_mask; - -	int_status = at91_mci_read(host, AT91_MCI_SR); -	int_mask = at91_mci_read(host, AT91_MCI_IMR); - -	pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask, -		int_status & int_mask); - -	int_status = int_status & int_mask; - -	if (int_status & AT91_MCI_ERRORS) { -		completed = 1; - -		if (int_status & AT91_MCI_UNRE) -			pr_debug("MMC: Underrun error\n"); -		if (int_status & AT91_MCI_OVRE) -			pr_debug("MMC: Overrun error\n"); -		if (int_status & AT91_MCI_DTOE) -			pr_debug("MMC: Data timeout\n"); -		if (int_status & AT91_MCI_DCRCE) -			pr_debug("MMC: CRC error in data\n"); -		if (int_status & AT91_MCI_RTOE) -			pr_debug("MMC: Response timeout\n"); -		if (int_status & AT91_MCI_RENDE) -			pr_debug("MMC: Response end bit error\n"); -		if (int_status & AT91_MCI_RCRCE) -			pr_debug("MMC: Response CRC error\n"); -		if (int_status & AT91_MCI_RDIRE) -			pr_debug("MMC: Response direction error\n"); -		if (int_status & AT91_MCI_RINDE) -			pr_debug("MMC: Response index error\n"); -	} else { -		/* Only continue processing if no errors */ - -		if (int_status & AT91_MCI_TXBUFE) { -			pr_debug("TX buffer empty\n"); -			at91_mci_handle_transmitted(host); -		} - -		if (int_status & AT91_MCI_ENDRX) { -			pr_debug("ENDRX\n"); -			at91_mci_post_dma_read(host); -		} - -		if (int_status & AT91_MCI_RXBUFF) { -			pr_debug("RX buffer full\n"); -			at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); -			at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_RXBUFF | AT91_MCI_ENDRX); -			completed = 1; -		} - -		if (int_status & AT91_MCI_ENDTX) -			pr_debug("Transmit has ended\n"); - -		if (int_status & AT91_MCI_NOTBUSY) { -			pr_debug("Card is ready\n"); -			at91_mci_update_bytes_xfered(host); -			completed = 1; -		} - -		if (int_status & AT91_MCI_DTIP) -			pr_debug("Data transfer in progress\n"); - -		if (int_status & AT91_MCI_BLKE) { -			pr_debug("Block transfer has ended\n"); -			if (host->request->data && host->request->data->blocks > 1) { -				/* multi block write : complete multi write -				 * command and send stop */ -				completed = 1; -			} else { -				at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY); -			} -		} - -		if (int_status & AT91_MCI_SDIOIRQA) -			mmc_signal_sdio_irq(host->mmc); - -		if (int_status & AT91_MCI_SDIOIRQB) -			mmc_signal_sdio_irq(host->mmc); - -		if (int_status & AT91_MCI_TXRDY) -			pr_debug("Ready to transmit\n"); - -		if (int_status & AT91_MCI_RXRDY) -			pr_debug("Ready to receive\n"); - -		if (int_status & AT91_MCI_CMDRDY) { -			pr_debug("Command ready\n"); -			completed = at91_mci_handle_cmdrdy(host); -		} -	} - -	if (completed) { -		pr_debug("Completed command\n"); -		at91_mci_write(host, AT91_MCI_IDR, 0xffffffff & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB)); -		at91_mci_completed_command(host, int_status); -	} else -		at91_mci_write(host, AT91_MCI_IDR, int_status & ~(AT91_MCI_SDIOIRQA | AT91_MCI_SDIOIRQB)); - -	return IRQ_HANDLED; -} - -static irqreturn_t at91_mmc_det_irq(int irq, void *_host) -{ -	struct at91mci_host *host = _host; -	int present; - -	/* entering this ISR means that we have configured det_pin: -	 * we can use its value in board structure */ -	present = !gpio_get_value(host->board->det_pin); - -	/* -	 * we expect this irq on both insert and remove, -	 * and use a short delay to debounce. -	 */ -	if (present != host->present) { -		host->present = present; -		pr_debug("%s: card %s\n", mmc_hostname(host->mmc), -			present ? "insert" : "remove"); -		if (!present) { -			pr_debug("****** Resetting SD-card bus width ******\n"); -			at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS); -		} -		/* 0.5s needed because of early card detect switch firing */ -		mmc_detect_change(host->mmc, msecs_to_jiffies(500)); -	} -	return IRQ_HANDLED; -} - -static int at91_mci_get_ro(struct mmc_host *mmc) -{ -	struct at91mci_host *host = mmc_priv(mmc); - -	if (gpio_is_valid(host->board->wp_pin)) -		return !!gpio_get_value(host->board->wp_pin); -	/* -	 * Board doesn't support read only detection; let the mmc core -	 * decide what to do. -	 */ -	return -ENOSYS; -} - -static void at91_mci_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ -	struct at91mci_host *host = mmc_priv(mmc); - -	pr_debug("%s: sdio_irq %c : %s\n", mmc_hostname(host->mmc), -		host->board->slot_b ? 'B':'A', enable ? "enable" : "disable"); -	at91_mci_write(host, enable ? AT91_MCI_IER : AT91_MCI_IDR, -		host->board->slot_b ? AT91_MCI_SDIOIRQB : AT91_MCI_SDIOIRQA); - -} - -static const struct mmc_host_ops at91_mci_ops = { -	.request	= at91_mci_request, -	.set_ios	= at91_mci_set_ios, -	.get_ro		= at91_mci_get_ro, -	.enable_sdio_irq = at91_mci_enable_sdio_irq, -}; - -/* - * Probe for the device - */ -static int __init at91_mci_probe(struct platform_device *pdev) -{ -	struct mmc_host *mmc; -	struct at91mci_host *host; -	struct resource *res; -	int ret; - -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) -		return -ENXIO; - -	if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME)) -		return -EBUSY; - -	mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev); -	if (!mmc) { -		ret = -ENOMEM; -		dev_dbg(&pdev->dev, "couldn't allocate mmc host\n"); -		goto fail6; -	} - -	mmc->ops = &at91_mci_ops; -	mmc->f_min = 375000; -	mmc->f_max = 25000000; -	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; -	mmc->caps = 0; - -	mmc->max_blk_size  = MCI_MAXBLKSIZE; -	mmc->max_blk_count = MCI_BLKATONCE; -	mmc->max_req_size  = MCI_BUFSIZE; -	mmc->max_segs      = MCI_BLKATONCE; -	mmc->max_seg_size  = MCI_BUFSIZE; - -	host = mmc_priv(mmc); -	host->mmc = mmc; -	host->bus_mode = 0; -	host->board = pdev->dev.platform_data; -	if (host->board->wire4) { -		if (at91mci_is_mci1rev2xx()) -			mmc->caps |= MMC_CAP_4_BIT_DATA; -		else -			dev_warn(&pdev->dev, "4 wire bus mode not supported" -				" - using 1 wire\n"); -	} - -	host->buffer = dma_alloc_coherent(&pdev->dev, MCI_BUFSIZE, -					&host->physical_address, GFP_KERNEL); -	if (!host->buffer) { -		ret = -ENOMEM; -		dev_err(&pdev->dev, "Can't allocate transmit buffer\n"); -		goto fail5; -	} - -	/* Add SDIO capability when available */ -	if (at91mci_is_mci1rev2xx()) { -		/* at91mci MCI1 rev2xx sdio interrupt erratum */ -		if (host->board->wire4 || !host->board->slot_b) -			mmc->caps |= MMC_CAP_SDIO_IRQ; -	} - -	/* -	 * Reserve GPIOs ... board init code makes sure these pins are set -	 * up as GPIOs with the right direction (input, except for vcc) -	 */ -	if (gpio_is_valid(host->board->det_pin)) { -		ret = gpio_request(host->board->det_pin, "mmc_detect"); -		if (ret < 0) { -			dev_dbg(&pdev->dev, "couldn't claim card detect pin\n"); -			goto fail4b; -		} -	} -	if (gpio_is_valid(host->board->wp_pin)) { -		ret = gpio_request(host->board->wp_pin, "mmc_wp"); -		if (ret < 0) { -			dev_dbg(&pdev->dev, "couldn't claim wp sense pin\n"); -			goto fail4; -		} -	} -	if (gpio_is_valid(host->board->vcc_pin)) { -		ret = gpio_request(host->board->vcc_pin, "mmc_vcc"); -		if (ret < 0) { -			dev_dbg(&pdev->dev, "couldn't claim vcc switch pin\n"); -			goto fail3; -		} -	} - -	/* -	 * Get Clock -	 */ -	host->mci_clk = clk_get(&pdev->dev, "mci_clk"); -	if (IS_ERR(host->mci_clk)) { -		ret = -ENODEV; -		dev_dbg(&pdev->dev, "no mci_clk?\n"); -		goto fail2; -	} - -	/* -	 * Map I/O region -	 */ -	host->baseaddr = ioremap(res->start, resource_size(res)); -	if (!host->baseaddr) { -		ret = -ENOMEM; -		goto fail1; -	} - -	/* -	 * Reset hardware -	 */ -	clk_enable(host->mci_clk);		/* Enable the peripheral clock */ -	at91_mci_disable(host); -	at91_mci_enable(host); - -	/* -	 * Allocate the MCI interrupt -	 */ -	host->irq = platform_get_irq(pdev, 0); -	ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED, -			mmc_hostname(mmc), host); -	if (ret) { -		dev_dbg(&pdev->dev, "request MCI interrupt failed\n"); -		goto fail0; -	} - -	setup_timer(&host->timer, at91_timeout_timer, (unsigned long)host); - -	platform_set_drvdata(pdev, mmc); - -	/* -	 * Add host to MMC layer -	 */ -	if (gpio_is_valid(host->board->det_pin)) { -		host->present = !gpio_get_value(host->board->det_pin); -	} -	else -		host->present = -1; - -	mmc_add_host(mmc); - -	/* -	 * monitor card insertion/removal if we can -	 */ -	if (gpio_is_valid(host->board->det_pin)) { -		ret = request_irq(gpio_to_irq(host->board->det_pin), -				at91_mmc_det_irq, 0, mmc_hostname(mmc), host); -		if (ret) -			dev_warn(&pdev->dev, "request MMC detect irq failed\n"); -		else -			device_init_wakeup(&pdev->dev, 1); -	} - -	pr_debug("Added MCI driver\n"); - -	return 0; - -fail0: -	clk_disable(host->mci_clk); -	iounmap(host->baseaddr); -fail1: -	clk_put(host->mci_clk); -fail2: -	if (gpio_is_valid(host->board->vcc_pin)) -		gpio_free(host->board->vcc_pin); -fail3: -	if (gpio_is_valid(host->board->wp_pin)) -		gpio_free(host->board->wp_pin); -fail4: -	if (gpio_is_valid(host->board->det_pin)) -		gpio_free(host->board->det_pin); -fail4b: -	if (host->buffer) -		dma_free_coherent(&pdev->dev, MCI_BUFSIZE, -				host->buffer, host->physical_address); -fail5: -	mmc_free_host(mmc); -fail6: -	release_mem_region(res->start, resource_size(res)); -	dev_err(&pdev->dev, "probe failed, err %d\n", ret); -	return ret; -} - -/* - * Remove a device - */ -static int __exit at91_mci_remove(struct platform_device *pdev) -{ -	struct mmc_host *mmc = platform_get_drvdata(pdev); -	struct at91mci_host *host; -	struct resource *res; - -	if (!mmc) -		return -1; - -	host = mmc_priv(mmc); - -	if (host->buffer) -		dma_free_coherent(&pdev->dev, MCI_BUFSIZE, -				host->buffer, host->physical_address); - -	if (gpio_is_valid(host->board->det_pin)) { -		if (device_can_wakeup(&pdev->dev)) -			free_irq(gpio_to_irq(host->board->det_pin), host); -		device_init_wakeup(&pdev->dev, 0); -		gpio_free(host->board->det_pin); -	} - -	at91_mci_disable(host); -	del_timer_sync(&host->timer); -	mmc_remove_host(mmc); -	free_irq(host->irq, host); - -	clk_disable(host->mci_clk);			/* Disable the peripheral clock */ -	clk_put(host->mci_clk); - -	if (gpio_is_valid(host->board->vcc_pin)) -		gpio_free(host->board->vcc_pin); -	if (gpio_is_valid(host->board->wp_pin)) -		gpio_free(host->board->wp_pin); - -	iounmap(host->baseaddr); -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	release_mem_region(res->start, resource_size(res)); - -	mmc_free_host(mmc); -	platform_set_drvdata(pdev, NULL); -	pr_debug("MCI Removed\n"); - -	return 0; -} - -#ifdef CONFIG_PM -static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state) -{ -	struct mmc_host *mmc = platform_get_drvdata(pdev); -	struct at91mci_host *host = mmc_priv(mmc); -	int ret = 0; - -	if (gpio_is_valid(host->board->det_pin) && device_may_wakeup(&pdev->dev)) -		enable_irq_wake(host->board->det_pin); - -	if (mmc) -		ret = mmc_suspend_host(mmc); - -	return ret; -} - -static int at91_mci_resume(struct platform_device *pdev) -{ -	struct mmc_host *mmc = platform_get_drvdata(pdev); -	struct at91mci_host *host = mmc_priv(mmc); -	int ret = 0; - -	if (gpio_is_valid(host->board->det_pin) && device_may_wakeup(&pdev->dev)) -		disable_irq_wake(host->board->det_pin); - -	if (mmc) -		ret = mmc_resume_host(mmc); - -	return ret; -} -#else -#define at91_mci_suspend	NULL -#define at91_mci_resume		NULL -#endif - -static struct platform_driver at91_mci_driver = { -	.remove		= __exit_p(at91_mci_remove), -	.suspend	= at91_mci_suspend, -	.resume		= at91_mci_resume, -	.driver		= { -		.name	= DRIVER_NAME, -		.owner	= THIS_MODULE, -	}, -}; - -static int __init at91_mci_init(void) -{ -	return platform_driver_probe(&at91_mci_driver, at91_mci_probe); -} - -static void __exit at91_mci_exit(void) -{ -	platform_driver_unregister(&at91_mci_driver); -} - -module_init(at91_mci_init); -module_exit(at91_mci_exit); - -MODULE_DESCRIPTION("AT91 Multimedia Card Interface driver"); -MODULE_AUTHOR("Nick Randell"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:at91_mci"); diff --git a/drivers/mmc/host/at91_mci.h b/drivers/mmc/host/at91_mci.h deleted file mode 100644 index eec3a6b1c2b..00000000000 --- a/drivers/mmc/host/at91_mci.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * drivers/mmc/host/at91_mci.h - * - * Copyright (C) 2005 Ivan Kokshaysky - * Copyright (C) SAN People - * - * MultiMedia Card Interface (MCI) registers. - * Based on AT91RM9200 datasheet revision F. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef AT91_MCI_H -#define AT91_MCI_H - -#define AT91_MCI_CR		0x00		/* Control Register */ -#define		AT91_MCI_MCIEN		(1 <<  0)	/* Multi-Media Interface Enable */ -#define		AT91_MCI_MCIDIS		(1 <<  1)	/* Multi-Media Interface Disable */ -#define		AT91_MCI_PWSEN		(1 <<  2)	/* Power Save Mode Enable */ -#define		AT91_MCI_PWSDIS		(1 <<  3)	/* Power Save Mode Disable */ -#define		AT91_MCI_SWRST		(1 <<  7)	/* Software Reset */ - -#define AT91_MCI_MR		0x04		/* Mode Register */ -#define		AT91_MCI_CLKDIV		(0xff  <<  0)	/* Clock Divider */ -#define		AT91_MCI_PWSDIV		(7     <<  8)	/* Power Saving Divider */ -#define		AT91_MCI_RDPROOF	(1     << 11)	/* Read Proof Enable [SAM926[03] only] */ -#define		AT91_MCI_WRPROOF	(1     << 12)	/* Write Proof Enable [SAM926[03] only] */ -#define		AT91_MCI_PDCFBYTE	(1     << 13)	/* PDC Force Byte Transfer [SAM926[03] only] */ -#define		AT91_MCI_PDCPADV	(1     << 14)	/* PDC Padding Value */ -#define		AT91_MCI_PDCMODE	(1     << 15)	/* PDC-orientated Mode */ -#define		AT91_MCI_BLKLEN		(0xfff << 18)	/* Data Block Length */ - -#define AT91_MCI_DTOR		0x08		/* Data Timeout Register */ -#define		AT91_MCI_DTOCYC		(0xf << 0)	/* Data Timeout Cycle Number */ -#define		AT91_MCI_DTOMUL		(7   << 4)	/* Data Timeout Multiplier */ -#define		AT91_MCI_DTOMUL_1		(0 <<  4) -#define		AT91_MCI_DTOMUL_16		(1 <<  4) -#define		AT91_MCI_DTOMUL_128		(2 <<  4) -#define		AT91_MCI_DTOMUL_256		(3 <<  4) -#define		AT91_MCI_DTOMUL_1K		(4 <<  4) -#define		AT91_MCI_DTOMUL_4K		(5 <<  4) -#define		AT91_MCI_DTOMUL_64K		(6 <<  4) -#define		AT91_MCI_DTOMUL_1M		(7 <<  4) - -#define AT91_MCI_SDCR		0x0c		/* SD Card Register */ -#define		AT91_MCI_SDCSEL		(3 << 0)	/* SD Card Selector */ -#define		AT91_MCI_SDCBUS		(1 << 7)	/* 1-bit or 4-bit bus */ - -#define AT91_MCI_ARGR		0x10		/* Argument Register */ - -#define AT91_MCI_CMDR		0x14		/* Command Register */ -#define		AT91_MCI_CMDNB		(0x3f << 0)	/* Command Number */ -#define		AT91_MCI_RSPTYP		(3    << 6)	/* Response Type */ -#define			AT91_MCI_RSPTYP_NONE	(0 <<  6) -#define			AT91_MCI_RSPTYP_48	(1 <<  6) -#define			AT91_MCI_RSPTYP_136	(2 <<  6) -#define		AT91_MCI_SPCMD		(7    << 8)	/* Special Command */ -#define			AT91_MCI_SPCMD_NONE	(0 <<  8) -#define			AT91_MCI_SPCMD_INIT	(1 <<  8) -#define			AT91_MCI_SPCMD_SYNC	(2 <<  8) -#define			AT91_MCI_SPCMD_ICMD	(4 <<  8) -#define			AT91_MCI_SPCMD_IRESP	(5 <<  8) -#define		AT91_MCI_OPDCMD		(1 << 11)	/* Open Drain Command */ -#define		AT91_MCI_MAXLAT		(1 << 12)	/* Max Latency for Command to Response */ -#define		AT91_MCI_TRCMD		(3 << 16)	/* Transfer Command */ -#define			AT91_MCI_TRCMD_NONE	(0 << 16) -#define			AT91_MCI_TRCMD_START	(1 << 16) -#define			AT91_MCI_TRCMD_STOP	(2 << 16) -#define		AT91_MCI_TRDIR		(1 << 18)	/* Transfer Direction */ -#define		AT91_MCI_TRTYP		(3 << 19)	/* Transfer Type */ -#define			AT91_MCI_TRTYP_BLOCK	(0 << 19) -#define			AT91_MCI_TRTYP_MULTIPLE	(1 << 19) -#define			AT91_MCI_TRTYP_STREAM	(2 << 19) -#define			AT91_MCI_TRTYP_SDIO_BYTE	(4 << 19) -#define			AT91_MCI_TRTYP_SDIO_BLOCK	(5 << 19) - -#define AT91_MCI_BLKR		0x18		/* Block Register */ -#define		AT91_MCI_BLKR_BCNT(n)	((0xffff & (n)) << 0)	/* Block count */ -#define		AT91_MCI_BLKR_BLKLEN(n)	((0xffff & (n)) << 16)	/* Block length */ - -#define AT91_MCI_RSPR(n)	(0x20 + ((n) * 4))	/* Response Registers 0-3 */ -#define AT91_MCR_RDR		0x30		/* Receive Data Register */ -#define AT91_MCR_TDR		0x34		/* Transmit Data Register */ - -#define AT91_MCI_SR		0x40		/* Status Register */ -#define		AT91_MCI_CMDRDY		(1 <<  0)	/* Command Ready */ -#define		AT91_MCI_RXRDY		(1 <<  1)	/* Receiver Ready */ -#define		AT91_MCI_TXRDY		(1 <<  2)	/* Transmit Ready */ -#define		AT91_MCI_BLKE		(1 <<  3)	/* Data Block Ended */ -#define		AT91_MCI_DTIP		(1 <<  4)	/* Data Transfer in Progress */ -#define		AT91_MCI_NOTBUSY	(1 <<  5)	/* Data Not Busy */ -#define		AT91_MCI_ENDRX		(1 <<  6)	/* End of RX Buffer */ -#define		AT91_MCI_ENDTX		(1 <<  7)	/* End fo TX Buffer */ -#define		AT91_MCI_SDIOIRQA	(1 <<  8)	/* SDIO Interrupt for Slot A */ -#define		AT91_MCI_SDIOIRQB	(1 <<  9)	/* SDIO Interrupt for Slot B */ -#define		AT91_MCI_RXBUFF		(1 << 14)	/* RX Buffer Full */ -#define		AT91_MCI_TXBUFE		(1 << 15)	/* TX Buffer Empty */ -#define		AT91_MCI_RINDE		(1 << 16)	/* Response Index Error */ -#define		AT91_MCI_RDIRE		(1 << 17)	/* Response Direction Error */ -#define		AT91_MCI_RCRCE		(1 << 18)	/* Response CRC Error */ -#define		AT91_MCI_RENDE		(1 << 19)	/* Response End Bit Error */ -#define		AT91_MCI_RTOE		(1 << 20)	/* Response Time-out Error */ -#define		AT91_MCI_DCRCE		(1 << 21)	/* Data CRC Error */ -#define		AT91_MCI_DTOE		(1 << 22)	/* Data Time-out Error */ -#define		AT91_MCI_OVRE		(1 << 30)	/* Overrun */ -#define		AT91_MCI_UNRE		(1 << 31)	/* Underrun */ - -#define AT91_MCI_IER		0x44		/* Interrupt Enable Register */ -#define AT91_MCI_IDR		0x48		/* Interrupt Disable Register */ -#define AT91_MCI_IMR		0x4c		/* Interrupt Mask Register */ - -#endif diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 660bbc52886..4d50da61816 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -208,7 +208,7 @@ static unsigned long exynos5250_dwmmc_caps[4] = {  	MMC_CAP_CMD23,  }; -static struct dw_mci_drv_data exynos5250_drv_data = { +static const struct dw_mci_drv_data exynos5250_drv_data = {  	.caps			= exynos5250_dwmmc_caps,  	.init			= dw_mci_exynos_priv_init,  	.setup_clock		= dw_mci_exynos_setup_clock, @@ -220,14 +220,14 @@ static struct dw_mci_drv_data exynos5250_drv_data = {  static const struct of_device_id dw_mci_exynos_match[] = {  	{ .compatible = "samsung,exynos5250-dw-mshc", -			.data = (void *)&exynos5250_drv_data, }, +			.data = &exynos5250_drv_data, },  	{},  }; -MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match); +MODULE_DEVICE_TABLE(of, dw_mci_exynos_match);  int dw_mci_exynos_probe(struct platform_device *pdev)  { -	struct dw_mci_drv_data *drv_data; +	const struct dw_mci_drv_data *drv_data;  	const struct of_device_id *match;  	match = of_match_node(dw_mci_exynos_match, pdev->dev.of_node); diff --git a/drivers/mmc/host/dw_mmc-pci.c b/drivers/mmc/host/dw_mmc-pci.c index edb37e9135a..53a09cbb2c7 100644 --- a/drivers/mmc/host/dw_mmc-pci.c +++ b/drivers/mmc/host/dw_mmc-pci.c @@ -134,7 +134,7 @@ static struct pci_driver dw_mci_pci_driver = {  	.name		= "dw_mmc_pci",  	.id_table	= dw_mci_pci_id,  	.probe		= dw_mci_pci_probe, -	.remove		= dw_mci_pci_remove, +	.remove		= __devexit_p(dw_mci_pci_remove),  	.driver		=	{  		.pm =   &dw_mci_pci_pmops  	}, diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c index c960ca7ffbe..4e133709e33 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c @@ -24,7 +24,7 @@  #include "dw_mmc.h"  int dw_mci_pltfm_register(struct platform_device *pdev, -				struct dw_mci_drv_data *drv_data) +				const struct dw_mci_drv_data *drv_data)  {  	struct dw_mci *host;  	struct resource	*regs; @@ -50,8 +50,8 @@ int dw_mci_pltfm_register(struct platform_device *pdev,  	if (!host->regs)  		return -ENOMEM; -	if (host->drv_data->init) { -		ret = host->drv_data->init(host); +	if (drv_data && drv_data->init) { +		ret = drv_data->init(host);  		if (ret)  			return ret;  	} @@ -119,7 +119,8 @@ static const struct of_device_id dw_mci_pltfm_match[] = {  MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);  static struct platform_driver dw_mci_pltfm_driver = { -	.remove		= __exit_p(dw_mci_pltfm_remove), +	.probe		= dw_mci_pltfm_probe, +	.remove		= __devexit_p(dw_mci_pltfm_remove),  	.driver		= {  		.name		= "dw_mmc",  		.of_match_table	= of_match_ptr(dw_mci_pltfm_match), @@ -127,18 +128,7 @@ static struct platform_driver dw_mci_pltfm_driver = {  	},  }; -static int __init dw_mci_init(void) -{ -	return platform_driver_probe(&dw_mci_pltfm_driver, dw_mci_pltfm_probe); -} - -static void __exit dw_mci_exit(void) -{ -	platform_driver_unregister(&dw_mci_pltfm_driver); -} - -module_init(dw_mci_init); -module_exit(dw_mci_exit); +module_platform_driver(dw_mci_pltfm_driver);  MODULE_DESCRIPTION("DW Multimedia Card Interface driver");  MODULE_AUTHOR("NXP Semiconductor VietNam"); diff --git a/drivers/mmc/host/dw_mmc-pltfm.h b/drivers/mmc/host/dw_mmc-pltfm.h index 301f24541fc..2ac37b81de4 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.h +++ b/drivers/mmc/host/dw_mmc-pltfm.h @@ -13,7 +13,7 @@  #define _DW_MMC_PLTFM_H_  extern int dw_mci_pltfm_register(struct platform_device *pdev, -				struct dw_mci_drv_data *drv_data); +				const struct dw_mci_drv_data *drv_data);  extern int __devexit dw_mci_pltfm_remove(struct platform_device *pdev);  extern const struct dev_pm_ops dw_mci_pltfm_pmops; diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index c2828f35c3b..323c5022c2c 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -232,6 +232,7 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)  {  	struct mmc_data	*data;  	struct dw_mci_slot *slot = mmc_priv(mmc); +	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;  	u32 cmdr;  	cmd->error = -EINPROGRESS; @@ -261,8 +262,8 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)  			cmdr |= SDMMC_CMD_DAT_WR;  	} -	if (slot->host->drv_data->prepare_command) -		slot->host->drv_data->prepare_command(slot->host, &cmdr); +	if (drv_data && drv_data->prepare_command) +		drv_data->prepare_command(slot->host, &cmdr);  	return cmdr;  } @@ -434,7 +435,7 @@ static int dw_mci_idmac_init(struct dw_mci *host)  	return 0;  } -static struct dw_mci_dma_ops dw_mci_idmac_ops = { +static const struct dw_mci_dma_ops dw_mci_idmac_ops = {  	.init = dw_mci_idmac_init,  	.start = dw_mci_idmac_start_dma,  	.stop = dw_mci_idmac_stop_dma, @@ -616,13 +617,13 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)  		cmd, arg, cmd_status);  } -static void dw_mci_setup_bus(struct dw_mci_slot *slot) +static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)  {  	struct dw_mci *host = slot->host;  	u32 div;  	u32 clk_en_a; -	if (slot->clock != host->current_speed) { +	if (slot->clock != host->current_speed || force_clkinit) {  		div = host->bus_hz / slot->clock;  		if (host->bus_hz % slot->clock && host->bus_hz > slot->clock)  			/* @@ -682,9 +683,6 @@ static void __dw_mci_start_request(struct dw_mci *host,  	if (host->pdata->select_slot)  		host->pdata->select_slot(slot->id); -	/* Slot specific timing and width adjustment */ -	dw_mci_setup_bus(slot); -  	host->cur_slot = slot;  	host->mrq = mrq; @@ -772,21 +770,19 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)  static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  {  	struct dw_mci_slot *slot = mmc_priv(mmc); +	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;  	u32 regs; -	/* set default 1 bit mode */ -	slot->ctype = SDMMC_CTYPE_1BIT; -  	switch (ios->bus_width) { -	case MMC_BUS_WIDTH_1: -		slot->ctype = SDMMC_CTYPE_1BIT; -		break;  	case MMC_BUS_WIDTH_4:  		slot->ctype = SDMMC_CTYPE_4BIT;  		break;  	case MMC_BUS_WIDTH_8:  		slot->ctype = SDMMC_CTYPE_8BIT;  		break; +	default: +		/* set default 1 bit mode */ +		slot->ctype = SDMMC_CTYPE_1BIT;  	}  	regs = mci_readl(slot->host, UHS_REG); @@ -807,8 +803,11 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  		slot->clock = ios->clock;  	} -	if (slot->host->drv_data->set_ios) -		slot->host->drv_data->set_ios(slot->host, ios); +	if (drv_data && drv_data->set_ios) +		drv_data->set_ios(slot->host, ios); + +	/* Slot specific timing and width adjustment */ +	dw_mci_setup_bus(slot, false);  	switch (ios->power_mode) {  	case MMC_POWER_UP: @@ -1815,6 +1814,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)  {  	struct mmc_host *mmc;  	struct dw_mci_slot *slot; +	const struct dw_mci_drv_data *drv_data = host->drv_data;  	int ctrl_id, ret;  	u8 bus_width; @@ -1847,6 +1847,9 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)  	if (host->pdata->caps)  		mmc->caps = host->pdata->caps; +	if (host->pdata->pm_caps) +		mmc->pm_caps = host->pdata->pm_caps; +  	if (host->dev->of_node) {  		ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");  		if (ctrl_id < 0) @@ -1854,8 +1857,8 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)  	} else {  		ctrl_id = to_platform_device(host->dev)->id;  	} -	if (host->drv_data && host->drv_data->caps) -		mmc->caps |= host->drv_data->caps[ctrl_id]; +	if (drv_data && drv_data->caps) +		mmc->caps |= drv_data->caps[ctrl_id];  	if (host->pdata->caps2)  		mmc->caps2 = host->pdata->caps2; @@ -1867,10 +1870,10 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)  	else  		bus_width = 1; -	if (host->drv_data->setup_bus) { +	if (drv_data && drv_data->setup_bus) {  		struct device_node *slot_np;  		slot_np = dw_mci_of_find_slot_node(host->dev, slot->id); -		ret = host->drv_data->setup_bus(host, slot_np, bus_width); +		ret = drv_data->setup_bus(host, slot_np, bus_width);  		if (ret)  			goto err_setup_bus;  	} @@ -1908,7 +1911,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)  #endif /* CONFIG_MMC_DW_IDMAC */  	} -	host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); +	host->vmmc = devm_regulator_get(mmc_dev(mmc), "vmmc");  	if (IS_ERR(host->vmmc)) {  		pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));  		host->vmmc = NULL; @@ -1957,7 +1960,7 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)  static void dw_mci_init_dma(struct dw_mci *host)  {  	/* Alloc memory for sg translation */ -	host->sg_cpu = dma_alloc_coherent(host->dev, PAGE_SIZE, +	host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,  					  &host->sg_dma, GFP_KERNEL);  	if (!host->sg_cpu) {  		dev_err(host->dev, "%s: could not alloc DMA memory\n", @@ -1968,7 +1971,7 @@ static void dw_mci_init_dma(struct dw_mci *host)  	/* Determine which DMA interface to use */  #ifdef CONFIG_MMC_DW_IDMAC  	host->dma_ops = &dw_mci_idmac_ops; -	dev_info(&host->dev, "Using internal DMA controller.\n"); +	dev_info(host->dev, "Using internal DMA controller.\n");  #endif  	if (!host->dma_ops) @@ -2035,6 +2038,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)  	struct dw_mci_board *pdata;  	struct device *dev = host->dev;  	struct device_node *np = dev->of_node; +	const struct dw_mci_drv_data *drv_data = host->drv_data;  	int idx, ret;  	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); @@ -2062,12 +2066,18 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)  	of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms); -	if (host->drv_data->parse_dt) { -		ret = host->drv_data->parse_dt(host); +	if (drv_data && drv_data->parse_dt) { +		ret = drv_data->parse_dt(host);  		if (ret)  			return ERR_PTR(ret);  	} +	if (of_find_property(np, "keep-power-in-suspend", NULL)) +		pdata->pm_caps |= MMC_PM_KEEP_POWER; + +	if (of_find_property(np, "enable-sdio-wakeup", NULL)) +		pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; +  	return pdata;  } @@ -2080,6 +2090,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)  int dw_mci_probe(struct dw_mci *host)  { +	const struct dw_mci_drv_data *drv_data = host->drv_data;  	int width, i, ret = 0;  	u32 fifo_size;  	int init_slots = 0; @@ -2098,26 +2109,24 @@ int dw_mci_probe(struct dw_mci *host)  		return -ENODEV;  	} -	host->biu_clk = clk_get(host->dev, "biu"); +	host->biu_clk = devm_clk_get(host->dev, "biu");  	if (IS_ERR(host->biu_clk)) {  		dev_dbg(host->dev, "biu clock not available\n");  	} else {  		ret = clk_prepare_enable(host->biu_clk);  		if (ret) {  			dev_err(host->dev, "failed to enable biu clock\n"); -			clk_put(host->biu_clk);  			return ret;  		}  	} -	host->ciu_clk = clk_get(host->dev, "ciu"); +	host->ciu_clk = devm_clk_get(host->dev, "ciu");  	if (IS_ERR(host->ciu_clk)) {  		dev_dbg(host->dev, "ciu clock not available\n");  	} else {  		ret = clk_prepare_enable(host->ciu_clk);  		if (ret) {  			dev_err(host->dev, "failed to enable ciu clock\n"); -			clk_put(host->ciu_clk);  			goto err_clk_biu;  		}  	} @@ -2127,8 +2136,8 @@ int dw_mci_probe(struct dw_mci *host)  	else  		host->bus_hz = clk_get_rate(host->ciu_clk); -	if (host->drv_data->setup_clock) { -		ret = host->drv_data->setup_clock(host); +	if (drv_data && drv_data->setup_clock) { +		ret = drv_data->setup_clock(host);  		if (ret) {  			dev_err(host->dev,  				"implementation specific clock setup failed\n"); @@ -2219,7 +2228,8 @@ int dw_mci_probe(struct dw_mci *host)  	if (!host->card_workqueue)  		goto err_dmaunmap;  	INIT_WORK(&host->card_work, dw_mci_work_routine_card); -	ret = request_irq(host->irq, dw_mci_interrupt, host->irq_flags, "dw-mci", host); +	ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt, +			       host->irq_flags, "dw-mci", host);  	if (ret)  		goto err_workqueue; @@ -2228,6 +2238,21 @@ int dw_mci_probe(struct dw_mci *host)  	else  		host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1; +	/* +	 * Enable interrupts for command done, data over, data empty, card det, +	 * receive ready and error such as transmit, receive timeout, crc error +	 */ +	mci_writel(host, RINTSTS, 0xFFFFFFFF); +	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | +		   SDMMC_INT_TXDR | SDMMC_INT_RXDR | +		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); +	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */ + +	dev_info(host->dev, "DW MMC controller at irq %d, " +		 "%d bit host data width, " +		 "%u deep fifo\n", +		 host->irq, width, fifo_size); +  	/* We need at least one slot to succeed */  	for (i = 0; i < host->num_slots; i++) {  		ret = dw_mci_init_slot(host, i); @@ -2242,7 +2267,7 @@ int dw_mci_probe(struct dw_mci *host)  	} else {  		dev_dbg(host->dev, "attempted to initialize %d slots, "  					"but failed on all\n", host->num_slots); -		goto err_init_slot; +		goto err_workqueue;  	}  	/* @@ -2257,52 +2282,29 @@ int dw_mci_probe(struct dw_mci *host)  	else  		host->data_offset = DATA_240A_OFFSET; -	/* -	 * Enable interrupts for command done, data over, data empty, card det, -	 * receive ready and error such as transmit, receive timeout, crc error -	 */ -	mci_writel(host, RINTSTS, 0xFFFFFFFF); -	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER | -		   SDMMC_INT_TXDR | SDMMC_INT_RXDR | -		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); -	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */ - -	dev_info(host->dev, "DW MMC controller at irq %d, " -		 "%d bit host data width, " -		 "%u deep fifo\n", -		 host->irq, width, fifo_size);  	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)  		dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");  	return 0; -err_init_slot: -	free_irq(host->irq, host); -  err_workqueue:  	destroy_workqueue(host->card_workqueue);  err_dmaunmap:  	if (host->use_dma && host->dma_ops->exit)  		host->dma_ops->exit(host); -	dma_free_coherent(host->dev, PAGE_SIZE, -			  host->sg_cpu, host->sg_dma); -	if (host->vmmc) { +	if (host->vmmc)  		regulator_disable(host->vmmc); -		regulator_put(host->vmmc); -	}  err_clk_ciu: -	if (!IS_ERR(host->ciu_clk)) { +	if (!IS_ERR(host->ciu_clk))  		clk_disable_unprepare(host->ciu_clk); -		clk_put(host->ciu_clk); -	} +  err_clk_biu: -	if (!IS_ERR(host->biu_clk)) { +	if (!IS_ERR(host->biu_clk))  		clk_disable_unprepare(host->biu_clk); -		clk_put(host->biu_clk); -	} +  	return ret;  }  EXPORT_SYMBOL(dw_mci_probe); @@ -2324,24 +2326,19 @@ void dw_mci_remove(struct dw_mci *host)  	mci_writel(host, CLKENA, 0);  	mci_writel(host, CLKSRC, 0); -	free_irq(host->irq, host);  	destroy_workqueue(host->card_workqueue); -	dma_free_coherent(host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);  	if (host->use_dma && host->dma_ops->exit)  		host->dma_ops->exit(host); -	if (host->vmmc) { +	if (host->vmmc)  		regulator_disable(host->vmmc); -		regulator_put(host->vmmc); -	}  	if (!IS_ERR(host->ciu_clk))  		clk_disable_unprepare(host->ciu_clk); +  	if (!IS_ERR(host->biu_clk))  		clk_disable_unprepare(host->biu_clk); -	clk_put(host->ciu_clk); -	clk_put(host->biu_clk);  }  EXPORT_SYMBOL(dw_mci_remove); @@ -2405,6 +2402,11 @@ int dw_mci_resume(struct dw_mci *host)  		struct dw_mci_slot *slot = host->slot[i];  		if (!slot)  			continue; +		if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) { +			dw_mci_set_ios(slot->mmc, &slot->mmc->ios); +			dw_mci_setup_bus(slot, true); +		} +  		ret = mmc_resume_host(host->slot[i]->mmc);  		if (ret < 0)  			return ret; diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 565c2e4fac7..29e680f193a 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -240,7 +240,7 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)  		return 0;  	for_each_sg(data->sg, sg, data->sg_len, i) { -		if (sg->offset & 3 || sg->length & 3) { +		if (sg->offset & 3 || sg->length & 3 || sg->length < 512) {  			host->do_dma = 0;  			return 0;  		} @@ -1134,4 +1134,4 @@ module_platform_driver(mxcmci_driver);  MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver");  MODULE_AUTHOR("Sascha Hauer, Pengutronix");  MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:imx-mmc"); +MODULE_ALIAS("platform:mxc-mmc"); diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index 80d1e6d4b0a..206fe499ded 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -43,7 +43,6 @@  #include <linux/module.h>  #include <linux/pinctrl/consumer.h>  #include <linux/stmp_device.h> -#include <linux/mmc/mxs-mmc.h>  #include <linux/spi/mxs-spi.h>  #define DRIVER_NAME	"mxs-mmc" @@ -593,13 +592,13 @@ static int mxs_mmc_probe(struct platform_device *pdev)  	struct mxs_mmc_host *host;  	struct mmc_host *mmc;  	struct resource *iores, *dmares; -	struct mxs_mmc_platform_data *pdata;  	struct pinctrl *pinctrl;  	int ret = 0, irq_err, irq_dma;  	dma_cap_mask_t mask;  	struct regulator *reg_vmmc;  	enum of_gpio_flags flags;  	struct mxs_ssp *ssp; +	u32 bus_width = 0;  	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); @@ -682,25 +681,15 @@ static int mxs_mmc_probe(struct platform_device *pdev)  	mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |  		    MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL; -	pdata =	mmc_dev(host->mmc)->platform_data; -	if (!pdata) { -		u32 bus_width = 0; -		of_property_read_u32(np, "bus-width", &bus_width); -		if (bus_width == 4) -			mmc->caps |= MMC_CAP_4_BIT_DATA; -		else if (bus_width == 8) -			mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; -		host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, -							&flags); -		if (flags & OF_GPIO_ACTIVE_LOW) -			host->wp_inverted = 1; -	} else { -		if (pdata->flags & SLOTF_8_BIT_CAPABLE) -			mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; -		if (pdata->flags & SLOTF_4_BIT_CAPABLE) -			mmc->caps |= MMC_CAP_4_BIT_DATA; -		host->wp_gpio = pdata->wp_gpio; -	} +	of_property_read_u32(np, "bus-width", &bus_width); +	if (bus_width == 4) +		mmc->caps |= MMC_CAP_4_BIT_DATA; +	else if (bus_width == 8) +		mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; +	host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags); + +	if (flags & OF_GPIO_ACTIVE_LOW) +		host->wp_inverted = 1;  	mmc->f_min = 400000;  	mmc->f_max = 288000000; diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 54bfd0cc106..d0a912fbad3 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -37,6 +37,7 @@  #include <linux/io.h>  #include <linux/gpio.h>  #include <linux/regulator/consumer.h> +#include <linux/pinctrl/consumer.h>  #include <linux/pm_runtime.h>  #include <mach/hardware.h>  #include <plat/mmc.h> @@ -62,6 +63,7 @@  #define VS18			(1 << 26)  #define VS30			(1 << 25) +#define HSS			(1 << 21)  #define SDVS18			(0x5 << 9)  #define SDVS30			(0x6 << 9)  #define SDVS33			(0x7 << 9) @@ -78,28 +80,17 @@  #define CLKD_SHIFT		6  #define DTO_MASK		0x000F0000  #define DTO_SHIFT		16 -#define INT_EN_MASK		0x307F0033 -#define BWR_ENABLE		(1 << 4) -#define BRR_ENABLE		(1 << 5) -#define DTO_ENABLE		(1 << 20)  #define INIT_STREAM		(1 << 1)  #define DP_SELECT		(1 << 21)  #define DDIR			(1 << 4) -#define DMA_EN			0x1 +#define DMAE			0x1  #define MSBS			(1 << 5)  #define BCE			(1 << 1)  #define FOUR_BIT		(1 << 1) +#define HSPE			(1 << 2)  #define DDR			(1 << 19)  #define DW8			(1 << 5) -#define CC			0x1 -#define TC			0x02  #define OD			0x1 -#define ERR			(1 << 15) -#define CMD_TIMEOUT		(1 << 16) -#define DATA_TIMEOUT		(1 << 20) -#define CMD_CRC			(1 << 17) -#define DATA_CRC		(1 << 21) -#define CARD_ERR		(1 << 28)  #define STAT_CLEAR		0xFFFFFFFF  #define INIT_STREAM_CMD		0x00000000  #define DUAL_VOLT_OCR_BIT	7 @@ -108,6 +99,26 @@  #define SOFTRESET		(1 << 1)  #define RESETDONE		(1 << 0) +/* Interrupt masks for IE and ISE register */ +#define CC_EN			(1 << 0) +#define TC_EN			(1 << 1) +#define BWR_EN			(1 << 4) +#define BRR_EN			(1 << 5) +#define ERR_EN			(1 << 15) +#define CTO_EN			(1 << 16) +#define CCRC_EN			(1 << 17) +#define CEB_EN			(1 << 18) +#define CIE_EN			(1 << 19) +#define DTO_EN			(1 << 20) +#define DCRC_EN			(1 << 21) +#define DEB_EN			(1 << 22) +#define CERR_EN			(1 << 28) +#define BADA_EN			(1 << 29) + +#define INT_EN_MASK		(BADA_EN | CERR_EN | DEB_EN | DCRC_EN |\ +		DTO_EN | CIE_EN | CEB_EN | CCRC_EN | CTO_EN | \ +		BRR_EN | BWR_EN | TC_EN | CC_EN) +  #define MMC_AUTOSUSPEND_DELAY	100  #define MMC_TIMEOUT_MS		20  #define OMAP_MMC_MIN_CLOCK	400000 @@ -178,7 +189,8 @@ struct omap_hsmmc_host {  static int omap_hsmmc_card_detect(struct device *dev, int slot)  { -	struct omap_mmc_platform_data *mmc = dev->platform_data; +	struct omap_hsmmc_host *host = dev_get_drvdata(dev); +	struct omap_mmc_platform_data *mmc = host->pdata;  	/* NOTE: assumes card detect signal is active-low */  	return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); @@ -186,7 +198,8 @@ static int omap_hsmmc_card_detect(struct device *dev, int slot)  static int omap_hsmmc_get_wp(struct device *dev, int slot)  { -	struct omap_mmc_platform_data *mmc = dev->platform_data; +	struct omap_hsmmc_host *host = dev_get_drvdata(dev); +	struct omap_mmc_platform_data *mmc = host->pdata;  	/* NOTE: assumes write protect signal is active-high */  	return gpio_get_value_cansleep(mmc->slots[0].gpio_wp); @@ -194,7 +207,8 @@ static int omap_hsmmc_get_wp(struct device *dev, int slot)  static int omap_hsmmc_get_cover_state(struct device *dev, int slot)  { -	struct omap_mmc_platform_data *mmc = dev->platform_data; +	struct omap_hsmmc_host *host = dev_get_drvdata(dev); +	struct omap_mmc_platform_data *mmc = host->pdata;  	/* NOTE: assumes card detect signal is active-low */  	return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); @@ -204,7 +218,8 @@ static int omap_hsmmc_get_cover_state(struct device *dev, int slot)  static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot)  { -	struct omap_mmc_platform_data *mmc = dev->platform_data; +	struct omap_hsmmc_host *host = dev_get_drvdata(dev); +	struct omap_mmc_platform_data *mmc = host->pdata;  	disable_irq(mmc->slots[0].card_detect_irq);  	return 0; @@ -212,7 +227,8 @@ static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot)  static int omap_hsmmc_resume_cdirq(struct device *dev, int slot)  { -	struct omap_mmc_platform_data *mmc = dev->platform_data; +	struct omap_hsmmc_host *host = dev_get_drvdata(dev); +	struct omap_mmc_platform_data *mmc = host->pdata;  	enable_irq(mmc->slots[0].card_detect_irq);  	return 0; @@ -297,7 +313,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)  	reg = regulator_get(host->dev, "vmmc");  	if (IS_ERR(reg)) { -		dev_dbg(host->dev, "vmmc regulator missing\n"); +		dev_err(host->dev, "vmmc regulator missing\n");  		return PTR_ERR(reg);  	} else {  		mmc_slot(host).set_power = omap_hsmmc_set_power; @@ -450,13 +466,13 @@ static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,  	unsigned int irq_mask;  	if (host->use_dma) -		irq_mask = INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE); +		irq_mask = INT_EN_MASK & ~(BRR_EN | BWR_EN);  	else  		irq_mask = INT_EN_MASK;  	/* Disable timeout for erases */  	if (cmd->opcode == MMC_ERASE) -		irq_mask &= ~DTO_ENABLE; +		irq_mask &= ~DTO_EN;  	OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);  	OMAP_HSMMC_WRITE(host->base, ISE, irq_mask); @@ -489,6 +505,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)  	struct mmc_ios *ios = &host->mmc->ios;  	unsigned long regval;  	unsigned long timeout; +	unsigned long clkdiv;  	dev_vdbg(mmc_dev(host->mmc), "Set clock to %uHz\n", ios->clock); @@ -496,7 +513,8 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)  	regval = OMAP_HSMMC_READ(host->base, SYSCTL);  	regval = regval & ~(CLKD_MASK | DTO_MASK); -	regval = regval | (calc_divisor(host, ios) << 6) | (DTO << 16); +	clkdiv = calc_divisor(host, ios); +	regval = regval | (clkdiv << 6) | (DTO << 16);  	OMAP_HSMMC_WRITE(host->base, SYSCTL, regval);  	OMAP_HSMMC_WRITE(host->base, SYSCTL,  		OMAP_HSMMC_READ(host->base, SYSCTL) | ICE); @@ -507,6 +525,27 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)  		&& time_before(jiffies, timeout))  		cpu_relax(); +	/* +	 * Enable High-Speed Support +	 * Pre-Requisites +	 *	- Controller should support High-Speed-Enable Bit +	 *	- Controller should not be using DDR Mode +	 *	- Controller should advertise that it supports High Speed +	 *	  in capabilities register +	 *	- MMC/SD clock coming out of controller > 25MHz +	 */ +	if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) && +	    (ios->timing != MMC_TIMING_UHS_DDR50) && +	    ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) { +		regval = OMAP_HSMMC_READ(host->base, HCTL); +		if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000) +			regval |= HSPE; +		else +			regval &= ~HSPE; + +		OMAP_HSMMC_WRITE(host->base, HCTL, regval); +	} +  	omap_hsmmc_start_clock(host);  } @@ -671,8 +710,8 @@ static void send_init_stream(struct omap_hsmmc_host *host)  	OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);  	timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS); -	while ((reg != CC) && time_before(jiffies, timeout)) -		reg = OMAP_HSMMC_READ(host->base, STAT) & CC; +	while ((reg != CC_EN) && time_before(jiffies, timeout)) +		reg = OMAP_HSMMC_READ(host->base, STAT) & CC_EN;  	OMAP_HSMMC_WRITE(host->base, CON,  		OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM); @@ -763,7 +802,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,  	}  	if (host->use_dma) -		cmdreg |= DMA_EN; +		cmdreg |= DMAE;  	host->req_in_progress = 1; @@ -963,16 +1002,20 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,  			__func__);  } -static void hsmmc_command_incomplete(struct omap_hsmmc_host *host, int err) +static void hsmmc_command_incomplete(struct omap_hsmmc_host *host, +					int err, int end_cmd)  { -	omap_hsmmc_reset_controller_fsm(host, SRC); -	host->cmd->error = err; +	if (end_cmd) { +		omap_hsmmc_reset_controller_fsm(host, SRC); +		if (host->cmd) +			host->cmd->error = err; +	}  	if (host->data) {  		omap_hsmmc_reset_controller_fsm(host, SRD);  		omap_hsmmc_dma_cleanup(host, err); -	} - +	} else if (host->mrq && host->mrq->cmd) +		host->mrq->cmd->error = err;  }  static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) @@ -983,23 +1026,25 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)  	data = host->data;  	dev_vdbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status); -	if (status & ERR) { +	if (status & ERR_EN) {  		omap_hsmmc_dbg_report_irq(host, status); -		if (status & (CMD_TIMEOUT | DATA_TIMEOUT)) -			hsmmc_command_incomplete(host, -ETIMEDOUT); -		else if (status & (CMD_CRC | DATA_CRC)) -			hsmmc_command_incomplete(host, -EILSEQ); -		end_cmd = 1; +		if (status & (CTO_EN | CCRC_EN)) +			end_cmd = 1; +		if (status & (CTO_EN | DTO_EN)) +			hsmmc_command_incomplete(host, -ETIMEDOUT, end_cmd); +		else if (status & (CCRC_EN | DCRC_EN)) +			hsmmc_command_incomplete(host, -EILSEQ, end_cmd); +  		if (host->data || host->response_busy) { -			end_trans = 1; +			end_trans = !end_cmd;  			host->response_busy = 0;  		}  	} -	if (end_cmd || ((status & CC) && host->cmd)) +	if (end_cmd || ((status & CC_EN) && host->cmd))  		omap_hsmmc_cmd_done(host, host->cmd); -	if ((end_trans || (status & TC)) && host->mrq) +	if ((end_trans || (status & TC_EN)) && host->mrq)  		omap_hsmmc_xfer_done(host, data);  } @@ -1096,7 +1141,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)  	return 0;  err: -	dev_dbg(mmc_dev(host->mmc), "Unable to switch operating voltage\n"); +	dev_err(mmc_dev(host->mmc), "Unable to switch operating voltage\n");  	return ret;  } @@ -1355,7 +1400,7 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)  	if (host->use_dma) {  		ret = omap_hsmmc_start_dma_transfer(host, req);  		if (ret != 0) { -			dev_dbg(mmc_dev(host->mmc), "MMC start dma failure\n"); +			dev_err(mmc_dev(host->mmc), "MMC start dma failure\n");  			return ret;  		}  	} @@ -1673,7 +1718,7 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)  {  	struct omap_mmc_platform_data *pdata;  	struct device_node *np = dev->of_node; -	u32 bus_width; +	u32 bus_width, max_freq;  	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);  	if (!pdata) @@ -1700,6 +1745,12 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)  	if (of_find_property(np, "ti,needs-special-reset", NULL))  		pdata->slots[0].features |= HSMMC_HAS_UPDATED_RESET; +	if (!of_property_read_u32(np, "max-frequency", &max_freq)) +		pdata->max_freq = max_freq; + +	if (of_find_property(np, "ti,needs-special-hs-handling", NULL)) +		pdata->slots[0].features |= HSMMC_HAS_HSPE_SUPPORT; +  	return pdata;  }  #else @@ -1720,6 +1771,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)  	const struct of_device_id *match;  	dma_cap_mask_t mask;  	unsigned tx_req, rx_req; +	struct pinctrl *pinctrl;  	match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);  	if (match) { @@ -1816,7 +1868,6 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)  	 * MMC can still work without debounce clock.  	 */  	if (IS_ERR(host->dbclk)) { -		dev_warn(mmc_dev(host->mmc), "Failed to get debounce clk\n");  		host->dbclk = NULL;  	} else if (clk_prepare_enable(host->dbclk) != 0) {  		dev_warn(mmc_dev(host->mmc), "Failed to enable debounce clk\n"); @@ -1884,13 +1935,13 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)  	ret = request_irq(host->irq, omap_hsmmc_irq, 0,  			mmc_hostname(mmc), host);  	if (ret) { -		dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n"); +		dev_err(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");  		goto err_irq;  	}  	if (pdata->init != NULL) {  		if (pdata->init(&pdev->dev) != 0) { -			dev_dbg(mmc_dev(host->mmc), +			dev_err(mmc_dev(host->mmc),  				"Unable to configure MMC IRQs\n");  			goto err_irq_cd_init;  		} @@ -1913,7 +1964,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)  					   IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,  					   mmc_hostname(mmc), host);  		if (ret) { -			dev_dbg(mmc_dev(host->mmc), +			dev_err(mmc_dev(host->mmc),  				"Unable to grab MMC CD IRQ\n");  			goto err_irq_cd;  		} @@ -1923,6 +1974,11 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)  	omap_hsmmc_disable_irq(host); +	pinctrl = devm_pinctrl_get_select_default(&pdev->dev); +	if (IS_ERR(pinctrl)) +		dev_warn(&pdev->dev, +			"pins are not configured from the driver\n"); +  	omap_hsmmc_protect_card(host);  	mmc_add_host(mmc); @@ -2009,9 +2065,9 @@ static int __devexit omap_hsmmc_remove(struct platform_device *pdev)  		clk_put(host->dbclk);  	} -	mmc_free_host(host->mmc); +	omap_hsmmc_gpio_free(host->pdata);  	iounmap(host->base); -	omap_hsmmc_gpio_free(pdev->dev.platform_data); +	mmc_free_host(host->mmc);  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (res) @@ -2022,6 +2078,25 @@ static int __devexit omap_hsmmc_remove(struct platform_device *pdev)  }  #ifdef CONFIG_PM +static int omap_hsmmc_prepare(struct device *dev) +{ +	struct omap_hsmmc_host *host = dev_get_drvdata(dev); + +	if (host->pdata->suspend) +		return host->pdata->suspend(dev, host->slot_id); + +	return 0; +} + +static void omap_hsmmc_complete(struct device *dev) +{ +	struct omap_hsmmc_host *host = dev_get_drvdata(dev); + +	if (host->pdata->resume) +		host->pdata->resume(dev, host->slot_id); + +} +  static int omap_hsmmc_suspend(struct device *dev)  {  	int ret = 0; @@ -2035,23 +2110,10 @@ static int omap_hsmmc_suspend(struct device *dev)  	pm_runtime_get_sync(host->dev);  	host->suspended = 1; -	if (host->pdata->suspend) { -		ret = host->pdata->suspend(dev, host->slot_id); -		if (ret) { -			dev_dbg(dev, "Unable to handle MMC board" -					" level suspend\n"); -			host->suspended = 0; -			return ret; -		} -	}  	ret = mmc_suspend_host(host->mmc);  	if (ret) {  		host->suspended = 0; -		if (host->pdata->resume) { -			if (host->pdata->resume(dev, host->slot_id)) -				dev_dbg(dev, "Unmask interrupt failed\n"); -		}  		goto err;  	} @@ -2088,12 +2150,6 @@ static int omap_hsmmc_resume(struct device *dev)  	if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER))  		omap_hsmmc_conf_bus_power(host); -	if (host->pdata->resume) { -		ret = host->pdata->resume(dev, host->slot_id); -		if (ret) -			dev_dbg(dev, "Unmask interrupt failed\n"); -	} -  	omap_hsmmc_protect_card(host);  	/* Notify the core to resume the host */ @@ -2109,8 +2165,10 @@ static int omap_hsmmc_resume(struct device *dev)  }  #else +#define omap_hsmmc_prepare	NULL +#define omap_hsmmc_complete	NULL  #define omap_hsmmc_suspend	NULL -#define omap_hsmmc_resume		NULL +#define omap_hsmmc_resume	NULL  #endif  static int omap_hsmmc_runtime_suspend(struct device *dev) @@ -2138,6 +2196,8 @@ static int omap_hsmmc_runtime_resume(struct device *dev)  static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {  	.suspend	= omap_hsmmc_suspend,  	.resume		= omap_hsmmc_resume, +	.prepare	= omap_hsmmc_prepare, +	.complete	= omap_hsmmc_complete,  	.runtime_suspend = omap_hsmmc_runtime_suspend,  	.runtime_resume = omap_hsmmc_runtime_resume,  }; diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c new file mode 100644 index 00000000000..12b0a78497f --- /dev/null +++ b/drivers/mmc/host/sdhci-acpi.c @@ -0,0 +1,312 @@ +/* + * Secure Digital Host Controller Interface ACPI driver. + * + * Copyright (c) 2012, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <linux/init.h> +#include <linux/export.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/ioport.h> +#include <linux/io.h> +#include <linux/dma-mapping.h> +#include <linux/compiler.h> +#include <linux/stddef.h> +#include <linux/bitops.h> +#include <linux/types.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/acpi.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> + +#include <linux/mmc/host.h> +#include <linux/mmc/pm.h> +#include <linux/mmc/sdhci.h> + +#include "sdhci.h" + +enum { +	SDHCI_ACPI_SD_CD	= BIT(0), +	SDHCI_ACPI_RUNTIME_PM	= BIT(1), +}; + +struct sdhci_acpi_chip { +	const struct	sdhci_ops *ops; +	unsigned int	quirks; +	unsigned int	quirks2; +	unsigned long	caps; +	unsigned int	caps2; +	mmc_pm_flag_t	pm_caps; +}; + +struct sdhci_acpi_slot { +	const struct	sdhci_acpi_chip *chip; +	unsigned int	quirks; +	unsigned int	quirks2; +	unsigned long	caps; +	unsigned int	caps2; +	mmc_pm_flag_t	pm_caps; +	unsigned int	flags; +}; + +struct sdhci_acpi_host { +	struct sdhci_host		*host; +	const struct sdhci_acpi_slot	*slot; +	struct platform_device		*pdev; +	bool				use_runtime_pm; +}; + +static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag) +{ +	return c->slot && (c->slot->flags & flag); +} + +static int sdhci_acpi_enable_dma(struct sdhci_host *host) +{ +	return 0; +} + +static const struct sdhci_ops sdhci_acpi_ops_dflt = { +	.enable_dma = sdhci_acpi_enable_dma, +}; + +static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = { +	.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON, +	.caps    = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD, +	.flags   = SDHCI_ACPI_RUNTIME_PM, +	.pm_caps = MMC_PM_KEEP_POWER, +}; + +static const struct acpi_device_id sdhci_acpi_ids[] = { +	{ "INT33C6", (kernel_ulong_t)&sdhci_acpi_slot_int_sdio }, +	{ "PNP0D40" }, +	{ }, +}; +MODULE_DEVICE_TABLE(acpi, sdhci_acpi_ids); + +static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(const char *hid) +{ +	const struct acpi_device_id *id; + +	for (id = sdhci_acpi_ids; id->id[0]; id++) +		if (!strcmp(id->id, hid)) +			return (const struct sdhci_acpi_slot *)id->driver_data; +	return NULL; +} + +static int __devinit sdhci_acpi_probe(struct platform_device *pdev) +{ +	struct device *dev = &pdev->dev; +	acpi_handle handle = ACPI_HANDLE(dev); +	struct acpi_device *device; +	struct sdhci_acpi_host *c; +	struct sdhci_host *host; +	struct resource *iomem; +	resource_size_t len; +	const char *hid; +	int err; + +	if (acpi_bus_get_device(handle, &device)) +		return -ENODEV; + +	if (acpi_bus_get_status(device) || !device->status.present) +		return -ENODEV; + +	hid = acpi_device_hid(device); + +	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	if (!iomem) +		return -ENOMEM; + +	len = resource_size(iomem); +	if (len < 0x100) +		dev_err(dev, "Invalid iomem size!\n"); + +	if (!devm_request_mem_region(dev, iomem->start, len, dev_name(dev))) +		return -ENOMEM; + +	host = sdhci_alloc_host(dev, sizeof(struct sdhci_acpi_host)); +	if (IS_ERR(host)) +		return PTR_ERR(host); + +	c = sdhci_priv(host); +	c->host = host; +	c->slot = sdhci_acpi_get_slot(hid); +	c->pdev = pdev; +	c->use_runtime_pm = sdhci_acpi_flag(c, SDHCI_ACPI_RUNTIME_PM); + +	platform_set_drvdata(pdev, c); + +	host->hw_name	= "ACPI"; +	host->ops	= &sdhci_acpi_ops_dflt; +	host->irq	= platform_get_irq(pdev, 0); + +	host->ioaddr = devm_ioremap_nocache(dev, iomem->start, +					    resource_size(iomem)); +	if (host->ioaddr == NULL) { +		err = -ENOMEM; +		goto err_free; +	} + +	if (!dev->dma_mask) { +		u64 dma_mask; + +		if (sdhci_readl(host, SDHCI_CAPABILITIES) & SDHCI_CAN_64BIT) { +			/* 64-bit DMA is not supported at present */ +			dma_mask = DMA_BIT_MASK(32); +		} else { +			dma_mask = DMA_BIT_MASK(32); +		} + +		dev->dma_mask = &dev->coherent_dma_mask; +		dev->coherent_dma_mask = dma_mask; +	} + +	if (c->slot) { +		if (c->slot->chip) { +			host->ops            = c->slot->chip->ops; +			host->quirks        |= c->slot->chip->quirks; +			host->quirks2       |= c->slot->chip->quirks2; +			host->mmc->caps     |= c->slot->chip->caps; +			host->mmc->caps2    |= c->slot->chip->caps2; +			host->mmc->pm_caps  |= c->slot->chip->pm_caps; +		} +		host->quirks        |= c->slot->quirks; +		host->quirks2       |= c->slot->quirks2; +		host->mmc->caps     |= c->slot->caps; +		host->mmc->caps2    |= c->slot->caps2; +		host->mmc->pm_caps  |= c->slot->pm_caps; +	} + +	err = sdhci_add_host(host); +	if (err) +		goto err_free; + +	if (c->use_runtime_pm) { +		pm_suspend_ignore_children(dev, 1); +		pm_runtime_set_autosuspend_delay(dev, 50); +		pm_runtime_use_autosuspend(dev); +		pm_runtime_enable(dev); +	} + +	return 0; + +err_free: +	platform_set_drvdata(pdev, NULL); +	sdhci_free_host(c->host); +	return err; +} + +static int __devexit sdhci_acpi_remove(struct platform_device *pdev) +{ +	struct sdhci_acpi_host *c = platform_get_drvdata(pdev); +	struct device *dev = &pdev->dev; +	int dead; + +	if (c->use_runtime_pm) { +		pm_runtime_get_sync(dev); +		pm_runtime_disable(dev); +		pm_runtime_put_noidle(dev); +	} + +	dead = (sdhci_readl(c->host, SDHCI_INT_STATUS) == ~0); +	sdhci_remove_host(c->host, dead); +	platform_set_drvdata(pdev, NULL); +	sdhci_free_host(c->host); + +	return 0; +} + +#ifdef CONFIG_PM_SLEEP + +static int sdhci_acpi_suspend(struct device *dev) +{ +	struct sdhci_acpi_host *c = dev_get_drvdata(dev); + +	return sdhci_suspend_host(c->host); +} + +static int sdhci_acpi_resume(struct device *dev) +{ +	struct sdhci_acpi_host *c = dev_get_drvdata(dev); + +	return sdhci_resume_host(c->host); +} + +#else + +#define sdhci_acpi_suspend	NULL +#define sdhci_acpi_resume	NULL + +#endif + +#ifdef CONFIG_PM_RUNTIME + +static int sdhci_acpi_runtime_suspend(struct device *dev) +{ +	struct sdhci_acpi_host *c = dev_get_drvdata(dev); + +	return sdhci_runtime_suspend_host(c->host); +} + +static int sdhci_acpi_runtime_resume(struct device *dev) +{ +	struct sdhci_acpi_host *c = dev_get_drvdata(dev); + +	return sdhci_runtime_resume_host(c->host); +} + +static int sdhci_acpi_runtime_idle(struct device *dev) +{ +	return 0; +} + +#else + +#define sdhci_acpi_runtime_suspend	NULL +#define sdhci_acpi_runtime_resume	NULL +#define sdhci_acpi_runtime_idle		NULL + +#endif + +static const struct dev_pm_ops sdhci_acpi_pm_ops = { +	.suspend		= sdhci_acpi_suspend, +	.resume			= sdhci_acpi_resume, +	.runtime_suspend	= sdhci_acpi_runtime_suspend, +	.runtime_resume		= sdhci_acpi_runtime_resume, +	.runtime_idle		= sdhci_acpi_runtime_idle, +}; + +static struct platform_driver sdhci_acpi_driver = { +	.driver = { +		.name			= "sdhci-acpi", +		.owner			= THIS_MODULE, +		.acpi_match_table	= sdhci_acpi_ids, +		.pm			= &sdhci_acpi_pm_ops, +	}, +	.probe	= sdhci_acpi_probe, +	.remove	= __devexit_p(sdhci_acpi_remove), +}; + +module_platform_driver(sdhci_acpi_driver); + +MODULE_DESCRIPTION("Secure Digital Host Controller Interface ACPI driver"); +MODULE_AUTHOR("Adrian Hunter"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c index 90140eb03e3..e6214480bc9 100644 --- a/drivers/mmc/host/sdhci-dove.c +++ b/drivers/mmc/host/sdhci-dove.c @@ -19,19 +19,30 @@   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   */ -#include <linux/io.h>  #include <linux/clk.h>  #include <linux/err.h> -#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/io.h>  #include <linux/mmc/host.h> +#include <linux/module.h>  #include <linux/of.h> +#include <linux/of_gpio.h>  #include "sdhci-pltfm.h"  struct sdhci_dove_priv {  	struct clk *clk; +	int gpio_cd;  }; +static irqreturn_t sdhci_dove_carddetect_irq(int irq, void *data) +{ +	struct sdhci_host *host = data; + +	tasklet_schedule(&host->card_tasklet); +	return IRQ_HANDLED; +} +  static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)  {  	u16 ret; @@ -49,16 +60,25 @@ static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)  static u32 sdhci_dove_readl(struct sdhci_host *host, int reg)  { +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct sdhci_dove_priv *priv = pltfm_host->priv;  	u32 ret; +	ret = readl(host->ioaddr + reg); +  	switch (reg) {  	case SDHCI_CAPABILITIES: -		ret = readl(host->ioaddr + reg);  		/* Mask the support for 3.0V */  		ret &= ~SDHCI_CAN_VDD_300;  		break; -	default: -		ret = readl(host->ioaddr + reg); +	case SDHCI_PRESENT_STATE: +		if (gpio_is_valid(priv->gpio_cd)) { +			if (gpio_get_value(priv->gpio_cd) == 0) +				ret |= SDHCI_CARD_PRESENT; +			else +				ret &= ~SDHCI_CARD_PRESENT; +		} +		break;  	}  	return ret;  } @@ -84,30 +104,77 @@ static int __devinit sdhci_dove_probe(struct platform_device *pdev)  	struct sdhci_dove_priv *priv;  	int ret; -	ret = sdhci_pltfm_register(pdev, &sdhci_dove_pdata); -	if (ret) -		goto sdhci_dove_register_fail; -  	priv = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_dove_priv),  			    GFP_KERNEL);  	if (!priv) {  		dev_err(&pdev->dev, "unable to allocate private data"); -		ret = -ENOMEM; -		goto sdhci_dove_allocate_fail; +		return -ENOMEM; +	} + +	priv->clk = devm_clk_get(&pdev->dev, NULL); + +	if (pdev->dev.of_node) { +		priv->gpio_cd = of_get_named_gpio(pdev->dev.of_node, +						  "cd-gpios", 0); +	} else { +		priv->gpio_cd = -EINVAL; +	} + +	if (gpio_is_valid(priv->gpio_cd)) { +		ret = gpio_request(priv->gpio_cd, "sdhci-cd"); +		if (ret) { +			dev_err(&pdev->dev, "card detect gpio request failed: %d\n", +				ret); +			return ret; +		} +		gpio_direction_input(priv->gpio_cd); +	} + +	host = sdhci_pltfm_init(pdev, &sdhci_dove_pdata); +	if (IS_ERR(host)) { +		ret = PTR_ERR(host); +		goto err_sdhci_pltfm_init;  	} -	host = platform_get_drvdata(pdev);  	pltfm_host = sdhci_priv(host);  	pltfm_host->priv = priv; -	priv->clk = clk_get(&pdev->dev, NULL);  	if (!IS_ERR(priv->clk))  		clk_prepare_enable(priv->clk); + +	sdhci_get_of_property(pdev); + +	ret = sdhci_add_host(host); +	if (ret) +		goto err_sdhci_add; + +	/* +	 * We must request the IRQ after sdhci_add_host(), as the tasklet only +	 * gets setup in sdhci_add_host() and we oops. +	 */ +	if (gpio_is_valid(priv->gpio_cd)) { +		ret = request_irq(gpio_to_irq(priv->gpio_cd), +				  sdhci_dove_carddetect_irq, +				  IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, +				  mmc_hostname(host->mmc), host); +		if (ret) { +			dev_err(&pdev->dev, "card detect irq request failed: %d\n", +				ret); +			goto err_request_irq; +		} +	} +  	return 0; -sdhci_dove_allocate_fail: -	sdhci_pltfm_unregister(pdev); -sdhci_dove_register_fail: +err_request_irq: +	sdhci_remove_host(host, 0); +err_sdhci_add: +	if (!IS_ERR(priv->clk)) +		clk_disable_unprepare(priv->clk); +	sdhci_pltfm_free(pdev); +err_sdhci_pltfm_init: +	if (gpio_is_valid(priv->gpio_cd)) +		gpio_free(priv->gpio_cd);  	return ret;  } @@ -117,14 +184,17 @@ static int __devexit sdhci_dove_remove(struct platform_device *pdev)  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);  	struct sdhci_dove_priv *priv = pltfm_host->priv; -	if (priv->clk) { -		if (!IS_ERR(priv->clk)) { -			clk_disable_unprepare(priv->clk); -			clk_put(priv->clk); -		} -		devm_kfree(&pdev->dev, priv->clk); +	sdhci_pltfm_unregister(pdev); + +	if (gpio_is_valid(priv->gpio_cd)) { +		free_irq(gpio_to_irq(priv->gpio_cd), host); +		gpio_free(priv->gpio_cd);  	} -	return sdhci_pltfm_unregister(pdev); + +	if (!IS_ERR(priv->clk)) +		clk_disable_unprepare(priv->clk); + +	return 0;  }  static const struct of_device_id sdhci_dove_of_match_table[] __devinitdata = { diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index effc2acfe77..1849461c39e 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -456,10 +456,10 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)  	pltfm_host = sdhci_priv(host); -	imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL); +	imx_data = devm_kzalloc(&pdev->dev, sizeof(*imx_data), GFP_KERNEL);  	if (!imx_data) {  		err = -ENOMEM; -		goto err_imx_data; +		goto free_sdhci;  	}  	if (of_id) @@ -470,19 +470,19 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)  	imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg");  	if (IS_ERR(imx_data->clk_ipg)) {  		err = PTR_ERR(imx_data->clk_ipg); -		goto err_clk_get; +		goto free_sdhci;  	}  	imx_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb");  	if (IS_ERR(imx_data->clk_ahb)) {  		err = PTR_ERR(imx_data->clk_ahb); -		goto err_clk_get; +		goto free_sdhci;  	}  	imx_data->clk_per = devm_clk_get(&pdev->dev, "per");  	if (IS_ERR(imx_data->clk_per)) {  		err = PTR_ERR(imx_data->clk_per); -		goto err_clk_get; +		goto free_sdhci;  	}  	pltfm_host->clk = imx_data->clk_per; @@ -494,7 +494,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)  	imx_data->pinctrl = devm_pinctrl_get_select_default(&pdev->dev);  	if (IS_ERR(imx_data->pinctrl)) {  		err = PTR_ERR(imx_data->pinctrl); -		goto pin_err; +		goto disable_clk;  	}  	host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; @@ -519,7 +519,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)  		if (!host->mmc->parent->platform_data) {  			dev_err(mmc_dev(host->mmc), "no board data!\n");  			err = -EINVAL; -			goto no_board_data; +			goto disable_clk;  		}  		imx_data->boarddata = *((struct esdhc_platform_data *)  					host->mmc->parent->platform_data); @@ -527,7 +527,8 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)  	/* write_protect */  	if (boarddata->wp_type == ESDHC_WP_GPIO) { -		err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); +		err = devm_gpio_request_one(&pdev->dev, boarddata->wp_gpio, +					    GPIOF_IN, "ESDHC_WP");  		if (err) {  			dev_warn(mmc_dev(host->mmc),  				 "no write-protect pin available!\n"); @@ -543,19 +544,21 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)  	switch (boarddata->cd_type) {  	case ESDHC_CD_GPIO: -		err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD"); +		err = devm_gpio_request_one(&pdev->dev, boarddata->cd_gpio, +					    GPIOF_IN, "ESDHC_CD");  		if (err) {  			dev_err(mmc_dev(host->mmc),  				"no card-detect pin available!\n"); -			goto no_card_detect_pin; +			goto disable_clk;  		} -		err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq, +		err = devm_request_irq(&pdev->dev, +				 gpio_to_irq(boarddata->cd_gpio), cd_irq,  				 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,  				 mmc_hostname(host->mmc), host);  		if (err) {  			dev_err(mmc_dev(host->mmc), "request irq error\n"); -			goto no_card_detect_irq; +			goto disable_clk;  		}  		/* fall through */ @@ -574,27 +577,15 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)  	err = sdhci_add_host(host);  	if (err) -		goto err_add_host; +		goto disable_clk;  	return 0; -err_add_host: -	if (gpio_is_valid(boarddata->cd_gpio)) -		free_irq(gpio_to_irq(boarddata->cd_gpio), host); -no_card_detect_irq: -	if (gpio_is_valid(boarddata->cd_gpio)) -		gpio_free(boarddata->cd_gpio); -	if (gpio_is_valid(boarddata->wp_gpio)) -		gpio_free(boarddata->wp_gpio); -no_card_detect_pin: -no_board_data: -pin_err: +disable_clk:  	clk_disable_unprepare(imx_data->clk_per);  	clk_disable_unprepare(imx_data->clk_ipg);  	clk_disable_unprepare(imx_data->clk_ahb); -err_clk_get: -	kfree(imx_data); -err_imx_data: +free_sdhci:  	sdhci_pltfm_free(pdev);  	return err;  } @@ -604,25 +595,14 @@ static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)  	struct sdhci_host *host = platform_get_drvdata(pdev);  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);  	struct pltfm_imx_data *imx_data = pltfm_host->priv; -	struct esdhc_platform_data *boarddata = &imx_data->boarddata;  	int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);  	sdhci_remove_host(host, dead); -	if (gpio_is_valid(boarddata->wp_gpio)) -		gpio_free(boarddata->wp_gpio); - -	if (gpio_is_valid(boarddata->cd_gpio)) { -		free_irq(gpio_to_irq(boarddata->cd_gpio), host); -		gpio_free(boarddata->cd_gpio); -	} -  	clk_disable_unprepare(imx_data->clk_per);  	clk_disable_unprepare(imx_data->clk_ipg);  	clk_disable_unprepare(imx_data->clk_ahb); -	kfree(imx_data); -  	sdhci_pltfm_free(pdev);  	return 0; diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index ae5fcbfa1ee..60de2eeb39b 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -22,6 +22,7 @@  #include "sdhci-esdhc.h"  #define VENDOR_V_22	0x12 +#define VENDOR_V_23	0x13  static u32 esdhc_readl(struct sdhci_host *host, int reg)  {  	u32 ret; @@ -85,6 +86,18 @@ static u8 esdhc_readb(struct sdhci_host *host, int reg)  	return ret;  } +static void esdhc_writel(struct sdhci_host *host, u32 val, int reg) +{ +	/* +	 * Enable IRQSTATEN[BGESEN] is just to set IRQSTAT[BGE] +	 * when SYSCTL[RSTD]) is set for some special operations. +	 * No any impact other operation. +	 */ +	if (reg == SDHCI_INT_ENABLE) +		val |= SDHCI_INT_BLK_GAP; +	sdhci_be32bs_writel(host, val, reg); +} +  static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)  {  	if (reg == SDHCI_BLOCK_SIZE) { @@ -121,6 +134,41 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)  	sdhci_be32bs_writeb(host, val, reg);  } +/* + * For Abort or Suspend after Stop at Block Gap, ignore the ADMA + * error(IRQSTAT[ADMAE]) if both Transfer Complete(IRQSTAT[TC]) + * and Block Gap Event(IRQSTAT[BGE]) are also set. + * For Continue, apply soft reset for data(SYSCTL[RSTD]); + * and re-issue the entire read transaction from beginning. + */ +static void esdhci_of_adma_workaround(struct sdhci_host *host, u32 intmask) +{ +	u32 tmp; +	bool applicable; +	dma_addr_t dmastart; +	dma_addr_t dmanow; + +	tmp = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS); +	tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT; + +	applicable = (intmask & SDHCI_INT_DATA_END) && +		(intmask & SDHCI_INT_BLK_GAP) && +		(tmp == VENDOR_V_23); +	if (!applicable) +		return; + +	host->data->error = 0; +	dmastart = sg_dma_address(host->data->sg); +	dmanow = dmastart + host->data->bytes_xfered; +	/* +	 * Force update to the next DMA block boundary. +	 */ +	dmanow = (dmanow & ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) + +		SDHCI_DEFAULT_BOUNDARY_SIZE; +	host->data->bytes_xfered = dmanow - dmastart; +	sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS); +} +  static int esdhc_of_enable_dma(struct sdhci_host *host)  {  	setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP); @@ -169,21 +217,36 @@ static void esdhc_of_resume(struct sdhci_host *host)  }  #endif +static void esdhc_of_platform_init(struct sdhci_host *host) +{ +	u32 vvn; + +	vvn = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS); +	vvn = (vvn & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT; +	if (vvn == VENDOR_V_22) +		host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23; + +	if (vvn > VENDOR_V_22) +		host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; +} +  static struct sdhci_ops sdhci_esdhc_ops = {  	.read_l = esdhc_readl,  	.read_w = esdhc_readw,  	.read_b = esdhc_readb, -	.write_l = sdhci_be32bs_writel, +	.write_l = esdhc_writel,  	.write_w = esdhc_writew,  	.write_b = esdhc_writeb,  	.set_clock = esdhc_of_set_clock,  	.enable_dma = esdhc_of_enable_dma,  	.get_max_clock = esdhc_of_get_max_clock,  	.get_min_clock = esdhc_of_get_min_clock, +	.platform_init = esdhc_of_platform_init,  #ifdef CONFIG_PM  	.platform_suspend = esdhc_of_suspend,  	.platform_resume = esdhc_of_resume,  #endif +	.adma_workaround = esdhci_of_adma_workaround,  };  static struct sdhci_pltfm_data sdhci_esdhc_pdata = { diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 4bb74b042a0..0777fad997b 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -114,6 +114,7 @@ static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot)  		SDHCI_TIMEOUT_CLK_UNIT |  		SDHCI_CAN_VDD_330 | +		SDHCI_CAN_DO_HISPD |  		SDHCI_CAN_DO_SDMA;  	return 0;  } @@ -1196,7 +1197,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(  		return ERR_PTR(-ENODEV);  	} -	if (pci_resource_len(pdev, bar) != 0x100) { +	if (pci_resource_len(pdev, bar) < 0x100) {  		dev_err(&pdev->dev, "Invalid iomem size. You may "  			"experience problems.\n");  	} diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 65551a9709c..d4283ef5917 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -78,6 +78,9 @@ void sdhci_get_of_property(struct platform_device *pdev)  		if (of_get_property(np, "broken-cd", NULL))  			host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; +		if (of_get_property(np, "no-1-8-v", NULL)) +			host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; +  		if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc"))  			host->quirks |= SDHCI_QUIRK_BROKEN_DMA; @@ -89,6 +92,12 @@ void sdhci_get_of_property(struct platform_device *pdev)  		clk = of_get_property(np, "clock-frequency", &size);  		if (clk && size == sizeof(*clk) && *clk)  			pltfm_host->clock = be32_to_cpup(clk); + +		if (of_find_property(np, "keep-power-in-suspend", NULL)) +			host->mmc->pm_caps |= MMC_PM_KEEP_POWER; + +		if (of_find_property(np, "enable-sdio-wakeup", NULL)) +			host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;  	}  }  #else @@ -150,6 +159,13 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,  		goto err_remap;  	} +	/* +	 * Some platforms need to probe the controller to be able to +	 * determine which caps should be used. +	 */ +	if (host->ops && host->ops->platform_init) +		host->ops->platform_init(host); +  	platform_set_drvdata(pdev, host);  	return host; diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index e918a2bb3af..60829c92bcf 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -163,10 +163,18 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)  	return 0;  } +static u32 pxav3_get_max_clock(struct sdhci_host *host) +{ +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + +	return clk_get_rate(pltfm_host->clk); +} +  static struct sdhci_ops pxav3_sdhci_ops = {  	.platform_reset_exit = pxav3_set_private_registers,  	.set_uhs_signaling = pxav3_set_uhs_signaling,  	.platform_send_init_74_clocks = pxav3_gen_init_74_clocks, +	.get_max_clock = pxav3_get_max_clock,  };  #ifdef CONFIG_OF @@ -249,7 +257,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)  	host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL  		| SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC -		| SDHCI_QUIRK_32BIT_ADMA_SIZE; +		| SDHCI_QUIRK_32BIT_ADMA_SIZE +		| SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;  	/* enable 1/8V DDR capable */  	host->mmc->caps |= MMC_CAP_1_8V_DDR; @@ -271,6 +280,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)  		if (pdata->quirks)  			host->quirks |= pdata->quirks; +		if (pdata->quirks2) +			host->quirks2 |= pdata->quirks2;  		if (pdata->host_caps)  			host->mmc->caps |= pdata->host_caps;  		if (pdata->host_caps2) diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 2903949594c..82b7a7ad421 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -24,6 +24,7 @@  #include <linux/of_gpio.h>  #include <linux/pm.h>  #include <linux/pm_runtime.h> +#include <linux/pinctrl/consumer.h>  #include <linux/mmc/host.h> @@ -57,6 +58,7 @@ struct sdhci_s3c {  	int			ext_cd_irq;  	int			ext_cd_gpio;  	int			*gpios; +	struct pinctrl          *pctrl;  	struct clk		*clk_io;  	struct clk		*clk_bus[MAX_BUS_CLK]; @@ -211,8 +213,8 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)  	if (ourhost->cur_clk != best_src) {  		struct clk *clk = ourhost->clk_bus[best_src]; -		clk_enable(clk); -		clk_disable(ourhost->clk_bus[ourhost->cur_clk]); +		clk_prepare_enable(clk); +		clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]);  		/* turn clock off to card before changing clock source */  		writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL); @@ -373,18 +375,27 @@ static struct sdhci_ops sdhci_s3c_ops = {  static void sdhci_s3c_notify_change(struct platform_device *dev, int state)  {  	struct sdhci_host *host = platform_get_drvdata(dev); +#ifdef CONFIG_PM_RUNTIME +	struct sdhci_s3c *sc = sdhci_priv(host); +#endif  	unsigned long flags;  	if (host) {  		spin_lock_irqsave(&host->lock, flags);  		if (state) {  			dev_dbg(&dev->dev, "card inserted.\n"); +#ifdef CONFIG_PM_RUNTIME +			clk_prepare_enable(sc->clk_io); +#endif  			host->flags &= ~SDHCI_DEVICE_DEAD;  			host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;  		} else {  			dev_dbg(&dev->dev, "card removed.\n");  			host->flags |= SDHCI_DEVICE_DEAD;  			host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; +#ifdef CONFIG_PM_RUNTIME +			clk_disable_unprepare(sc->clk_io); +#endif  		}  		tasklet_schedule(&host->card_tasklet);  		spin_unlock_irqrestore(&host->lock, flags); @@ -406,7 +417,7 @@ static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc)  	struct s3c_sdhci_platdata *pdata = sc->pdata;  	struct device *dev = &sc->pdev->dev; -	if (gpio_request(pdata->ext_cd_gpio, "SDHCI EXT CD") == 0) { +	if (devm_gpio_request(dev, pdata->ext_cd_gpio, "SDHCI EXT CD") == 0) {  		sc->ext_cd_gpio = pdata->ext_cd_gpio;  		sc->ext_cd_irq = gpio_to_irq(pdata->ext_cd_gpio);  		if (sc->ext_cd_irq && @@ -449,12 +460,12 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,  		return -ENOMEM;  	/* get the card detection method */ -	if (of_get_property(node, "broken-cd", 0)) { +	if (of_get_property(node, "broken-cd", NULL)) {  		pdata->cd_type = S3C_SDHCI_CD_NONE;  		goto setup_bus;  	} -	if (of_get_property(node, "non-removable", 0)) { +	if (of_get_property(node, "non-removable", NULL)) {  		pdata->cd_type = S3C_SDHCI_CD_PERMANENT;  		goto setup_bus;  	} @@ -477,8 +488,9 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,  		return -EINVAL;  	} -	dev_info(dev, "assuming no card detect line available\n"); -	pdata->cd_type = S3C_SDHCI_CD_NONE; +	/* assuming internal card detect that will be configured by pinctrl */ +	pdata->cd_type = S3C_SDHCI_CD_INTERNAL; +	goto setup_bus;   found_cd:  	if (pdata->cd_type == S3C_SDHCI_CD_GPIO) { @@ -487,7 +499,7 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,  		if (of_get_property(node, "cd-inverted", NULL))  			pdata->ext_cd_gpio_invert = 1;  	} else if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { -		ret = gpio_request(gpio, "sdhci-cd"); +		ret = devm_gpio_request(dev, gpio, "sdhci-cd");  		if (ret) {  			dev_err(dev, "card detect gpio request failed\n");  			return -EINVAL; @@ -496,33 +508,28 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,  	}   setup_bus: +	if (!IS_ERR(ourhost->pctrl)) +		return 0; +  	/* get the gpios for command, clock and data lines */  	for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) {  		gpio = of_get_gpio(node, cnt);  		if (!gpio_is_valid(gpio)) {  			dev_err(dev, "invalid gpio[%d]\n", cnt); -			goto err_free_dt_cd_gpio; +			return -EINVAL;  		}  		ourhost->gpios[cnt] = gpio;  	}  	for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) { -		ret = gpio_request(ourhost->gpios[cnt], "sdhci-gpio"); +		ret = devm_gpio_request(dev, ourhost->gpios[cnt], "sdhci-gpio");  		if (ret) {  			dev_err(dev, "gpio[%d] request failed\n", cnt); -			goto err_free_dt_gpios; +			return -EINVAL;  		}  	}  	return 0; - - err_free_dt_gpios: -	while (--cnt >= 0) -		gpio_free(ourhost->gpios[cnt]); - err_free_dt_cd_gpio: -	if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) -		gpio_free(ourhost->ext_cd_gpio); -	return -EINVAL;  }  #else  static int __devinit sdhci_s3c_parse_dt(struct device *dev, @@ -579,13 +586,15 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)  	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);  	if (!pdata) {  		ret = -ENOMEM; -		goto err_pdata; +		goto err_pdata_io_clk;  	} +	sc->pctrl = devm_pinctrl_get_select_default(&pdev->dev); +  	if (pdev->dev.of_node) {  		ret = sdhci_s3c_parse_dt(&pdev->dev, host, pdata);  		if (ret) -			goto err_pdata; +			goto err_pdata_io_clk;  	} else {  		memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));  		sc->ext_cd_gpio = -1; /* invalid gpio number */ @@ -603,11 +612,11 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)  	if (IS_ERR(sc->clk_io)) {  		dev_err(dev, "failed to get io clock\n");  		ret = PTR_ERR(sc->clk_io); -		goto err_io_clk; +		goto err_pdata_io_clk;  	}  	/* enable the local io clock and keep it running for the moment. */ -	clk_enable(sc->clk_io); +	clk_prepare_enable(sc->clk_io);  	for (clks = 0, ptr = 0; ptr < MAX_BUS_CLK; ptr++) {  		struct clk *clk; @@ -638,7 +647,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)  	}  #ifndef CONFIG_PM_RUNTIME -	clk_enable(sc->clk_bus[sc->cur_clk]); +	clk_prepare_enable(sc->clk_bus[sc->cur_clk]);  #endif  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -747,13 +756,14 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)  		sdhci_s3c_setup_card_detect_gpio(sc);  #ifdef CONFIG_PM_RUNTIME -	clk_disable(sc->clk_io); +	if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL) +		clk_disable_unprepare(sc->clk_io);  #endif  	return 0;   err_req_regs:  #ifndef CONFIG_PM_RUNTIME -	clk_disable(sc->clk_bus[sc->cur_clk]); +	clk_disable_unprepare(sc->clk_bus[sc->cur_clk]);  #endif  	for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) {  		if (sc->clk_bus[ptr]) { @@ -762,16 +772,10 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)  	}   err_no_busclks: -	clk_disable(sc->clk_io); +	clk_disable_unprepare(sc->clk_io);  	clk_put(sc->clk_io); - err_io_clk: -	for (ptr = 0; ptr < NUM_GPIOS(sc->pdata->max_width); ptr++) -		gpio_free(sc->gpios[ptr]); -	if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) -		gpio_free(sc->ext_cd_gpio); - - err_pdata: + err_pdata_io_clk:  	sdhci_free_host(host);  	return ret; @@ -790,11 +794,9 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev)  	if (sc->ext_cd_irq)  		free_irq(sc->ext_cd_irq, sc); -	if (gpio_is_valid(sc->ext_cd_gpio)) -		gpio_free(sc->ext_cd_gpio); -  #ifdef CONFIG_PM_RUNTIME -	clk_enable(sc->clk_io); +	if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL) +		clk_prepare_enable(sc->clk_io);  #endif  	sdhci_remove_host(host, 1); @@ -802,21 +804,16 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev)  	pm_runtime_disable(&pdev->dev);  #ifndef CONFIG_PM_RUNTIME -	clk_disable(sc->clk_bus[sc->cur_clk]); +	clk_disable_unprepare(sc->clk_bus[sc->cur_clk]);  #endif  	for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) {  		if (sc->clk_bus[ptr]) {  			clk_put(sc->clk_bus[ptr]);  		}  	} -	clk_disable(sc->clk_io); +	clk_disable_unprepare(sc->clk_io);  	clk_put(sc->clk_io); -	if (pdev->dev.of_node) { -		for (ptr = 0; ptr < NUM_GPIOS(sc->pdata->max_width); ptr++) -			gpio_free(sc->gpios[ptr]); -	} -  	sdhci_free_host(host);  	platform_set_drvdata(pdev, NULL); @@ -849,8 +846,8 @@ static int sdhci_s3c_runtime_suspend(struct device *dev)  	ret = sdhci_runtime_suspend_host(host); -	clk_disable(ourhost->clk_bus[ourhost->cur_clk]); -	clk_disable(busclk); +	clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]); +	clk_disable_unprepare(busclk);  	return ret;  } @@ -861,8 +858,8 @@ static int sdhci_s3c_runtime_resume(struct device *dev)  	struct clk *busclk = ourhost->clk_io;  	int ret; -	clk_enable(busclk); -	clk_enable(ourhost->clk_bus[ourhost->cur_clk]); +	clk_prepare_enable(busclk); +	clk_prepare_enable(ourhost->clk_bus[ourhost->cur_clk]);  	ret = sdhci_runtime_resume_host(host);  	return ret;  } diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index 6be89c032de..87a700944b7 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -146,6 +146,11 @@ static int __devinit sdhci_probe(struct platform_device *pdev)  		goto put_clk;  	} +	ret = clk_set_rate(sdhci->clk, 50000000); +	if (ret) +		dev_dbg(&pdev->dev, "Error setting desired clk, clk=%lu\n", +				clk_get_rate(sdhci->clk)); +  	if (np) {  		sdhci->data = sdhci_probe_config_dt(pdev);  		if (IS_ERR(sdhci->data)) { @@ -297,7 +302,7 @@ static int sdhci_suspend(struct device *dev)  	ret = sdhci_suspend_host(host);  	if (!ret) -		clk_disable_unprepare(sdhci->clk); +		clk_disable(sdhci->clk);  	return ret;  } @@ -308,7 +313,7 @@ static int sdhci_resume(struct device *dev)  	struct spear_sdhci *sdhci = dev_get_platdata(dev);  	int ret; -	ret = clk_prepare_enable(sdhci->clk); +	ret = clk_enable(sdhci->clk);  	if (ret) {  		dev_dbg(dev, "Resume: Error enabling clock\n");  		return ret; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 7922adb4238..6f0bfc0c8c9 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1315,16 +1315,19 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)  		 */  		if ((host->flags & SDHCI_NEEDS_RETUNING) &&  		    !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) { -			/* eMMC uses cmd21 while sd and sdio use cmd19 */ -			tuning_opcode = mmc->card->type == MMC_TYPE_MMC ? -				MMC_SEND_TUNING_BLOCK_HS200 : -				MMC_SEND_TUNING_BLOCK; -			spin_unlock_irqrestore(&host->lock, flags); -			sdhci_execute_tuning(mmc, tuning_opcode); -			spin_lock_irqsave(&host->lock, flags); +			if (mmc->card) { +				/* eMMC uses cmd21 but sd and sdio use cmd19 */ +				tuning_opcode = +					mmc->card->type == MMC_TYPE_MMC ? +					MMC_SEND_TUNING_BLOCK_HS200 : +					MMC_SEND_TUNING_BLOCK; +				spin_unlock_irqrestore(&host->lock, flags); +				sdhci_execute_tuning(mmc, tuning_opcode); +				spin_lock_irqsave(&host->lock, flags); -			/* Restore original mmc_request structure */ -			host->mrq = mrq; +				/* Restore original mmc_request structure */ +				host->mrq = mrq; +			}  		}  		if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23)) @@ -1615,7 +1618,7 @@ static int sdhci_do_3_3v_signal_voltage_switch(struct sdhci_host *host,  	sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);  	if (host->vqmmc) { -		ret = regulator_set_voltage(host->vqmmc, 3300000, 3300000); +		ret = regulator_set_voltage(host->vqmmc, 2700000, 3600000);  		if (ret) {  			pr_warning("%s: Switching to 3.3V signalling voltage "  				   " failed\n", mmc_hostname(host->mmc)); @@ -1659,7 +1662,7 @@ static int sdhci_do_1_8v_signal_voltage_switch(struct sdhci_host *host,  		 */  		if (host->vqmmc)  			ret = regulator_set_voltage(host->vqmmc, -				1800000, 1800000); +				1700000, 1950000);  		else  			ret = 0; @@ -1991,30 +1994,11 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable)  	sdhci_runtime_pm_put(host);  } -static const struct mmc_host_ops sdhci_ops = { -	.request	= sdhci_request, -	.set_ios	= sdhci_set_ios, -	.get_ro		= sdhci_get_ro, -	.hw_reset	= sdhci_hw_reset, -	.enable_sdio_irq = sdhci_enable_sdio_irq, -	.start_signal_voltage_switch	= sdhci_start_signal_voltage_switch, -	.execute_tuning			= sdhci_execute_tuning, -	.enable_preset_value		= sdhci_enable_preset_value, -}; - -/*****************************************************************************\ - *                                                                           * - * Tasklets                                                                  * - *                                                                           * -\*****************************************************************************/ - -static void sdhci_tasklet_card(unsigned long param) +static void sdhci_card_event(struct mmc_host *mmc)  { -	struct sdhci_host *host; +	struct sdhci_host *host = mmc_priv(mmc);  	unsigned long flags; -	host = (struct sdhci_host*)param; -  	spin_lock_irqsave(&host->lock, flags);  	/* Check host->mrq first in case we are runtime suspended */ @@ -2033,6 +2017,31 @@ static void sdhci_tasklet_card(unsigned long param)  	}  	spin_unlock_irqrestore(&host->lock, flags); +} + +static const struct mmc_host_ops sdhci_ops = { +	.request	= sdhci_request, +	.set_ios	= sdhci_set_ios, +	.get_ro		= sdhci_get_ro, +	.hw_reset	= sdhci_hw_reset, +	.enable_sdio_irq = sdhci_enable_sdio_irq, +	.start_signal_voltage_switch	= sdhci_start_signal_voltage_switch, +	.execute_tuning			= sdhci_execute_tuning, +	.enable_preset_value		= sdhci_enable_preset_value, +	.card_event			= sdhci_card_event, +}; + +/*****************************************************************************\ + *                                                                           * + * Tasklets                                                                  * + *                                                                           * +\*****************************************************************************/ + +static void sdhci_tasklet_card(unsigned long param) +{ +	struct sdhci_host *host = (struct sdhci_host*)param; + +	sdhci_card_event(host->mmc);  	mmc_detect_change(host->mmc, msecs_to_jiffies(200));  } @@ -2279,6 +2288,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)  		pr_err("%s: ADMA error\n", mmc_hostname(host->mmc));  		sdhci_show_adma_error(host);  		host->data->error = -EIO; +		if (host->ops->adma_workaround) +			host->ops->adma_workaround(host, intmask);  	}  	if (host->data->error) @@ -2837,6 +2848,9 @@ int sdhci_add_host(struct sdhci_host *host)  	if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))  		mmc->caps |= MMC_CAP_4_BIT_DATA; +	if (host->quirks2 & SDHCI_QUIRK2_HOST_NO_CMD23) +		mmc->caps &= ~MMC_CAP_CMD23; +  	if (caps[0] & SDHCI_CAN_DO_HISPD)  		mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; @@ -2846,13 +2860,22 @@ int sdhci_add_host(struct sdhci_host *host)  	/* If vqmmc regulator and no 1.8V signalling, then there's no UHS */  	host->vqmmc = regulator_get(mmc_dev(mmc), "vqmmc"); -	if (IS_ERR(host->vqmmc)) { -		pr_info("%s: no vqmmc regulator found\n", mmc_hostname(mmc)); -		host->vqmmc = NULL; -	} -	else if (regulator_is_supported_voltage(host->vqmmc, 1800000, 1800000)) +	if (IS_ERR_OR_NULL(host->vqmmc)) { +		if (PTR_ERR(host->vqmmc) < 0) { +			pr_info("%s: no vqmmc regulator found\n", +				mmc_hostname(mmc)); +			host->vqmmc = NULL; +		} +	} else {  		regulator_enable(host->vqmmc); -	else +		if (!regulator_is_supported_voltage(host->vqmmc, 1700000, +			1950000)) +			caps[1] &= ~(SDHCI_SUPPORT_SDR104 | +					SDHCI_SUPPORT_SDR50 | +					SDHCI_SUPPORT_DDR50); +	} + +	if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V)  		caps[1] &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |  		       SDHCI_SUPPORT_DDR50); @@ -2904,24 +2927,24 @@ int sdhci_add_host(struct sdhci_host *host)  	ocr_avail = 0;  	host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); -	if (IS_ERR(host->vmmc)) { -		pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); -		host->vmmc = NULL; -	} else -		regulator_enable(host->vmmc); +	if (IS_ERR_OR_NULL(host->vmmc)) { +		if (PTR_ERR(host->vmmc) < 0) { +			pr_info("%s: no vmmc regulator found\n", +				mmc_hostname(mmc)); +			host->vmmc = NULL; +		} +	}  #ifdef CONFIG_REGULATOR  	if (host->vmmc) { -		ret = regulator_is_supported_voltage(host->vmmc, 3300000, -			3300000); +		ret = regulator_is_supported_voltage(host->vmmc, 2700000, +			3600000);  		if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_330)))  			caps[0] &= ~SDHCI_CAN_VDD_330; -		ret = regulator_is_supported_voltage(host->vmmc, 3000000, -			3000000);  		if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_300)))  			caps[0] &= ~SDHCI_CAN_VDD_300; -		ret = regulator_is_supported_voltage(host->vmmc, 1800000, -			1800000); +		ret = regulator_is_supported_voltage(host->vmmc, 1700000, +			1950000);  		if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_180)))  			caps[0] &= ~SDHCI_CAN_VDD_180;  	} diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 97653ea8942..a6d69b7bdea 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -120,6 +120,7 @@  #define SDHCI_SIGNAL_ENABLE	0x38  #define  SDHCI_INT_RESPONSE	0x00000001  #define  SDHCI_INT_DATA_END	0x00000002 +#define  SDHCI_INT_BLK_GAP	0x00000004  #define  SDHCI_INT_DMA_END	0x00000008  #define  SDHCI_INT_SPACE_AVAIL	0x00000010  #define  SDHCI_INT_DATA_AVAIL	0x00000020 @@ -146,7 +147,8 @@  #define  SDHCI_INT_DATA_MASK	(SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \  		SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \  		SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \ -		SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR) +		SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \ +		SDHCI_INT_BLK_GAP)  #define SDHCI_INT_ALL_MASK	((unsigned int)-1)  #define SDHCI_ACMD12_ERR	0x3C @@ -278,6 +280,8 @@ struct sdhci_ops {  	void	(*hw_reset)(struct sdhci_host *host);  	void	(*platform_suspend)(struct sdhci_host *host);  	void	(*platform_resume)(struct sdhci_host *host); +	void    (*adma_workaround)(struct sdhci_host *host, u32 intmask); +	void	(*platform_init)(struct sdhci_host *host);  };  #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 11d2bc3b51d..ae795233a1d 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1104,7 +1104,6 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)  {  	struct sh_mmcif_host *host = dev_id;  	struct mmc_request *mrq = host->mrq; -	struct mmc_data *data = mrq->data;  	cancel_delayed_work_sync(&host->timeout_work); @@ -1152,13 +1151,14 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)  	case MMCIF_WAIT_FOR_READ_END:  	case MMCIF_WAIT_FOR_WRITE_END:  		if (host->sd_error) -			data->error = sh_mmcif_error_manage(host); +			mrq->data->error = sh_mmcif_error_manage(host);  		break;  	default:  		BUG();  	}  	if (host->wait_for != MMCIF_WAIT_FOR_STOP) { +		struct mmc_data *data = mrq->data;  		if (!mrq->cmd->error && data && !data->error)  			data->bytes_xfered =  				data->blocks * data->blksz; @@ -1231,10 +1231,6 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)  		host->sd_error = true;  		dev_dbg(&host->pd->dev, "int err state = %08x\n", state);  	} -	if (host->state == STATE_IDLE) { -		dev_info(&host->pd->dev, "Spurious IRQ status 0x%x", state); -		return IRQ_HANDLED; -	}  	if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) {  		if (!host->dma_active)  			return IRQ_WAKE_THREAD; @@ -1310,7 +1306,6 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)  	struct sh_mmcif_plat_data *pd = pdev->dev.platform_data;  	struct resource *res;  	void __iomem *reg; -	char clk_name[8];  	irq[0] = platform_get_irq(pdev, 0);  	irq[1] = platform_get_irq(pdev, 1); @@ -1360,11 +1355,10 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)  	pm_runtime_enable(&pdev->dev);  	host->power = false; -	snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id); -	host->hclk = clk_get(&pdev->dev, clk_name); +	host->hclk = clk_get(&pdev->dev, NULL);  	if (IS_ERR(host->hclk)) {  		ret = PTR_ERR(host->hclk); -		dev_err(&pdev->dev, "cannot get clock \"%s\": %d\n", clk_name, ret); +		dev_err(&pdev->dev, "cannot get clock: %d\n", ret);  		goto eclkget;  	}  	ret = sh_mmcif_clk_update(host); @@ -1466,9 +1460,9 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)  	platform_set_drvdata(pdev, NULL); +	clk_disable(host->hclk);  	mmc_free_host(host->mmc);  	pm_runtime_put_sync(&pdev->dev); -	clk_disable(host->hclk);  	pm_runtime_disable(&pdev->dev);  	return 0; diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 0bdc146178d..d6ff8531fb3 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -123,7 +123,6 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)  	struct tmio_mmc_data *mmc_data;  	struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;  	struct tmio_mmc_host *host; -	char clk_name[8];  	int irq, ret, i = 0;  	bool multiplexed_isr = true; @@ -144,11 +143,10 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)  		}  	} -	snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id); -	priv->clk = clk_get(&pdev->dev, clk_name); +	priv->clk = clk_get(&pdev->dev, NULL);  	if (IS_ERR(priv->clk)) { -		dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);  		ret = PTR_ERR(priv->clk); +		dev_err(&pdev->dev, "cannot get clock: %d\n", ret);  		goto eclkget;  	} @@ -250,7 +248,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)  	dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n",  		 mmc_hostname(host->mmc), (unsigned long)  		 (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start), -		 mmc_data->hclk / 1000000); +		 host->mmc->f_max / 1000000);  	return ret; diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index d5655a63eda..cb9f361c03a 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -2362,6 +2362,7 @@ error4:  error1:  	usb_free_urb(command_out_urb);  error0: +	usb_put_dev(udev);  	return retval;  } diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c new file mode 100644 index 00000000000..5ba4605e4f8 --- /dev/null +++ b/drivers/mmc/host/wmt-sdmmc.c @@ -0,0 +1,1029 @@ +/* + *  WM8505/WM8650 SD/MMC Host Controller + * + *  Copyright (C) 2010 Tony Prisk + *  Copyright (C) 2008 WonderMedia Technologies, Inc. + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License version 2 as + *  published by the Free Software Foundation + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/ioport.h> +#include <linux/errno.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/clk.h> +#include <linux/gpio.h> + +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_device.h> + +#include <linux/mmc/host.h> +#include <linux/mmc/mmc.h> +#include <linux/mmc/sd.h> + +#include <asm/byteorder.h> + + +#define DRIVER_NAME "wmt-sdhc" + + +/* MMC/SD controller registers */ +#define SDMMC_CTLR			0x00 +#define SDMMC_CMD			0x01 +#define SDMMC_RSPTYPE			0x02 +#define SDMMC_ARG			0x04 +#define SDMMC_BUSMODE			0x08 +#define SDMMC_BLKLEN			0x0C +#define SDMMC_BLKCNT			0x0E +#define SDMMC_RSP			0x10 +#define SDMMC_CBCR			0x20 +#define SDMMC_INTMASK0			0x24 +#define SDMMC_INTMASK1			0x25 +#define SDMMC_STS0			0x28 +#define SDMMC_STS1			0x29 +#define SDMMC_STS2			0x2A +#define SDMMC_STS3			0x2B +#define SDMMC_RSPTIMEOUT		0x2C +#define SDMMC_CLK			0x30	/* VT8500 only */ +#define SDMMC_EXTCTRL			0x34 +#define SDMMC_SBLKLEN			0x38 +#define SDMMC_DMATIMEOUT		0x3C + + +/* SDMMC_CTLR bit fields */ +#define CTLR_CMD_START			0x01 +#define CTLR_CMD_WRITE			0x04 +#define CTLR_FIFO_RESET			0x08 + +/* SDMMC_BUSMODE bit fields */ +#define BM_SPI_MODE			0x01 +#define BM_FOURBIT_MODE			0x02 +#define BM_EIGHTBIT_MODE		0x04 +#define BM_SD_OFF			0x10 +#define BM_SPI_CS			0x20 +#define BM_SD_POWER			0x40 +#define BM_SOFT_RESET			0x80 +#define BM_ONEBIT_MASK			0xFD + +/* SDMMC_BLKLEN bit fields */ +#define BLKL_CRCERR_ABORT		0x0800 +#define BLKL_CD_POL_HIGH		0x1000 +#define BLKL_GPI_CD			0x2000 +#define BLKL_DATA3_CD			0x4000 +#define BLKL_INT_ENABLE			0x8000 + +/* SDMMC_INTMASK0 bit fields */ +#define INT0_MBLK_TRAN_DONE_INT_EN	0x10 +#define INT0_BLK_TRAN_DONE_INT_EN	0x20 +#define INT0_CD_INT_EN			0x40 +#define INT0_DI_INT_EN			0x80 + +/* SDMMC_INTMASK1 bit fields */ +#define INT1_CMD_RES_TRAN_DONE_INT_EN	0x02 +#define INT1_CMD_RES_TOUT_INT_EN	0x04 +#define INT1_MBLK_AUTO_STOP_INT_EN	0x08 +#define INT1_DATA_TOUT_INT_EN		0x10 +#define INT1_RESCRC_ERR_INT_EN		0x20 +#define INT1_RCRC_ERR_INT_EN		0x40 +#define INT1_WCRC_ERR_INT_EN		0x80 + +/* SDMMC_STS0 bit fields */ +#define STS0_WRITE_PROTECT		0x02 +#define STS0_CD_DATA3			0x04 +#define STS0_CD_GPI			0x08 +#define STS0_MBLK_DONE			0x10 +#define STS0_BLK_DONE			0x20 +#define STS0_CARD_DETECT		0x40 +#define STS0_DEVICE_INS			0x80 + +/* SDMMC_STS1 bit fields */ +#define STS1_SDIO_INT			0x01 +#define STS1_CMDRSP_DONE		0x02 +#define STS1_RSP_TIMEOUT		0x04 +#define STS1_AUTOSTOP_DONE		0x08 +#define STS1_DATA_TIMEOUT		0x10 +#define STS1_RSP_CRC_ERR		0x20 +#define STS1_RCRC_ERR			0x40 +#define STS1_WCRC_ERR			0x80 + +/* SDMMC_STS2 bit fields */ +#define STS2_CMD_RES_BUSY		0x10 +#define STS2_DATARSP_BUSY		0x20 +#define STS2_DIS_FORCECLK		0x80 + + +/* MMC/SD DMA Controller Registers */ +#define SDDMA_GCR			0x100 +#define SDDMA_IER			0x104 +#define SDDMA_ISR			0x108 +#define SDDMA_DESPR			0x10C +#define SDDMA_RBR			0x110 +#define SDDMA_DAR			0x114 +#define SDDMA_BAR			0x118 +#define SDDMA_CPR			0x11C +#define SDDMA_CCR			0x120 + + +/* SDDMA_GCR bit fields */ +#define DMA_GCR_DMA_EN			0x00000001 +#define DMA_GCR_SOFT_RESET		0x00000100 + +/* SDDMA_IER bit fields */ +#define DMA_IER_INT_EN			0x00000001 + +/* SDDMA_ISR bit fields */ +#define DMA_ISR_INT_STS			0x00000001 + +/* SDDMA_RBR bit fields */ +#define DMA_RBR_FORMAT			0x40000000 +#define DMA_RBR_END			0x80000000 + +/* SDDMA_CCR bit fields */ +#define DMA_CCR_RUN			0x00000080 +#define DMA_CCR_IF_TO_PERIPHERAL	0x00000000 +#define DMA_CCR_PERIPHERAL_TO_IF	0x00400000 + +/* SDDMA_CCR event status */ +#define DMA_CCR_EVT_NO_STATUS		0x00000000 +#define DMA_CCR_EVT_UNDERRUN		0x00000001 +#define DMA_CCR_EVT_OVERRUN		0x00000002 +#define DMA_CCR_EVT_DESP_READ		0x00000003 +#define DMA_CCR_EVT_DATA_RW		0x00000004 +#define DMA_CCR_EVT_EARLY_END		0x00000005 +#define DMA_CCR_EVT_SUCCESS		0x0000000F + +#define PDMA_READ			0x00 +#define PDMA_WRITE			0x01 + +#define WMT_SD_POWER_OFF		0 +#define WMT_SD_POWER_ON			1 + +struct wmt_dma_descriptor { +	u32 flags; +	u32 data_buffer_addr; +	u32 branch_addr; +	u32 reserved1; +}; + +struct wmt_mci_caps { +	unsigned int	f_min; +	unsigned int	f_max; +	u32		ocr_avail; +	u32		caps; +	u32		max_seg_size; +	u32		max_segs; +	u32		max_blk_size; +}; + +struct wmt_mci_priv { +	struct mmc_host *mmc; +	void __iomem *sdmmc_base; + +	int irq_regular; +	int irq_dma; + +	void *dma_desc_buffer; +	dma_addr_t dma_desc_device_addr; + +	struct completion cmdcomp; +	struct completion datacomp; + +	struct completion *comp_cmd; +	struct completion *comp_dma; + +	struct mmc_request *req; +	struct mmc_command *cmd; + +	struct clk *clk_sdmmc; +	struct device *dev; + +	u8 power_inverted; +	u8 cd_inverted; +}; + +static void wmt_set_sd_power(struct wmt_mci_priv *priv, int enable) +{ +	u32 reg_tmp; +	if (enable) { +		if (priv->power_inverted) { +			reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); +			writeb(reg_tmp | BM_SD_OFF, +			       priv->sdmmc_base + SDMMC_BUSMODE); +		} else { +			reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); +			writeb(reg_tmp & (~BM_SD_OFF), +			       priv->sdmmc_base + SDMMC_BUSMODE); +		} +	} else { +		if (priv->power_inverted) { +			reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); +			writeb(reg_tmp & (~BM_SD_OFF), +			       priv->sdmmc_base + SDMMC_BUSMODE); +		} else { +			reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); +			writeb(reg_tmp | BM_SD_OFF, +			       priv->sdmmc_base + SDMMC_BUSMODE); +		} +	} +} + +static void wmt_mci_read_response(struct mmc_host *mmc) +{ +	struct wmt_mci_priv *priv; +	int idx1, idx2; +	u8 tmp_resp; +	u32 response; + +	priv = mmc_priv(mmc); + +	for (idx1 = 0; idx1 < 4; idx1++) { +		response = 0; +		for (idx2 = 0; idx2 < 4; idx2++) { +			if ((idx1 == 3) && (idx2 == 3)) +				tmp_resp = readb(priv->sdmmc_base + SDMMC_RSP); +			else +				tmp_resp = readb(priv->sdmmc_base + SDMMC_RSP + +						 (idx1*4) + idx2 + 1); +			response |= (tmp_resp << (idx2 * 8)); +		} +		priv->cmd->resp[idx1] = cpu_to_be32(response); +	} +} + +static void wmt_mci_start_command(struct wmt_mci_priv *priv) +{ +	u32 reg_tmp; + +	reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR); +	writeb(reg_tmp | CTLR_CMD_START, priv->sdmmc_base + SDMMC_CTLR); +} + +static int wmt_mci_send_command(struct mmc_host *mmc, u8 command, u8 cmdtype, +				u32 arg, u8 rsptype) +{ +	struct wmt_mci_priv *priv; +	u32 reg_tmp; + +	priv = mmc_priv(mmc); + +	/* write command, arg, resptype registers */ +	writeb(command, priv->sdmmc_base + SDMMC_CMD); +	writel(arg, priv->sdmmc_base + SDMMC_ARG); +	writeb(rsptype, priv->sdmmc_base + SDMMC_RSPTYPE); + +	/* reset response FIFO */ +	reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR); +	writeb(reg_tmp | CTLR_FIFO_RESET, priv->sdmmc_base + SDMMC_CTLR); + +	/* ensure clock enabled - VT3465 */ +	wmt_set_sd_power(priv, WMT_SD_POWER_ON); + +	/* clear status bits */ +	writeb(0xFF, priv->sdmmc_base + SDMMC_STS0); +	writeb(0xFF, priv->sdmmc_base + SDMMC_STS1); +	writeb(0xFF, priv->sdmmc_base + SDMMC_STS2); +	writeb(0xFF, priv->sdmmc_base + SDMMC_STS3); + +	/* set command type */ +	reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR); +	writeb((reg_tmp & 0x0F) | (cmdtype << 4), +	       priv->sdmmc_base + SDMMC_CTLR); + +	return 0; +} + +static void wmt_mci_disable_dma(struct wmt_mci_priv *priv) +{ +	writel(DMA_ISR_INT_STS, priv->sdmmc_base + SDDMA_ISR); +	writel(0, priv->sdmmc_base + SDDMA_IER); +} + +static void wmt_complete_data_request(struct wmt_mci_priv *priv) +{ +	struct mmc_request *req; +	req = priv->req; + +	req->data->bytes_xfered = req->data->blksz * req->data->blocks; + +	/* unmap the DMA pages used for write data */ +	if (req->data->flags & MMC_DATA_WRITE) +		dma_unmap_sg(mmc_dev(priv->mmc), req->data->sg, +			     req->data->sg_len, DMA_TO_DEVICE); +	else +		dma_unmap_sg(mmc_dev(priv->mmc), req->data->sg, +			     req->data->sg_len, DMA_FROM_DEVICE); + +	/* Check if the DMA ISR returned a data error */ +	if ((req->cmd->error) || (req->data->error)) +		mmc_request_done(priv->mmc, req); +	else { +		wmt_mci_read_response(priv->mmc); +		if (!req->data->stop) { +			/* single-block read/write requests end here */ +			mmc_request_done(priv->mmc, req); +		} else { +			/* +			 * we change the priv->cmd variable so the response is +			 * stored in the stop struct rather than the original +			 * calling command struct +			 */ +			priv->comp_cmd = &priv->cmdcomp; +			init_completion(priv->comp_cmd); +			priv->cmd = req->data->stop; +			wmt_mci_send_command(priv->mmc, req->data->stop->opcode, +					     7, req->data->stop->arg, 9); +			wmt_mci_start_command(priv); +		} +	} +} + +static irqreturn_t wmt_mci_dma_isr(int irq_num, void *data) +{ +	struct mmc_host *mmc; +	struct wmt_mci_priv *priv; + +	int status; + +	priv = (struct wmt_mci_priv *)data; +	mmc = priv->mmc; + +	status = readl(priv->sdmmc_base + SDDMA_CCR) & 0x0F; + +	if (status != DMA_CCR_EVT_SUCCESS) { +		dev_err(priv->dev, "DMA Error: Status = %d\n", status); +		priv->req->data->error = -ETIMEDOUT; +		complete(priv->comp_dma); +		return IRQ_HANDLED; +	} + +	priv->req->data->error = 0; + +	wmt_mci_disable_dma(priv); + +	complete(priv->comp_dma); + +	if (priv->comp_cmd) { +		if (completion_done(priv->comp_cmd)) { +			/* +			 * if the command (regular) interrupt has already +			 * completed, finish off the request otherwise we wait +			 * for the command interrupt and finish from there. +			 */ +			wmt_complete_data_request(priv); +		} +	} + +	return IRQ_HANDLED; +} + +static irqreturn_t wmt_mci_regular_isr(int irq_num, void *data) +{ +	struct wmt_mci_priv *priv; +	u32 status0; +	u32 status1; +	u32 status2; +	u32 reg_tmp; +	int cmd_done; + +	priv = (struct wmt_mci_priv *)data; +	cmd_done = 0; +	status0 = readb(priv->sdmmc_base + SDMMC_STS0); +	status1 = readb(priv->sdmmc_base + SDMMC_STS1); +	status2 = readb(priv->sdmmc_base + SDMMC_STS2); + +	/* Check for card insertion */ +	reg_tmp = readb(priv->sdmmc_base + SDMMC_INTMASK0); +	if ((reg_tmp & INT0_DI_INT_EN) && (status0 & STS0_DEVICE_INS)) { +		mmc_detect_change(priv->mmc, 0); +		if (priv->cmd) +			priv->cmd->error = -ETIMEDOUT; +		if (priv->comp_cmd) +			complete(priv->comp_cmd); +		if (priv->comp_dma) { +			wmt_mci_disable_dma(priv); +			complete(priv->comp_dma); +		} +		writeb(STS0_DEVICE_INS, priv->sdmmc_base + SDMMC_STS0); +		return IRQ_HANDLED; +	} + +	if ((!priv->req->data) || +	    ((priv->req->data->stop) && (priv->cmd == priv->req->data->stop))) { +		/* handle non-data & stop_transmission requests */ +		if (status1 & STS1_CMDRSP_DONE) { +			priv->cmd->error = 0; +			cmd_done = 1; +		} else if ((status1 & STS1_RSP_TIMEOUT) || +			   (status1 & STS1_DATA_TIMEOUT)) { +			priv->cmd->error = -ETIMEDOUT; +			cmd_done = 1; +		} + +		if (cmd_done) { +			priv->comp_cmd = NULL; + +			if (!priv->cmd->error) +				wmt_mci_read_response(priv->mmc); + +			priv->cmd = NULL; + +			mmc_request_done(priv->mmc, priv->req); +		} +	} else { +		/* handle data requests */ +		if (status1 & STS1_CMDRSP_DONE) { +			if (priv->cmd) +				priv->cmd->error = 0; +			if (priv->comp_cmd) +				complete(priv->comp_cmd); +		} + +		if ((status1 & STS1_RSP_TIMEOUT) || +		    (status1 & STS1_DATA_TIMEOUT)) { +			if (priv->cmd) +				priv->cmd->error = -ETIMEDOUT; +			if (priv->comp_cmd) +				complete(priv->comp_cmd); +			if (priv->comp_dma) { +				wmt_mci_disable_dma(priv); +				complete(priv->comp_dma); +			} +		} + +		if (priv->comp_dma) { +			/* +			 * If the dma interrupt has already completed, finish +			 * off the request; otherwise we wait for the DMA +			 * interrupt and finish from there. +			 */ +			if (completion_done(priv->comp_dma)) +				wmt_complete_data_request(priv); +		} +	} + +	writeb(status0, priv->sdmmc_base + SDMMC_STS0); +	writeb(status1, priv->sdmmc_base + SDMMC_STS1); +	writeb(status2, priv->sdmmc_base + SDMMC_STS2); + +	return IRQ_HANDLED; +} + +static void wmt_reset_hardware(struct mmc_host *mmc) +{ +	struct wmt_mci_priv *priv; +	u32 reg_tmp; + +	priv = mmc_priv(mmc); + +	/* reset controller */ +	reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); +	writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + SDMMC_BUSMODE); + +	/* reset response FIFO */ +	reg_tmp = readb(priv->sdmmc_base + SDMMC_CTLR); +	writeb(reg_tmp | CTLR_FIFO_RESET, priv->sdmmc_base + SDMMC_CTLR); + +	/* enable GPI pin to detect card */ +	writew(BLKL_INT_ENABLE | BLKL_GPI_CD, priv->sdmmc_base + SDMMC_BLKLEN); + +	/* clear interrupt status */ +	writeb(0xFF, priv->sdmmc_base + SDMMC_STS0); +	writeb(0xFF, priv->sdmmc_base + SDMMC_STS1); + +	/* setup interrupts */ +	writeb(INT0_CD_INT_EN | INT0_DI_INT_EN, priv->sdmmc_base + +	       SDMMC_INTMASK0); +	writeb(INT1_DATA_TOUT_INT_EN | INT1_CMD_RES_TRAN_DONE_INT_EN | +	       INT1_CMD_RES_TOUT_INT_EN, priv->sdmmc_base + SDMMC_INTMASK1); + +	/* set the DMA timeout */ +	writew(8191, priv->sdmmc_base + SDMMC_DMATIMEOUT); + +	/* auto clock freezing enable */ +	reg_tmp = readb(priv->sdmmc_base + SDMMC_STS2); +	writeb(reg_tmp | STS2_DIS_FORCECLK, priv->sdmmc_base + SDMMC_STS2); + +	/* set a default clock speed of 400Khz */ +	clk_set_rate(priv->clk_sdmmc, 400000); +} + +static int wmt_dma_init(struct mmc_host *mmc) +{ +	struct wmt_mci_priv *priv; + +	priv = mmc_priv(mmc); + +	writel(DMA_GCR_SOFT_RESET, priv->sdmmc_base + SDDMA_GCR); +	writel(DMA_GCR_DMA_EN, priv->sdmmc_base + SDDMA_GCR); +	if ((readl(priv->sdmmc_base + SDDMA_GCR) & DMA_GCR_DMA_EN) != 0) +		return 0; +	else +		return 1; +} + +static void wmt_dma_init_descriptor(struct wmt_dma_descriptor *desc, +		u16 req_count, u32 buffer_addr, u32 branch_addr, int end) +{ +	desc->flags = 0x40000000 | req_count; +	if (end) +		desc->flags |= 0x80000000; +	desc->data_buffer_addr = buffer_addr; +	desc->branch_addr = branch_addr; +} + +static void wmt_dma_config(struct mmc_host *mmc, u32 descaddr, u8 dir) +{ +	struct wmt_mci_priv *priv; +	u32 reg_tmp; + +	priv = mmc_priv(mmc); + +	/* Enable DMA Interrupts */ +	writel(DMA_IER_INT_EN, priv->sdmmc_base + SDDMA_IER); + +	/* Write DMA Descriptor Pointer Register */ +	writel(descaddr, priv->sdmmc_base + SDDMA_DESPR); + +	writel(0x00, priv->sdmmc_base + SDDMA_CCR); + +	if (dir == PDMA_WRITE) { +		reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR); +		writel(reg_tmp & DMA_CCR_IF_TO_PERIPHERAL, priv->sdmmc_base + +		       SDDMA_CCR); +	} else { +		reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR); +		writel(reg_tmp | DMA_CCR_PERIPHERAL_TO_IF, priv->sdmmc_base + +		       SDDMA_CCR); +	} +} + +static void wmt_dma_start(struct wmt_mci_priv *priv) +{ +	u32 reg_tmp; + +	reg_tmp = readl(priv->sdmmc_base + SDDMA_CCR); +	writel(reg_tmp | DMA_CCR_RUN, priv->sdmmc_base + SDDMA_CCR); +} + +static void wmt_mci_request(struct mmc_host *mmc, struct mmc_request *req) +{ +	struct wmt_mci_priv *priv; +	struct wmt_dma_descriptor *desc; +	u8 command; +	u8 cmdtype; +	u32 arg; +	u8 rsptype; +	u32 reg_tmp; + +	struct scatterlist *sg; +	int i; +	int sg_cnt; +	int offset; +	u32 dma_address; +	int desc_cnt; + +	priv = mmc_priv(mmc); +	priv->req = req; + +	/* +	 * Use the cmd variable to pass a pointer to the resp[] structure +	 * This is required on multi-block requests to pass the pointer to the +	 * stop command +	 */ +	priv->cmd = req->cmd; + +	command = req->cmd->opcode; +	arg = req->cmd->arg; +	rsptype = mmc_resp_type(req->cmd); +	cmdtype = 0; + +	/* rsptype=7 only valid for SPI commands - should be =2 for SD */ +	if (rsptype == 7) +		rsptype = 2; +	/* rsptype=21 is R1B, convert for controller */ +	if (rsptype == 21) +		rsptype = 9; + +	if (!req->data) { +		wmt_mci_send_command(mmc, command, cmdtype, arg, rsptype); +		wmt_mci_start_command(priv); +		/* completion is now handled in the regular_isr() */ +	} +	if (req->data) { +		priv->comp_cmd = &priv->cmdcomp; +		init_completion(priv->comp_cmd); + +		wmt_dma_init(mmc); + +		/* set controller data length */ +		reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN); +		writew((reg_tmp & 0xF800) | (req->data->blksz - 1), +		       priv->sdmmc_base + SDMMC_BLKLEN); + +		/* set controller block count */ +		writew(req->data->blocks, priv->sdmmc_base + SDMMC_BLKCNT); + +		desc = (struct wmt_dma_descriptor *)priv->dma_desc_buffer; + +		if (req->data->flags & MMC_DATA_WRITE) { +			sg_cnt = dma_map_sg(mmc_dev(mmc), req->data->sg, +					    req->data->sg_len, DMA_TO_DEVICE); +			cmdtype = 1; +			if (req->data->blocks > 1) +				cmdtype = 3; +		} else { +			sg_cnt = dma_map_sg(mmc_dev(mmc), req->data->sg, +					    req->data->sg_len, DMA_FROM_DEVICE); +			cmdtype = 2; +			if (req->data->blocks > 1) +				cmdtype = 4; +		} + +		dma_address = priv->dma_desc_device_addr + 16; +		desc_cnt = 0; + +		for_each_sg(req->data->sg, sg, sg_cnt, i) { +			offset = 0; +			while (offset < sg_dma_len(sg)) { +				wmt_dma_init_descriptor(desc, req->data->blksz, +						sg_dma_address(sg)+offset, +						dma_address, 0); +				desc++; +				desc_cnt++; +				offset += req->data->blksz; +				dma_address += 16; +				if (desc_cnt == req->data->blocks) +					break; +			} +		} +		desc--; +		desc->flags |= 0x80000000; + +		if (req->data->flags & MMC_DATA_WRITE) +			wmt_dma_config(mmc, priv->dma_desc_device_addr, +				       PDMA_WRITE); +		else +			wmt_dma_config(mmc, priv->dma_desc_device_addr, +				       PDMA_READ); + +		wmt_mci_send_command(mmc, command, cmdtype, arg, rsptype); + +		priv->comp_dma = &priv->datacomp; +		init_completion(priv->comp_dma); + +		wmt_dma_start(priv); +		wmt_mci_start_command(priv); +	} +} + +static void wmt_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ +	struct wmt_mci_priv *priv; +	u32 reg_tmp; + +	priv = mmc_priv(mmc); + +	if (ios->power_mode == MMC_POWER_UP) { +		wmt_reset_hardware(mmc); + +		wmt_set_sd_power(priv, WMT_SD_POWER_ON); +	} +	if (ios->power_mode == MMC_POWER_OFF) +		wmt_set_sd_power(priv, WMT_SD_POWER_OFF); + +	if (ios->clock != 0) +		clk_set_rate(priv->clk_sdmmc, ios->clock); + +	switch (ios->bus_width) { +	case MMC_BUS_WIDTH_8: +		reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL); +		writeb(reg_tmp | 0x04, priv->sdmmc_base + SDMMC_EXTCTRL); +		break; +	case MMC_BUS_WIDTH_4: +		reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); +		writeb(reg_tmp | BM_FOURBIT_MODE, priv->sdmmc_base + +		       SDMMC_BUSMODE); + +		reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL); +		writeb(reg_tmp & 0xFB, priv->sdmmc_base + SDMMC_EXTCTRL); +		break; +	case MMC_BUS_WIDTH_1: +		reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); +		writeb(reg_tmp & BM_ONEBIT_MASK, priv->sdmmc_base + +		       SDMMC_BUSMODE); + +		reg_tmp = readb(priv->sdmmc_base + SDMMC_EXTCTRL); +		writeb(reg_tmp & 0xFB, priv->sdmmc_base + SDMMC_EXTCTRL); +		break; +	} +} + +static int wmt_mci_get_ro(struct mmc_host *mmc) +{ +	struct wmt_mci_priv *priv = mmc_priv(mmc); + +	return !(readb(priv->sdmmc_base + SDMMC_STS0) & STS0_WRITE_PROTECT); +} + +static int wmt_mci_get_cd(struct mmc_host *mmc) +{ +	struct wmt_mci_priv *priv = mmc_priv(mmc); +	u32 cd = (readb(priv->sdmmc_base + SDMMC_STS0) & STS0_CD_GPI) >> 3; + +	return !(cd ^ priv->cd_inverted); +} + +static struct mmc_host_ops wmt_mci_ops = { +	.request = wmt_mci_request, +	.set_ios = wmt_mci_set_ios, +	.get_ro = wmt_mci_get_ro, +	.get_cd = wmt_mci_get_cd, +}; + +/* Controller capabilities */ +static struct wmt_mci_caps wm8505_caps = { +	.f_min = 390425, +	.f_max = 50000000, +	.ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34, +	.caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED | +		MMC_CAP_SD_HIGHSPEED, +	.max_seg_size = 65024, +	.max_segs = 128, +	.max_blk_size = 2048, +}; + +static struct of_device_id wmt_mci_dt_ids[] = { +	{ .compatible = "wm,wm8505-sdhc", .data = &wm8505_caps }, +	{ /* Sentinel */ }, +}; + +static int __devinit wmt_mci_probe(struct platform_device *pdev) +{ +	struct mmc_host *mmc; +	struct wmt_mci_priv *priv; +	struct device_node *np = pdev->dev.of_node; +	const struct of_device_id *of_id = +		of_match_device(wmt_mci_dt_ids, &pdev->dev); +	const struct wmt_mci_caps *wmt_caps = of_id->data; +	int ret; +	int regular_irq, dma_irq; + +	if (!of_id || !of_id->data) { +		dev_err(&pdev->dev, "Controller capabilities data missing\n"); +		return -EFAULT; +	} + +	if (!np) { +		dev_err(&pdev->dev, "Missing SDMMC description in devicetree\n"); +		return -EFAULT; +	} + +	regular_irq = irq_of_parse_and_map(np, 0); +	dma_irq = irq_of_parse_and_map(np, 1); + +	if (!regular_irq || !dma_irq) { +		dev_err(&pdev->dev, "Getting IRQs failed!\n"); +		ret = -ENXIO; +		goto fail1; +	} + +	mmc = mmc_alloc_host(sizeof(struct wmt_mci_priv), &pdev->dev); +	if (!mmc) { +		dev_err(&pdev->dev, "Failed to allocate mmc_host\n"); +		ret = -ENOMEM; +		goto fail1; +	} + +	mmc->ops = &wmt_mci_ops; +	mmc->f_min = wmt_caps->f_min; +	mmc->f_max = wmt_caps->f_max; +	mmc->ocr_avail = wmt_caps->ocr_avail; +	mmc->caps = wmt_caps->caps; + +	mmc->max_seg_size = wmt_caps->max_seg_size; +	mmc->max_segs = wmt_caps->max_segs; +	mmc->max_blk_size = wmt_caps->max_blk_size; + +	mmc->max_req_size = (16*512*mmc->max_segs); +	mmc->max_blk_count = mmc->max_req_size / 512; + +	priv = mmc_priv(mmc); +	priv->mmc = mmc; +	priv->dev = &pdev->dev; + +	priv->power_inverted = 0; +	priv->cd_inverted = 0; + +	if (of_get_property(np, "sdon-inverted", NULL)) +		priv->power_inverted = 1; +	if (of_get_property(np, "cd-inverted", NULL)) +		priv->cd_inverted = 1; + +	priv->sdmmc_base = of_iomap(np, 0); +	if (!priv->sdmmc_base) { +		dev_err(&pdev->dev, "Failed to map IO space\n"); +		ret = -ENOMEM; +		goto fail2; +	} + +	priv->irq_regular = regular_irq; +	priv->irq_dma = dma_irq; + +	ret = request_irq(regular_irq, wmt_mci_regular_isr, 0, "sdmmc", priv); +	if (ret) { +		dev_err(&pdev->dev, "Register regular IRQ fail\n"); +		goto fail3; +	} + +	ret = request_irq(dma_irq, wmt_mci_dma_isr, 32, "sdmmc", priv); +	if (ret) { +		dev_err(&pdev->dev, "Register DMA IRQ fail\n"); +		goto fail4; +	} + +	/* alloc some DMA buffers for descriptors/transfers */ +	priv->dma_desc_buffer = dma_alloc_coherent(&pdev->dev, +						   mmc->max_blk_count * 16, +						   &priv->dma_desc_device_addr, +						   208); +	if (!priv->dma_desc_buffer) { +		dev_err(&pdev->dev, "DMA alloc fail\n"); +		ret = -EPERM; +		goto fail5; +	} + +	platform_set_drvdata(pdev, mmc); + +	priv->clk_sdmmc = of_clk_get(np, 0); +	if (IS_ERR(priv->clk_sdmmc)) { +		dev_err(&pdev->dev, "Error getting clock\n"); +		ret = PTR_ERR(priv->clk_sdmmc); +		goto fail5; +	} + +	clk_prepare_enable(priv->clk_sdmmc); + +	/* configure the controller to a known 'ready' state */ +	wmt_reset_hardware(mmc); + +	mmc_add_host(mmc); + +	dev_info(&pdev->dev, "WMT SDHC Controller initialized\n"); + +	return 0; +fail5: +	free_irq(dma_irq, priv); +fail4: +	free_irq(regular_irq, priv); +fail3: +	iounmap(priv->sdmmc_base); +fail2: +	mmc_free_host(mmc); +fail1: +	return ret; +} + +static int __devexit wmt_mci_remove(struct platform_device *pdev) +{ +	struct mmc_host *mmc; +	struct wmt_mci_priv *priv; +	struct resource *res; +	u32 reg_tmp; + +	mmc = platform_get_drvdata(pdev); +	priv = mmc_priv(mmc); + +	/* reset SD controller */ +	reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); +	writel(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + SDMMC_BUSMODE); +	reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN); +	writew(reg_tmp & ~(0xA000), priv->sdmmc_base + SDMMC_BLKLEN); +	writeb(0xFF, priv->sdmmc_base + SDMMC_STS0); +	writeb(0xFF, priv->sdmmc_base + SDMMC_STS1); + +	/* release the dma buffers */ +	dma_free_coherent(&pdev->dev, priv->mmc->max_blk_count * 16, +			  priv->dma_desc_buffer, priv->dma_desc_device_addr); + +	mmc_remove_host(mmc); + +	free_irq(priv->irq_regular, priv); +	free_irq(priv->irq_dma, priv); + +	iounmap(priv->sdmmc_base); + +	clk_disable_unprepare(priv->clk_sdmmc); +	clk_put(priv->clk_sdmmc); + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	release_mem_region(res->start, res->end - res->start + 1); + +	mmc_free_host(mmc); + +	platform_set_drvdata(pdev, NULL); + +	dev_info(&pdev->dev, "WMT MCI device removed\n"); + +	return 0; +} + +#ifdef CONFIG_PM +static int wmt_mci_suspend(struct device *dev) +{ +	u32 reg_tmp; +	struct platform_device *pdev = to_platform_device(dev); +	struct mmc_host *mmc = platform_get_drvdata(pdev); +	struct wmt_mci_priv *priv; +	int ret; + +	if (!mmc) +		return 0; + +	priv = mmc_priv(mmc); +	ret = mmc_suspend_host(mmc); + +	if (!ret) { +		reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); +		writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + +		       SDMMC_BUSMODE); + +		reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN); +		writew(reg_tmp & 0x5FFF, priv->sdmmc_base + SDMMC_BLKLEN); + +		writeb(0xFF, priv->sdmmc_base + SDMMC_STS0); +		writeb(0xFF, priv->sdmmc_base + SDMMC_STS1); + +		clk_disable(priv->clk_sdmmc); +	} +	return ret; +} + +static int wmt_mci_resume(struct device *dev) +{ +	u32 reg_tmp; +	struct platform_device *pdev = to_platform_device(dev); +	struct mmc_host *mmc = platform_get_drvdata(pdev); +	struct wmt_mci_priv *priv; +	int ret = 0; + +	if (mmc) { +		priv = mmc_priv(mmc); +		clk_enable(priv->clk_sdmmc); + +		reg_tmp = readb(priv->sdmmc_base + SDMMC_BUSMODE); +		writeb(reg_tmp | BM_SOFT_RESET, priv->sdmmc_base + +		       SDMMC_BUSMODE); + +		reg_tmp = readw(priv->sdmmc_base + SDMMC_BLKLEN); +		writew(reg_tmp | (BLKL_GPI_CD | BLKL_INT_ENABLE), +		       priv->sdmmc_base + SDMMC_BLKLEN); + +		reg_tmp = readb(priv->sdmmc_base + SDMMC_INTMASK0); +		writeb(reg_tmp | INT0_DI_INT_EN, priv->sdmmc_base + +		       SDMMC_INTMASK0); + +		ret = mmc_resume_host(mmc); +	} + +	return ret; +} + +static const struct dev_pm_ops wmt_mci_pm = { +	.suspend        = wmt_mci_suspend, +	.resume         = wmt_mci_resume, +}; + +#define wmt_mci_pm_ops (&wmt_mci_pm) + +#else	/* !CONFIG_PM */ + +#define wmt_mci_pm_ops NULL + +#endif + +static struct platform_driver wmt_mci_driver = { +	.probe = wmt_mci_probe, +	.remove = __exit_p(wmt_mci_remove), +	.driver = { +		.name = DRIVER_NAME, +		.owner = THIS_MODULE, +		.pm = wmt_mci_pm_ops, +		.of_match_table = wmt_mci_dt_ids, +	}, +}; + +module_platform_driver(wmt_mci_driver); + +MODULE_DESCRIPTION("Wondermedia MMC/SD Driver"); +MODULE_AUTHOR("Tony Prisk"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, wmt_mci_dt_ids);  |