Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (83 commits) mmc: fix compile error when CONFIG_BLOCK is not enabled mmc: core: Cleanup eMMC4.5 conditionals mmc: omap_hsmmc: if multiblock reads are broken, disable them mmc: core: add workaround for controllers with broken multiblock reads mmc: core: Prevent too long response times for suspend mmc: recognise SDIO cards with SDIO_CCCR_REV 3.00 mmc: sd: Handle SD3.0 cards not supporting UHS-I bus speed mode mmc: core: support HPI send command mmc: core: Add cache control for eMMC4.5 device mmc: core: Modify the timeout value for writing power class mmc: core: new discard feature support at eMMC v4.5 mmc: core: mmc sanitize feature support for v4.5 mmc: dw_mmc: modify DATA register offset mmc: sdhci-pci: add flag for devices that can support runtime PM mmc: omap_hsmmc: ensure pbias configuration is always done mmc: core: Add Power Off Notify Feature eMMC 4.5 mmc: sdhci-s3c: fix potential NULL dereference mmc: replace printk with appropriate display macro mmc: core: Add default timeout value for CMD6 mmc: sdhci-pci: add runtime pm support ...
This commit is contained in:
		
				commit
				
					
						46b51ea209
					
				
			
		
					 81 changed files with 3151 additions and 1067 deletions
				
			
		
							
								
								
									
										27
									
								
								Documentation/devicetree/bindings/mmc/nvidia-sdhci.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								Documentation/devicetree/bindings/mmc/nvidia-sdhci.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | |||
| * NVIDIA Tegra Secure Digital Host Controller | ||||
| 
 | ||||
| This controller on Tegra family SoCs provides an interface for MMC, SD, | ||||
| and SDIO types of memory cards. | ||||
| 
 | ||||
| Required properties: | ||||
| - compatible : Should be "nvidia,<chip>-sdhci" | ||||
| - reg : Should contain SD/MMC registers location and length | ||||
| - interrupts : Should contain SD/MMC interrupt | ||||
| 
 | ||||
| Optional properties: | ||||
| - cd-gpios : Specify GPIOs for card detection | ||||
| - wp-gpios : Specify GPIOs for write protection | ||||
| - power-gpios : Specify GPIOs for power control | ||||
| - support-8bit : Boolean, indicates if 8-bit mode should be used. | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
| sdhci@c8000200 { | ||||
| 	compatible = "nvidia,tegra20-sdhci"; | ||||
| 	reg = <0xc8000200 0x200>; | ||||
| 	interrupts = <47>; | ||||
| 	cd-gpios = <&gpio 69 0>; /* gpio PI5 */ | ||||
| 	wp-gpios = <&gpio 57 0>; /* gpio PH1 */ | ||||
| 	power-gpios = <&gpio 155 0>; /* gpio PT3 */ | ||||
| 	support-8bit; | ||||
| }; | ||||
|  | @ -21,6 +21,11 @@ o fail_make_request | |||
|   /sys/block/<device>/make-it-fail or | ||||
|   /sys/block/<device>/<partition>/make-it-fail. (generic_make_request()) | ||||
| 
 | ||||
| o fail_mmc_request | ||||
| 
 | ||||
|   injects MMC data errors on devices permitted by setting | ||||
|   debugfs entries under /sys/kernel/debug/mmc0/fail_mmc_request | ||||
| 
 | ||||
| Configure fault-injection capabilities behavior | ||||
| ----------------------------------------------- | ||||
| 
 | ||||
|  | @ -115,7 +120,8 @@ use the boot option: | |||
| 
 | ||||
| 	failslab= | ||||
| 	fail_page_alloc= | ||||
| 	fail_make_request=<interval>,<probability>,<space>,<times> | ||||
| 	fail_make_request= | ||||
| 	mmc_core.fail_request=<interval>,<probability>,<space>,<times> | ||||
| 
 | ||||
| How to add new fault injection capability | ||||
| ----------------------------------------- | ||||
|  |  | |||
|  | @ -319,7 +319,7 @@ void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) | |||
| 	if (!data) | ||||
| 		return; | ||||
| 
 | ||||
| 	for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) { | ||||
| 	for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { | ||||
| 		if (data->slot[i].bus_width) { | ||||
| 			/* input/irq */ | ||||
| 			if (data->slot[i].detect_pin) { | ||||
|  |  | |||
|  | @ -175,12 +175,6 @@ static struct resource resources_sdc1[] = { | |||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 		.name	= "cmd_irq", | ||||
| 	}, | ||||
| 	{ | ||||
| 		.start	= INT_SDC1_1, | ||||
| 		.end	= INT_SDC1_1, | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 		.name	= "pio_irq", | ||||
| 	}, | ||||
| 	{ | ||||
| 		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED, | ||||
| 		.name	= "status_irq" | ||||
|  | @ -203,12 +197,6 @@ static struct resource resources_sdc2[] = { | |||
| 		.end	= INT_SDC2_0, | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 		.name	= "cmd_irq", | ||||
| 	}, | ||||
| 		{ | ||||
| 		.start	= INT_SDC2_1, | ||||
| 		.end	= INT_SDC2_1, | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 		.name	= "pio_irq", | ||||
| 	}, | ||||
| 	{ | ||||
| 		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED, | ||||
|  | @ -232,12 +220,6 @@ static struct resource resources_sdc3[] = { | |||
| 		.end	= INT_SDC3_0, | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 		.name	= "cmd_irq", | ||||
| 	}, | ||||
| 		{ | ||||
| 		.start	= INT_SDC3_1, | ||||
| 		.end	= INT_SDC3_1, | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 		.name	= "pio_irq", | ||||
| 	}, | ||||
| 	{ | ||||
| 		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED, | ||||
|  | @ -261,12 +243,6 @@ static struct resource resources_sdc4[] = { | |||
| 		.end	= INT_SDC4_0, | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 		.name	= "cmd_irq", | ||||
| 	}, | ||||
| 		{ | ||||
| 		.start	= INT_SDC4_1, | ||||
| 		.end	= INT_SDC4_1, | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 		.name	= "pio_irq", | ||||
| 	}, | ||||
| 	{ | ||||
| 		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED, | ||||
|  |  | |||
|  | @ -139,12 +139,6 @@ static struct resource resources_sdc1[] = { | |||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 		.name	= "cmd_irq", | ||||
| 	}, | ||||
| 	{ | ||||
| 		.start	= INT_SDC1_1, | ||||
| 		.end	= INT_SDC1_1, | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 		.name	= "pio_irq", | ||||
| 	}, | ||||
| 	{ | ||||
| 		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED, | ||||
| 		.name	= "status_irq" | ||||
|  | @ -167,12 +161,6 @@ static struct resource resources_sdc2[] = { | |||
| 		.end	= INT_SDC2_0, | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 		.name	= "cmd_irq", | ||||
| 	}, | ||||
| 		{ | ||||
| 		.start	= INT_SDC2_1, | ||||
| 		.end	= INT_SDC2_1, | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 		.name	= "pio_irq", | ||||
| 	}, | ||||
| 	{ | ||||
| 		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED, | ||||
|  | @ -196,12 +184,6 @@ static struct resource resources_sdc3[] = { | |||
| 		.end	= INT_SDC3_0, | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 		.name	= "cmd_irq", | ||||
| 	}, | ||||
| 		{ | ||||
| 		.start	= INT_SDC3_1, | ||||
| 		.end	= INT_SDC3_1, | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 		.name	= "pio_irq", | ||||
| 	}, | ||||
| 	{ | ||||
| 		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED, | ||||
|  | @ -225,12 +207,6 @@ static struct resource resources_sdc4[] = { | |||
| 		.end	= INT_SDC4_0, | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 		.name	= "cmd_irq", | ||||
| 	}, | ||||
| 		{ | ||||
| 		.start	= INT_SDC4_1, | ||||
| 		.end	= INT_SDC4_1, | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 		.name	= "pio_irq", | ||||
| 	}, | ||||
| 	{ | ||||
| 		.flags	= IORESOURCE_IRQ | IORESOURCE_DISABLED, | ||||
|  |  | |||
|  | @ -8,13 +8,6 @@ | |||
| #include <linux/mmc/card.h> | ||||
| #include <linux/mmc/sdio_func.h> | ||||
| 
 | ||||
| struct embedded_sdio_data { | ||||
| 	struct sdio_cis cis; | ||||
| 	struct sdio_cccr cccr; | ||||
| 	struct sdio_embedded_func *funcs; | ||||
| 	int num_funcs; | ||||
| }; | ||||
| 
 | ||||
| struct msm_mmc_gpio { | ||||
| 	unsigned no; | ||||
| 	const char *name; | ||||
|  | @ -29,9 +22,9 @@ struct msm_mmc_platform_data { | |||
| 	unsigned int ocr_mask;			/* available voltages */ | ||||
| 	u32 (*translate_vdd)(struct device *, unsigned int); | ||||
| 	unsigned int (*status)(struct device *); | ||||
| 	struct embedded_sdio_data *embedded_sdio; | ||||
| 	int (*register_status_notify)(void (*callback)(int card_present, void *dev_id), void *dev_id); | ||||
| 	struct msm_mmc_gpio_data *gpio_data; | ||||
| 	void (*init_card)(struct mmc_card *card); | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -355,14 +355,17 @@ static struct resource sdhi0_resources[] = { | |||
| 		.flags	= IORESOURCE_MEM, | ||||
| 	}, | ||||
| 	[1] = { | ||||
| 		.name	= SH_MOBILE_SDHI_IRQ_CARD_DETECT, | ||||
| 		.start	= gic_spi(83), | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 	}, | ||||
| 	[2] = { | ||||
| 		.name	= SH_MOBILE_SDHI_IRQ_SDCARD, | ||||
| 		.start	= gic_spi(84), | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 	}, | ||||
| 	[3] = { | ||||
| 		.name	= SH_MOBILE_SDHI_IRQ_SDIO, | ||||
| 		.start	= gic_spi(85), | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 	}, | ||||
|  | @ -398,14 +401,17 @@ static struct resource sdhi1_resources[] = { | |||
| 		.flags	= IORESOURCE_MEM, | ||||
| 	}, | ||||
| 	[1] = { | ||||
| 		.name	= SH_MOBILE_SDHI_IRQ_CARD_DETECT, | ||||
| 		.start	= gic_spi(87), | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 	}, | ||||
| 	[2] = { | ||||
| 		.name	= SH_MOBILE_SDHI_IRQ_SDCARD, | ||||
| 		.start	= gic_spi(88), | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 	}, | ||||
| 	[3] = { | ||||
| 		.name	= SH_MOBILE_SDHI_IRQ_SDIO, | ||||
| 		.start	= gic_spi(89), | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 	}, | ||||
|  |  | |||
|  | @ -1072,14 +1072,17 @@ static struct resource sdhi1_resources[] = { | |||
| 		.flags	= IORESOURCE_MEM, | ||||
| 	}, | ||||
| 	[1] = { | ||||
| 		.name	= SH_MOBILE_SDHI_IRQ_CARD_DETECT, | ||||
| 		.start	= evt2irq(0x0e80), /* SDHI1_SDHI1I0 */ | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 	}, | ||||
| 	[2] = { | ||||
| 		.name	= SH_MOBILE_SDHI_IRQ_SDCARD, | ||||
| 		.start	= evt2irq(0x0ea0), /* SDHI1_SDHI1I1 */ | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 	}, | ||||
| 	[3] = { | ||||
| 		.name	= SH_MOBILE_SDHI_IRQ_SDIO, | ||||
| 		.start	= evt2irq(0x0ec0), /* SDHI1_SDHI1I2 */ | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 	}, | ||||
|  | @ -1123,14 +1126,17 @@ static struct resource sdhi2_resources[] = { | |||
| 		.flags	= IORESOURCE_MEM, | ||||
| 	}, | ||||
| 	[1] = { | ||||
| 		.name	= SH_MOBILE_SDHI_IRQ_CARD_DETECT, | ||||
| 		.start	= evt2irq(0x1200), /* SDHI2_SDHI2I0 */ | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 	}, | ||||
| 	[2] = { | ||||
| 		.name	= SH_MOBILE_SDHI_IRQ_SDCARD, | ||||
| 		.start	= evt2irq(0x1220), /* SDHI2_SDHI2I1 */ | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 	}, | ||||
| 	[3] = { | ||||
| 		.name	= SH_MOBILE_SDHI_IRQ_SDIO, | ||||
| 		.start	= evt2irq(0x1240), /* SDHI2_SDHI2I2 */ | ||||
| 		.flags	= IORESOURCE_IRQ, | ||||
| 	}, | ||||
|  |  | |||
|  | @ -31,7 +31,24 @@ | |||
| 
 | ||||
| #define OMAP_MMC_MAX_SLOTS	2 | ||||
| 
 | ||||
| #define OMAP_HSMMC_SUPPORTS_DUAL_VOLT	BIT(1) | ||||
| /*
 | ||||
|  * struct omap_mmc_dev_attr.flags possibilities | ||||
|  * | ||||
|  * OMAP_HSMMC_SUPPORTS_DUAL_VOLT: Some HSMMC controller instances can | ||||
|  *    operate with either 1.8Vdc or 3.0Vdc card voltages; this flag | ||||
|  *    should be set if this is the case.  See for example Section 22.5.3 | ||||
|  *    "MMC/SD/SDIO1 Bus Voltage Selection" of the OMAP34xx Multimedia | ||||
|  *    Device Silicon Revision 3.1.x Revision ZR (July 2011) (SWPU223R). | ||||
|  * | ||||
|  * OMAP_HSMMC_BROKEN_MULTIBLOCK_READ: Multiple-block read transfers | ||||
|  *    don't work correctly on some MMC controller instances on some | ||||
|  *    OMAP3 SoCs; this flag should be set if this is the case.  See | ||||
|  *    for example Advisory 2.1.1.128 "MMC: Multiple Block Read | ||||
|  *    Operation Issue" in _OMAP3530/3525/3515/3503 Silicon Errata_ | ||||
|  *    Revision F (October 2010) (SPRZ278F). | ||||
|  */ | ||||
| #define OMAP_HSMMC_SUPPORTS_DUAL_VOLT		BIT(0) | ||||
| #define OMAP_HSMMC_BROKEN_MULTIBLOCK_READ	BIT(1) | ||||
| 
 | ||||
| struct omap_mmc_dev_attr { | ||||
| 	u8 flags; | ||||
|  |  | |||
|  | @ -94,6 +94,11 @@ struct mmc_blk_data { | |||
| 	unsigned int	read_only; | ||||
| 	unsigned int	part_type; | ||||
| 	unsigned int	name_idx; | ||||
| 	unsigned int	reset_done; | ||||
| #define MMC_BLK_READ		BIT(0) | ||||
| #define MMC_BLK_WRITE		BIT(1) | ||||
| #define MMC_BLK_DISCARD		BIT(2) | ||||
| #define MMC_BLK_SECDISCARD	BIT(3) | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Only set in main mmc_blk_data associated | ||||
|  | @ -109,11 +114,11 @@ static DEFINE_MUTEX(open_lock); | |||
| enum mmc_blk_status { | ||||
| 	MMC_BLK_SUCCESS = 0, | ||||
| 	MMC_BLK_PARTIAL, | ||||
| 	MMC_BLK_RETRY, | ||||
| 	MMC_BLK_RETRY_SINGLE, | ||||
| 	MMC_BLK_DATA_ERR, | ||||
| 	MMC_BLK_CMD_ERR, | ||||
| 	MMC_BLK_RETRY, | ||||
| 	MMC_BLK_ABORT, | ||||
| 	MMC_BLK_DATA_ERR, | ||||
| 	MMC_BLK_ECC_ERR, | ||||
| }; | ||||
| 
 | ||||
| module_param(perdev_minors, int, 0444); | ||||
|  | @ -291,7 +296,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, | |||
| 	struct mmc_card *card; | ||||
| 	struct mmc_command cmd = {0}; | ||||
| 	struct mmc_data data = {0}; | ||||
| 	struct mmc_request mrq = {0}; | ||||
| 	struct mmc_request mrq = {NULL}; | ||||
| 	struct scatterlist sg; | ||||
| 	int err; | ||||
| 
 | ||||
|  | @ -442,19 +447,24 @@ static inline int mmc_blk_part_switch(struct mmc_card *card, | |||
| { | ||||
| 	int ret; | ||||
| 	struct mmc_blk_data *main_md = mmc_get_drvdata(card); | ||||
| 
 | ||||
| 	if (main_md->part_curr == md->part_type) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (mmc_card_mmc(card)) { | ||||
| 		card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK; | ||||
| 		card->ext_csd.part_config |= md->part_type; | ||||
| 		u8 part_config = card->ext_csd.part_config; | ||||
| 
 | ||||
| 		part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK; | ||||
| 		part_config |= md->part_type; | ||||
| 
 | ||||
| 		ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||||
| 				 EXT_CSD_PART_CONFIG, card->ext_csd.part_config, | ||||
| 				 EXT_CSD_PART_CONFIG, part_config, | ||||
| 				 card->ext_csd.part_time); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| } | ||||
| 
 | ||||
| 		card->ext_csd.part_config = part_config; | ||||
| 	} | ||||
| 
 | ||||
| 	main_md->part_curr = md->part_type; | ||||
| 	return 0; | ||||
|  | @ -466,7 +476,7 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card) | |||
| 	u32 result; | ||||
| 	__be32 *blocks; | ||||
| 
 | ||||
| 	struct mmc_request mrq = {0}; | ||||
| 	struct mmc_request mrq = {NULL}; | ||||
| 	struct mmc_command cmd = {0}; | ||||
| 	struct mmc_data data = {0}; | ||||
| 	unsigned int timeout_us; | ||||
|  | @ -616,7 +626,7 @@ static int mmc_blk_cmd_error(struct request *req, const char *name, int error, | |||
|  * Otherwise we don't understand what happened, so abort. | ||||
|  */ | ||||
| static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, | ||||
| 	struct mmc_blk_request *brq) | ||||
| 	struct mmc_blk_request *brq, int *ecc_err) | ||||
| { | ||||
| 	bool prev_cmd_status_valid = true; | ||||
| 	u32 status, stop_status = 0; | ||||
|  | @ -641,6 +651,12 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, | |||
| 	if (err) | ||||
| 		return ERR_ABORT; | ||||
| 
 | ||||
| 	/* Flag ECC errors */ | ||||
| 	if ((status & R1_CARD_ECC_FAILED) || | ||||
| 	    (brq->stop.resp[0] & R1_CARD_ECC_FAILED) || | ||||
| 	    (brq->cmd.resp[0] & R1_CARD_ECC_FAILED)) | ||||
| 		*ecc_err = 1; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Check the current card state.  If it is in some data transfer | ||||
| 	 * mode, tell it to stop (and hopefully transition back to TRAN.) | ||||
|  | @ -658,6 +674,8 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, | |||
| 		 */ | ||||
| 		if (err) | ||||
| 			return ERR_ABORT; | ||||
| 		if (stop_status & R1_CARD_ECC_FAILED) | ||||
| 			*ecc_err = 1; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Check for set block count errors */ | ||||
|  | @ -670,6 +688,10 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, | |||
| 		return mmc_blk_cmd_error(req, "r/w cmd", brq->cmd.error, | ||||
| 				prev_cmd_status_valid, status); | ||||
| 
 | ||||
| 	/* Data errors */ | ||||
| 	if (!brq->stop.error) | ||||
| 		return ERR_CONTINUE; | ||||
| 
 | ||||
| 	/* Now for stop errors.  These aren't fatal to the transfer. */ | ||||
| 	pr_err("%s: error %d sending stop command, original cmd response %#x, card status %#x\n", | ||||
| 	       req->rq_disk->disk_name, brq->stop.error, | ||||
|  | @ -686,12 +708,45 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, | |||
| 	return ERR_CONTINUE; | ||||
| } | ||||
| 
 | ||||
| static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host, | ||||
| 			 int type) | ||||
| { | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (md->reset_done & type) | ||||
| 		return -EEXIST; | ||||
| 
 | ||||
| 	md->reset_done |= type; | ||||
| 	err = mmc_hw_reset(host); | ||||
| 	/* Ensure we switch back to the correct partition */ | ||||
| 	if (err != -EOPNOTSUPP) { | ||||
| 		struct mmc_blk_data *main_md = mmc_get_drvdata(host->card); | ||||
| 		int part_err; | ||||
| 
 | ||||
| 		main_md->part_curr = main_md->part_type; | ||||
| 		part_err = mmc_blk_part_switch(host->card, md); | ||||
| 		if (part_err) { | ||||
| 			/*
 | ||||
| 			 * We have failed to get back into the correct | ||||
| 			 * partition, so we need to abort the whole request. | ||||
| 			 */ | ||||
| 			return -ENODEV; | ||||
| 		} | ||||
| 	} | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static inline void mmc_blk_reset_success(struct mmc_blk_data *md, int type) | ||||
| { | ||||
| 	md->reset_done &= ~type; | ||||
| } | ||||
| 
 | ||||
| static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) | ||||
| { | ||||
| 	struct mmc_blk_data *md = mq->data; | ||||
| 	struct mmc_card *card = md->queue.card; | ||||
| 	unsigned int from, nr, arg; | ||||
| 	int err = 0; | ||||
| 	int err = 0, type = MMC_BLK_DISCARD; | ||||
| 
 | ||||
| 	if (!mmc_can_erase(card)) { | ||||
| 		err = -EOPNOTSUPP; | ||||
|  | @ -701,11 +756,13 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) | |||
| 	from = blk_rq_pos(req); | ||||
| 	nr = blk_rq_sectors(req); | ||||
| 
 | ||||
| 	if (mmc_can_trim(card)) | ||||
| 	if (mmc_can_discard(card)) | ||||
| 		arg = MMC_DISCARD_ARG; | ||||
| 	else if (mmc_can_trim(card)) | ||||
| 		arg = MMC_TRIM_ARG; | ||||
| 	else | ||||
| 		arg = MMC_ERASE_ARG; | ||||
| 
 | ||||
| retry: | ||||
| 	if (card->quirks & MMC_QUIRK_INAND_CMD38) { | ||||
| 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||||
| 				 INAND_CMD38_ARG_EXT_CSD, | ||||
|  | @ -718,6 +775,10 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) | |||
| 	} | ||||
| 	err = mmc_erase(card, from, nr, arg); | ||||
| out: | ||||
| 	if (err == -EIO && !mmc_blk_reset(md, card->host, type)) | ||||
| 		goto retry; | ||||
| 	if (!err) | ||||
| 		mmc_blk_reset_success(md, type); | ||||
| 	spin_lock_irq(&md->lock); | ||||
| 	__blk_end_request(req, err, blk_rq_bytes(req)); | ||||
| 	spin_unlock_irq(&md->lock); | ||||
|  | @ -731,13 +792,20 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, | |||
| 	struct mmc_blk_data *md = mq->data; | ||||
| 	struct mmc_card *card = md->queue.card; | ||||
| 	unsigned int from, nr, arg; | ||||
| 	int err = 0; | ||||
| 	int err = 0, type = MMC_BLK_SECDISCARD; | ||||
| 
 | ||||
| 	if (!mmc_can_secure_erase_trim(card)) { | ||||
| 	if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) { | ||||
| 		err = -EOPNOTSUPP; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	/* The sanitize operation is supported at v4.5 only */ | ||||
| 	if (mmc_can_sanitize(card)) { | ||||
| 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||||
| 				EXT_CSD_SANITIZE_START, 1, 0); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	from = blk_rq_pos(req); | ||||
| 	nr = blk_rq_sectors(req); | ||||
| 
 | ||||
|  | @ -745,7 +813,7 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, | |||
| 		arg = MMC_SECURE_TRIM1_ARG; | ||||
| 	else | ||||
| 		arg = MMC_SECURE_ERASE_ARG; | ||||
| 
 | ||||
| retry: | ||||
| 	if (card->quirks & MMC_QUIRK_INAND_CMD38) { | ||||
| 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||||
| 				 INAND_CMD38_ARG_EXT_CSD, | ||||
|  | @ -769,6 +837,10 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, | |||
| 		err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG); | ||||
| 	} | ||||
| out: | ||||
| 	if (err == -EIO && !mmc_blk_reset(md, card->host, type)) | ||||
| 		goto retry; | ||||
| 	if (!err) | ||||
| 		mmc_blk_reset_success(md, type); | ||||
| 	spin_lock_irq(&md->lock); | ||||
| 	__blk_end_request(req, err, blk_rq_bytes(req)); | ||||
| 	spin_unlock_irq(&md->lock); | ||||
|  | @ -779,16 +851,18 @@ out: | |||
| static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req) | ||||
| { | ||||
| 	struct mmc_blk_data *md = mq->data; | ||||
| 	struct mmc_card *card = md->queue.card; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	ret = mmc_flush_cache(card); | ||||
| 	if (ret) | ||||
| 		ret = -EIO; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * No-op, only service this because we need REQ_FUA for reliable | ||||
| 	 * writes. | ||||
| 	 */ | ||||
| 	spin_lock_irq(&md->lock); | ||||
| 	__blk_end_request_all(req, 0); | ||||
| 	__blk_end_request_all(req, ret); | ||||
| 	spin_unlock_irq(&md->lock); | ||||
| 
 | ||||
| 	return 1; | ||||
| 	return ret ? 0 : 1; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  | @ -825,11 +899,11 @@ static inline void mmc_apply_rel_rw(struct mmc_blk_request *brq, | |||
| static int mmc_blk_err_check(struct mmc_card *card, | ||||
| 			     struct mmc_async_req *areq) | ||||
| { | ||||
| 	enum mmc_blk_status ret = MMC_BLK_SUCCESS; | ||||
| 	struct mmc_queue_req *mq_mrq = container_of(areq, struct mmc_queue_req, | ||||
| 						    mmc_active); | ||||
| 	struct mmc_blk_request *brq = &mq_mrq->brq; | ||||
| 	struct request *req = mq_mrq->req; | ||||
| 	int ecc_err = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * sbc.error indicates a problem with the set block count | ||||
|  | @ -841,8 +915,9 @@ static int mmc_blk_err_check(struct mmc_card *card, | |||
| 	 * stop.error indicates a problem with the stop command.  Data | ||||
| 	 * may have been transferred, or may still be transferring. | ||||
| 	 */ | ||||
| 	if (brq->sbc.error || brq->cmd.error || brq->stop.error) { | ||||
| 		switch (mmc_blk_cmd_recovery(card, req, brq)) { | ||||
| 	if (brq->sbc.error || brq->cmd.error || brq->stop.error || | ||||
| 	    brq->data.error) { | ||||
| 		switch (mmc_blk_cmd_recovery(card, req, brq, &ecc_err)) { | ||||
| 		case ERR_RETRY: | ||||
| 			return MMC_BLK_RETRY; | ||||
| 		case ERR_ABORT: | ||||
|  | @ -873,7 +948,7 @@ static int mmc_blk_err_check(struct mmc_card *card, | |||
| 		do { | ||||
| 			int err = get_card_status(card, &status, 5); | ||||
| 			if (err) { | ||||
| 				printk(KERN_ERR "%s: error %d requesting status\n", | ||||
| 				pr_err("%s: error %d requesting status\n", | ||||
| 				       req->rq_disk->disk_name, err); | ||||
| 				return MMC_BLK_CMD_ERR; | ||||
| 			} | ||||
|  | @ -894,23 +969,21 @@ static int mmc_blk_err_check(struct mmc_card *card, | |||
| 		       brq->cmd.resp[0], brq->stop.resp[0]); | ||||
| 
 | ||||
| 		if (rq_data_dir(req) == READ) { | ||||
| 			if (brq->data.blocks > 1) { | ||||
| 				/* Redo read one sector at a time */ | ||||
| 				pr_warning("%s: retrying using single block read\n", | ||||
| 					   req->rq_disk->disk_name); | ||||
| 				return MMC_BLK_RETRY_SINGLE; | ||||
| 			} | ||||
| 			if (ecc_err) | ||||
| 				return MMC_BLK_ECC_ERR; | ||||
| 			return MMC_BLK_DATA_ERR; | ||||
| 		} else { | ||||
| 			return MMC_BLK_CMD_ERR; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (ret == MMC_BLK_SUCCESS && | ||||
| 	    blk_rq_bytes(req) != brq->data.bytes_xfered) | ||||
| 		ret = MMC_BLK_PARTIAL; | ||||
| 	if (!brq->data.bytes_xfered) | ||||
| 		return MMC_BLK_RETRY; | ||||
| 
 | ||||
| 	return ret; | ||||
| 	if (blk_rq_bytes(req) != brq->data.bytes_xfered) | ||||
| 		return MMC_BLK_PARTIAL; | ||||
| 
 | ||||
| 	return MMC_BLK_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, | ||||
|  | @ -957,13 +1030,20 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, | |||
| 	if (brq->data.blocks > card->host->max_blk_count) | ||||
| 		brq->data.blocks = card->host->max_blk_count; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * After a read error, we redo the request one sector at a time | ||||
| 	 * in order to accurately determine which sectors can be read | ||||
| 	 * successfully. | ||||
| 	 */ | ||||
| 	if (disable_multi && brq->data.blocks > 1) | ||||
| 		brq->data.blocks = 1; | ||||
| 	if (brq->data.blocks > 1) { | ||||
| 		/*
 | ||||
| 		 * After a read error, we redo the request one sector | ||||
| 		 * at a time in order to accurately determine which | ||||
| 		 * sectors can be read successfully. | ||||
| 		 */ | ||||
| 		if (disable_multi) | ||||
| 			brq->data.blocks = 1; | ||||
| 
 | ||||
| 		/* Some controllers can't do multiblock reads due to hw bugs */ | ||||
| 		if (card->host->caps2 & MMC_CAP2_NO_MULTI_READ && | ||||
| 		    rq_data_dir(req) == READ) | ||||
| 			brq->data.blocks = 1; | ||||
| 	} | ||||
| 
 | ||||
| 	if (brq->data.blocks > 1 || do_rel_wr) { | ||||
| 		/* SPI multiblock writes terminate using a special
 | ||||
|  | @ -1049,12 +1129,41 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq, | |||
| 	mmc_queue_bounce_pre(mqrq); | ||||
| } | ||||
| 
 | ||||
| static int mmc_blk_cmd_err(struct mmc_blk_data *md, struct mmc_card *card, | ||||
| 			   struct mmc_blk_request *brq, struct request *req, | ||||
| 			   int ret) | ||||
| { | ||||
| 	/*
 | ||||
| 	 * If this is an SD card and we're writing, we can first | ||||
| 	 * mark the known good sectors as ok. | ||||
| 	 * | ||||
| 	 * If the card is not SD, we can still ok written sectors | ||||
| 	 * as reported by the controller (which might be less than | ||||
| 	 * the real number of written sectors, but never more). | ||||
| 	 */ | ||||
| 	if (mmc_card_sd(card)) { | ||||
| 		u32 blocks; | ||||
| 
 | ||||
| 		blocks = mmc_sd_num_wr_blocks(card); | ||||
| 		if (blocks != (u32)-1) { | ||||
| 			spin_lock_irq(&md->lock); | ||||
| 			ret = __blk_end_request(req, 0, blocks << 9); | ||||
| 			spin_unlock_irq(&md->lock); | ||||
| 		} | ||||
| 	} else { | ||||
| 		spin_lock_irq(&md->lock); | ||||
| 		ret = __blk_end_request(req, 0, brq->data.bytes_xfered); | ||||
| 		spin_unlock_irq(&md->lock); | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) | ||||
| { | ||||
| 	struct mmc_blk_data *md = mq->data; | ||||
| 	struct mmc_card *card = md->queue.card; | ||||
| 	struct mmc_blk_request *brq = &mq->mqrq_cur->brq; | ||||
| 	int ret = 1, disable_multi = 0, retry = 0; | ||||
| 	int ret = 1, disable_multi = 0, retry = 0, type; | ||||
| 	enum mmc_blk_status status; | ||||
| 	struct mmc_queue_req *mq_rq; | ||||
| 	struct request *req; | ||||
|  | @ -1076,6 +1185,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) | |||
| 		mq_rq = container_of(areq, struct mmc_queue_req, mmc_active); | ||||
| 		brq = &mq_rq->brq; | ||||
| 		req = mq_rq->req; | ||||
| 		type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE; | ||||
| 		mmc_queue_bounce_post(mq_rq); | ||||
| 
 | ||||
| 		switch (status) { | ||||
|  | @ -1084,18 +1194,18 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) | |||
| 			/*
 | ||||
| 			 * A block was successfully transferred. | ||||
| 			 */ | ||||
| 			mmc_blk_reset_success(md, type); | ||||
| 			spin_lock_irq(&md->lock); | ||||
| 			ret = __blk_end_request(req, 0, | ||||
| 						brq->data.bytes_xfered); | ||||
| 			spin_unlock_irq(&md->lock); | ||||
| 			/*
 | ||||
| 			 * If the blk_end_request function returns non-zero even | ||||
| 			 * though all data has been transferred and no errors | ||||
| 			 * were returned by the host controller, it's a bug. | ||||
| 			 */ | ||||
| 			if (status == MMC_BLK_SUCCESS && ret) { | ||||
| 				/*
 | ||||
| 				 * The blk_end_request has returned non zero | ||||
| 				 * even though all data is transfered and no | ||||
| 				 * erros returned by host. | ||||
| 				 * If this happen it's a bug. | ||||
| 				 */ | ||||
| 				printk(KERN_ERR "%s BUG rq_tot %d d_xfer %d\n", | ||||
| 				pr_err("%s BUG rq_tot %d d_xfer %d\n", | ||||
| 				       __func__, blk_rq_bytes(req), | ||||
| 				       brq->data.bytes_xfered); | ||||
| 				rqc = NULL; | ||||
|  | @ -1103,16 +1213,36 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) | |||
| 			} | ||||
| 			break; | ||||
| 		case MMC_BLK_CMD_ERR: | ||||
| 			goto cmd_err; | ||||
| 		case MMC_BLK_RETRY_SINGLE: | ||||
| 			disable_multi = 1; | ||||
| 			break; | ||||
| 			ret = mmc_blk_cmd_err(md, card, brq, req, ret); | ||||
| 			if (!mmc_blk_reset(md, card->host, type)) | ||||
| 				break; | ||||
| 			goto cmd_abort; | ||||
| 		case MMC_BLK_RETRY: | ||||
| 			if (retry++ < 5) | ||||
| 				break; | ||||
| 			/* Fall through */ | ||||
| 		case MMC_BLK_ABORT: | ||||
| 			if (!mmc_blk_reset(md, card->host, type)) | ||||
| 				break; | ||||
| 			goto cmd_abort; | ||||
| 		case MMC_BLK_DATA_ERR: | ||||
| 		case MMC_BLK_DATA_ERR: { | ||||
| 			int err; | ||||
| 
 | ||||
| 			err = mmc_blk_reset(md, card->host, type); | ||||
| 			if (!err) | ||||
| 				break; | ||||
| 			if (err == -ENODEV) | ||||
| 				goto cmd_abort; | ||||
| 			/* Fall through */ | ||||
| 		} | ||||
| 		case MMC_BLK_ECC_ERR: | ||||
| 			if (brq->data.blocks > 1) { | ||||
| 				/* Redo read one sector at a time */ | ||||
| 				pr_warning("%s: retrying using single block read\n", | ||||
| 					   req->rq_disk->disk_name); | ||||
| 				disable_multi = 1; | ||||
| 				break; | ||||
| 			} | ||||
| 			/*
 | ||||
| 			 * After an error, we redo I/O one sector at a | ||||
| 			 * time, so we only reach here after trying to | ||||
|  | @ -1129,7 +1259,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) | |||
| 
 | ||||
| 		if (ret) { | ||||
| 			/*
 | ||||
| 			 * In case of a none complete request | ||||
| 			 * In case of a incomplete request | ||||
| 			 * prepare it again and resend. | ||||
| 			 */ | ||||
| 			mmc_blk_rw_rq_prep(mq_rq, card, disable_multi, mq); | ||||
|  | @ -1139,30 +1269,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) | |||
| 
 | ||||
| 	return 1; | ||||
| 
 | ||||
|  cmd_err: | ||||
|  	/*
 | ||||
|  	 * If this is an SD card and we're writing, we can first | ||||
|  	 * mark the known good sectors as ok. | ||||
|  	 * | ||||
| 	 * If the card is not SD, we can still ok written sectors | ||||
| 	 * as reported by the controller (which might be less than | ||||
| 	 * the real number of written sectors, but never more). | ||||
| 	 */ | ||||
| 	if (mmc_card_sd(card)) { | ||||
| 		u32 blocks; | ||||
| 
 | ||||
| 		blocks = mmc_sd_num_wr_blocks(card); | ||||
| 		if (blocks != (u32)-1) { | ||||
| 			spin_lock_irq(&md->lock); | ||||
| 			ret = __blk_end_request(req, 0, blocks << 9); | ||||
| 			spin_unlock_irq(&md->lock); | ||||
| 		} | ||||
| 	} else { | ||||
| 		spin_lock_irq(&md->lock); | ||||
| 		ret = __blk_end_request(req, 0, brq->data.bytes_xfered); | ||||
| 		spin_unlock_irq(&md->lock); | ||||
| 	} | ||||
| 
 | ||||
|  cmd_abort: | ||||
| 	spin_lock_irq(&md->lock); | ||||
| 	while (ret) | ||||
|  | @ -1190,6 +1296,11 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) | |||
| 
 | ||||
| 	ret = mmc_blk_part_switch(card, md); | ||||
| 	if (ret) { | ||||
| 		if (req) { | ||||
| 			spin_lock_irq(&md->lock); | ||||
| 			__blk_end_request_all(req, -EIO); | ||||
| 			spin_unlock_irq(&md->lock); | ||||
| 		} | ||||
| 		ret = 0; | ||||
| 		goto out; | ||||
| 	} | ||||
|  | @ -1374,32 +1485,35 @@ static int mmc_blk_alloc_part(struct mmc_card *card, | |||
| 
 | ||||
| 	string_get_size((u64)get_capacity(part_md->disk) << 9, STRING_UNITS_2, | ||||
| 			cap_str, sizeof(cap_str)); | ||||
| 	printk(KERN_INFO "%s: %s %s partition %u %s\n", | ||||
| 	pr_info("%s: %s %s partition %u %s\n", | ||||
| 	       part_md->disk->disk_name, mmc_card_id(card), | ||||
| 	       mmc_card_name(card), part_md->part_type, cap_str); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* MMC Physical partitions consist of two boot partitions and
 | ||||
|  * up to four general purpose partitions. | ||||
|  * For each partition enabled in EXT_CSD a block device will be allocatedi | ||||
|  * to provide access to the partition. | ||||
|  */ | ||||
| 
 | ||||
| static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	int idx, ret = 0; | ||||
| 
 | ||||
| 	if (!mmc_card_mmc(card)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (card->ext_csd.boot_size) { | ||||
| 		ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT0, | ||||
| 					 card->ext_csd.boot_size >> 9, | ||||
| 					 true, | ||||
| 					 "boot0"); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 		ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT1, | ||||
| 					 card->ext_csd.boot_size >> 9, | ||||
| 					 true, | ||||
| 					 "boot1"); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 	for (idx = 0; idx < card->nr_parts; idx++) { | ||||
| 		if (card->part[idx].size) { | ||||
| 			ret = mmc_blk_alloc_part(card, md, | ||||
| 				card->part[idx].part_cfg, | ||||
| 				card->part[idx].size >> 9, | ||||
| 				card->part[idx].force_ro, | ||||
| 				card->part[idx].name); | ||||
| 			if (ret) | ||||
| 				return ret; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return ret; | ||||
|  | @ -1415,7 +1529,7 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card) | |||
| 	mmc_release_host(card->host); | ||||
| 
 | ||||
| 	if (err) { | ||||
| 		printk(KERN_ERR "%s: unable to set block size to 512: %d\n", | ||||
| 		pr_err("%s: unable to set block size to 512: %d\n", | ||||
| 			md->disk->disk_name, err); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | @ -1517,7 +1631,7 @@ static int mmc_blk_probe(struct mmc_card *card) | |||
| 
 | ||||
| 	string_get_size((u64)get_capacity(md->disk) << 9, STRING_UNITS_2, | ||||
| 			cap_str, sizeof(cap_str)); | ||||
| 	printk(KERN_INFO "%s: %s %s %s %s\n", | ||||
| 	pr_info("%s: %s %s %s %s\n", | ||||
| 		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), | ||||
| 		cap_str, md->read_only ? "(ro)" : ""); | ||||
| 
 | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ | |||
| #include <linux/debugfs.h> | ||||
| #include <linux/uaccess.h> | ||||
| #include <linux/seq_file.h> | ||||
| #include <linux/module.h> | ||||
| 
 | ||||
| #define RESULT_OK		0 | ||||
| #define RESULT_FAIL		1 | ||||
|  | @ -250,7 +251,7 @@ static int mmc_test_wait_busy(struct mmc_test_card *test) | |||
| 		if (!busy && mmc_test_busy(&cmd)) { | ||||
| 			busy = 1; | ||||
| 			if (test->card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) | ||||
| 				printk(KERN_INFO "%s: Warning: Host did not " | ||||
| 				pr_info("%s: Warning: Host did not " | ||||
| 					"wait for busy state to end.\n", | ||||
| 					mmc_hostname(test->card->host)); | ||||
| 		} | ||||
|  | @ -552,7 +553,7 @@ static void mmc_test_print_rate(struct mmc_test_card *test, uint64_t bytes, | |||
| 	rate = mmc_test_rate(bytes, &ts); | ||||
| 	iops = mmc_test_rate(100, &ts); /* I/O ops per sec x 100 */ | ||||
| 
 | ||||
| 	printk(KERN_INFO "%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu " | ||||
| 	pr_info("%s: Transfer of %u sectors (%u%s KiB) took %lu.%09lu " | ||||
| 			 "seconds (%u kB/s, %u KiB/s, %u.%02u IOPS)\n", | ||||
| 			 mmc_hostname(test->card->host), sectors, sectors >> 1, | ||||
| 			 (sectors & 1 ? ".5" : ""), (unsigned long)ts.tv_sec, | ||||
|  | @ -578,7 +579,7 @@ static void mmc_test_print_avg_rate(struct mmc_test_card *test, uint64_t bytes, | |||
| 	rate = mmc_test_rate(tot, &ts); | ||||
| 	iops = mmc_test_rate(count * 100, &ts); /* I/O ops per sec x 100 */ | ||||
| 
 | ||||
| 	printk(KERN_INFO "%s: Transfer of %u x %u sectors (%u x %u%s KiB) took " | ||||
| 	pr_info("%s: Transfer of %u x %u sectors (%u x %u%s KiB) took " | ||||
| 			 "%lu.%09lu seconds (%u kB/s, %u KiB/s, " | ||||
| 			 "%u.%02u IOPS, sg_len %d)\n", | ||||
| 			 mmc_hostname(test->card->host), count, sectors, count, | ||||
|  | @ -1408,7 +1409,7 @@ static int mmc_test_multi_read_high(struct mmc_test_card *test) | |||
| 
 | ||||
| static int mmc_test_no_highmem(struct mmc_test_card *test) | ||||
| { | ||||
| 	printk(KERN_INFO "%s: Highmem not configured - test skipped\n", | ||||
| 	pr_info("%s: Highmem not configured - test skipped\n", | ||||
| 	       mmc_hostname(test->card->host)); | ||||
| 	return 0; | ||||
| } | ||||
|  | @ -1435,7 +1436,7 @@ static int mmc_test_area_map(struct mmc_test_card *test, unsigned long sz, | |||
| 				      t->max_seg_sz, &t->sg_len, min_sg_len); | ||||
| 	} | ||||
| 	if (err) | ||||
| 		printk(KERN_INFO "%s: Failed to map sg list\n", | ||||
| 		pr_info("%s: Failed to map sg list\n", | ||||
| 		       mmc_hostname(test->card->host)); | ||||
| 	return err; | ||||
| } | ||||
|  | @ -2135,7 +2136,7 @@ static int mmc_test_rw_multiple(struct mmc_test_card *test, | |||
| 
 | ||||
| 	return ret; | ||||
|  err: | ||||
| 	printk(KERN_INFO "[%s] error\n", __func__); | ||||
| 	pr_info("[%s] error\n", __func__); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
|  | @ -2149,7 +2150,7 @@ static int mmc_test_rw_multiple_size(struct mmc_test_card *test, | |||
| 
 | ||||
| 	if (rw->do_nonblock_req && | ||||
| 	    ((!pre_req && post_req) || (pre_req && !post_req))) { | ||||
| 		printk(KERN_INFO "error: only one of pre/post is defined\n"); | ||||
| 		pr_info("error: only one of pre/post is defined\n"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -2328,6 +2329,31 @@ static int mmc_test_profile_sglen_r_nonblock_perf(struct mmc_test_card *test) | |||
| 	return mmc_test_rw_multiple_sg_len(test, &test_data); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * eMMC hardware reset. | ||||
|  */ | ||||
| static int mmc_test_hw_reset(struct mmc_test_card *test) | ||||
| { | ||||
| 	struct mmc_card *card = test->card; | ||||
| 	struct mmc_host *host = card->host; | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = mmc_hw_reset_check(host); | ||||
| 	if (!err) | ||||
| 		return RESULT_OK; | ||||
| 
 | ||||
| 	if (err == -ENOSYS) | ||||
| 		return RESULT_FAIL; | ||||
| 
 | ||||
| 	if (err != -EOPNOTSUPP) | ||||
| 		return err; | ||||
| 
 | ||||
| 	if (!mmc_can_reset(card)) | ||||
| 		return RESULT_UNSUP_CARD; | ||||
| 
 | ||||
| 	return RESULT_UNSUP_HOST; | ||||
| } | ||||
| 
 | ||||
| static const struct mmc_test_case mmc_test_cases[] = { | ||||
| 	{ | ||||
| 		.name = "Basic write (no data verification)", | ||||
|  | @ -2650,6 +2676,11 @@ static const struct mmc_test_case mmc_test_cases[] = { | |||
| 		.run = mmc_test_profile_sglen_r_nonblock_perf, | ||||
| 		.cleanup = mmc_test_area_cleanup, | ||||
| 	}, | ||||
| 
 | ||||
| 	{ | ||||
| 		.name = "eMMC hardware reset", | ||||
| 		.run = mmc_test_hw_reset, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static DEFINE_MUTEX(mmc_test_lock); | ||||
|  | @ -2660,7 +2691,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) | |||
| { | ||||
| 	int i, ret; | ||||
| 
 | ||||
| 	printk(KERN_INFO "%s: Starting tests of card %s...\n", | ||||
| 	pr_info("%s: Starting tests of card %s...\n", | ||||
| 		mmc_hostname(test->card->host), mmc_card_id(test->card)); | ||||
| 
 | ||||
| 	mmc_claim_host(test->card->host); | ||||
|  | @ -2671,14 +2702,14 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) | |||
| 		if (testcase && ((i + 1) != testcase)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		printk(KERN_INFO "%s: Test case %d. %s...\n", | ||||
| 		pr_info("%s: Test case %d. %s...\n", | ||||
| 			mmc_hostname(test->card->host), i + 1, | ||||
| 			mmc_test_cases[i].name); | ||||
| 
 | ||||
| 		if (mmc_test_cases[i].prepare) { | ||||
| 			ret = mmc_test_cases[i].prepare(test); | ||||
| 			if (ret) { | ||||
| 				printk(KERN_INFO "%s: Result: Prepare " | ||||
| 				pr_info("%s: Result: Prepare " | ||||
| 					"stage failed! (%d)\n", | ||||
| 					mmc_hostname(test->card->host), | ||||
| 					ret); | ||||
|  | @ -2708,25 +2739,25 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) | |||
| 		ret = mmc_test_cases[i].run(test); | ||||
| 		switch (ret) { | ||||
| 		case RESULT_OK: | ||||
| 			printk(KERN_INFO "%s: Result: OK\n", | ||||
| 			pr_info("%s: Result: OK\n", | ||||
| 				mmc_hostname(test->card->host)); | ||||
| 			break; | ||||
| 		case RESULT_FAIL: | ||||
| 			printk(KERN_INFO "%s: Result: FAILED\n", | ||||
| 			pr_info("%s: Result: FAILED\n", | ||||
| 				mmc_hostname(test->card->host)); | ||||
| 			break; | ||||
| 		case RESULT_UNSUP_HOST: | ||||
| 			printk(KERN_INFO "%s: Result: UNSUPPORTED " | ||||
| 			pr_info("%s: Result: UNSUPPORTED " | ||||
| 				"(by host)\n", | ||||
| 				mmc_hostname(test->card->host)); | ||||
| 			break; | ||||
| 		case RESULT_UNSUP_CARD: | ||||
| 			printk(KERN_INFO "%s: Result: UNSUPPORTED " | ||||
| 			pr_info("%s: Result: UNSUPPORTED " | ||||
| 				"(by card)\n", | ||||
| 				mmc_hostname(test->card->host)); | ||||
| 			break; | ||||
| 		default: | ||||
| 			printk(KERN_INFO "%s: Result: ERROR (%d)\n", | ||||
| 			pr_info("%s: Result: ERROR (%d)\n", | ||||
| 				mmc_hostname(test->card->host), ret); | ||||
| 		} | ||||
| 
 | ||||
|  | @ -2737,7 +2768,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) | |||
| 		if (mmc_test_cases[i].cleanup) { | ||||
| 			ret = mmc_test_cases[i].cleanup(test); | ||||
| 			if (ret) { | ||||
| 				printk(KERN_INFO "%s: Warning: Cleanup " | ||||
| 				pr_info("%s: Warning: Cleanup " | ||||
| 					"stage failed! (%d)\n", | ||||
| 					mmc_hostname(test->card->host), | ||||
| 					ret); | ||||
|  | @ -2747,7 +2778,7 @@ static void mmc_test_run(struct mmc_test_card *test, int testcase) | |||
| 
 | ||||
| 	mmc_release_host(test->card->host); | ||||
| 
 | ||||
| 	printk(KERN_INFO "%s: Tests completed.\n", | ||||
| 	pr_info("%s: Tests completed.\n", | ||||
| 		mmc_hostname(test->card->host)); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -108,7 +108,7 @@ static void mmc_request(struct request_queue *q) | |||
| 		wake_up_process(mq->thread); | ||||
| } | ||||
| 
 | ||||
| struct scatterlist *mmc_alloc_sg(int sg_len, int *err) | ||||
| static struct scatterlist *mmc_alloc_sg(int sg_len, int *err) | ||||
| { | ||||
| 	struct scatterlist *sg; | ||||
| 
 | ||||
|  | @ -140,7 +140,7 @@ static void mmc_queue_setup_discard(struct request_queue *q, | |||
| 	/* granularity must not be greater than max. discard */ | ||||
| 	if (card->pref_erase > max_discard) | ||||
| 		q->limits.discard_granularity = 0; | ||||
| 	if (mmc_can_secure_erase_trim(card)) | ||||
| 	if (mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card)) | ||||
| 		queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q); | ||||
| } | ||||
| 
 | ||||
|  | @ -197,13 +197,13 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, | |||
| 		if (bouncesz > 512) { | ||||
| 			mqrq_cur->bounce_buf = kmalloc(bouncesz, GFP_KERNEL); | ||||
| 			if (!mqrq_cur->bounce_buf) { | ||||
| 				printk(KERN_WARNING "%s: unable to " | ||||
| 				pr_warning("%s: unable to " | ||||
| 					"allocate bounce cur buffer\n", | ||||
| 					mmc_card_name(card)); | ||||
| 			} | ||||
| 			mqrq_prev->bounce_buf = kmalloc(bouncesz, GFP_KERNEL); | ||||
| 			if (!mqrq_prev->bounce_buf) { | ||||
| 				printk(KERN_WARNING "%s: unable to " | ||||
| 				pr_warning("%s: unable to " | ||||
| 					"allocate bounce prev buffer\n", | ||||
| 					mmc_card_name(card)); | ||||
| 				kfree(mqrq_cur->bounce_buf); | ||||
|  |  | |||
|  | @ -1082,7 +1082,7 @@ static int sdio_uart_probe(struct sdio_func *func, | |||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	if (func->class == SDIO_CLASS_UART) { | ||||
| 		printk(KERN_WARNING "%s: need info on UART class basic setup\n", | ||||
| 		pr_warning("%s: need info on UART class basic setup\n", | ||||
| 		       sdio_func_id(func)); | ||||
| 		kfree(port); | ||||
| 		return -ENOSYS; | ||||
|  | @ -1101,23 +1101,23 @@ static int sdio_uart_probe(struct sdio_func *func, | |||
| 				break; | ||||
| 		} | ||||
| 		if (!tpl) { | ||||
| 			printk(KERN_WARNING | ||||
| 			pr_warning( | ||||
|        "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n", | ||||
| 			       sdio_func_id(func)); | ||||
| 			kfree(port); | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 		printk(KERN_DEBUG "%s: Register ID = 0x%02x, Exp ID = 0x%02x\n", | ||||
| 		pr_debug("%s: Register ID = 0x%02x, Exp ID = 0x%02x\n", | ||||
| 		       sdio_func_id(func), tpl->data[2], tpl->data[3]); | ||||
| 		port->regs_offset = (tpl->data[4] << 0) | | ||||
| 				    (tpl->data[5] << 8) | | ||||
| 				    (tpl->data[6] << 16); | ||||
| 		printk(KERN_DEBUG "%s: regs offset = 0x%x\n", | ||||
| 		pr_debug("%s: regs offset = 0x%x\n", | ||||
| 		       sdio_func_id(func), port->regs_offset); | ||||
| 		port->uartclk = tpl->data[7] * 115200; | ||||
| 		if (port->uartclk == 0) | ||||
| 			port->uartclk = 115200; | ||||
| 		printk(KERN_DEBUG "%s: clk %d baudcode %u 4800-div %u\n", | ||||
| 		pr_debug("%s: clk %d baudcode %u 4800-div %u\n", | ||||
| 		       sdio_func_id(func), port->uartclk, | ||||
| 		       tpl->data[7], tpl->data[8] | (tpl->data[9] << 8)); | ||||
| 	} else { | ||||
|  |  | |||
|  | @ -295,7 +295,7 @@ int mmc_add_card(struct mmc_card *card) | |||
| 	} | ||||
| 
 | ||||
| 	if (mmc_host_is_spi(card->host)) { | ||||
| 		printk(KERN_INFO "%s: new %s%s%s card on SPI\n", | ||||
| 		pr_info("%s: new %s%s%s card on SPI\n", | ||||
| 			mmc_hostname(card->host), | ||||
| 			mmc_card_highspeed(card) ? "high speed " : "", | ||||
| 			mmc_card_ddr_mode(card) ? "DDR " : "", | ||||
|  | @ -334,10 +334,10 @@ void mmc_remove_card(struct mmc_card *card) | |||
| 
 | ||||
| 	if (mmc_card_present(card)) { | ||||
| 		if (mmc_host_is_spi(card->host)) { | ||||
| 			printk(KERN_INFO "%s: SPI card removed\n", | ||||
| 			pr_info("%s: SPI card removed\n", | ||||
| 				mmc_hostname(card->host)); | ||||
| 		} else { | ||||
| 			printk(KERN_INFO "%s: card %04x removed\n", | ||||
| 			pr_info("%s: card %04x removed\n", | ||||
| 				mmc_hostname(card->host), card->rca); | ||||
| 		} | ||||
| 		device_del(&card->dev); | ||||
|  |  | |||
|  | @ -24,6 +24,8 @@ | |||
| #include <linux/regulator/consumer.h> | ||||
| #include <linux/pm_runtime.h> | ||||
| #include <linux/suspend.h> | ||||
| #include <linux/fault-inject.h> | ||||
| #include <linux/random.h> | ||||
| 
 | ||||
| #include <linux/mmc/card.h> | ||||
| #include <linux/mmc/host.h> | ||||
|  | @ -83,6 +85,43 @@ static void mmc_flush_scheduled_work(void) | |||
| 	flush_workqueue(workqueue); | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_FAIL_MMC_REQUEST | ||||
| 
 | ||||
| /*
 | ||||
|  * Internal function. Inject random data errors. | ||||
|  * If mmc_data is NULL no errors are injected. | ||||
|  */ | ||||
| static void mmc_should_fail_request(struct mmc_host *host, | ||||
| 				    struct mmc_request *mrq) | ||||
| { | ||||
| 	struct mmc_command *cmd = mrq->cmd; | ||||
| 	struct mmc_data *data = mrq->data; | ||||
| 	static const int data_errors[] = { | ||||
| 		-ETIMEDOUT, | ||||
| 		-EILSEQ, | ||||
| 		-EIO, | ||||
| 	}; | ||||
| 
 | ||||
| 	if (!data) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (cmd->error || data->error || | ||||
| 	    !should_fail(&host->fail_mmc_request, data->blksz * data->blocks)) | ||||
| 		return; | ||||
| 
 | ||||
| 	data->error = data_errors[random32() % ARRAY_SIZE(data_errors)]; | ||||
| 	data->bytes_xfered = (random32() % (data->bytes_xfered >> 9)) << 9; | ||||
| } | ||||
| 
 | ||||
| #else /* CONFIG_FAIL_MMC_REQUEST */ | ||||
| 
 | ||||
| static inline void mmc_should_fail_request(struct mmc_host *host, | ||||
| 					   struct mmc_request *mrq) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| #endif /* CONFIG_FAIL_MMC_REQUEST */ | ||||
| 
 | ||||
| /**
 | ||||
|  *	mmc_request_done - finish processing an MMC request | ||||
|  *	@host: MMC host which completed request | ||||
|  | @ -102,13 +141,15 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) | |||
| 	} | ||||
| 
 | ||||
| 	if (err && cmd->retries) { | ||||
| 		pr_debug("%s: req failed (CMD%u): %d, retrying...\n", | ||||
| 			mmc_hostname(host), cmd->opcode, err); | ||||
| 
 | ||||
| 		cmd->retries--; | ||||
| 		cmd->error = 0; | ||||
| 		host->ops->request(host, mrq); | ||||
| 		/*
 | ||||
| 		 * Request starter must handle retries - see | ||||
| 		 * mmc_wait_for_req_done(). | ||||
| 		 */ | ||||
| 		if (mrq->done) | ||||
| 			mrq->done(mrq); | ||||
| 	} else { | ||||
| 		mmc_should_fail_request(host, mrq); | ||||
| 
 | ||||
| 		led_trigger_event(host->led, LED_OFF); | ||||
| 
 | ||||
| 		pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n", | ||||
|  | @ -212,7 +253,21 @@ static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) | |||
| static void mmc_wait_for_req_done(struct mmc_host *host, | ||||
| 				  struct mmc_request *mrq) | ||||
| { | ||||
| 	wait_for_completion(&mrq->completion); | ||||
| 	struct mmc_command *cmd; | ||||
| 
 | ||||
| 	while (1) { | ||||
| 		wait_for_completion(&mrq->completion); | ||||
| 
 | ||||
| 		cmd = mrq->cmd; | ||||
| 		if (!cmd->error || !cmd->retries) | ||||
| 			break; | ||||
| 
 | ||||
| 		pr_debug("%s: req failed (CMD%u): %d, retrying...\n", | ||||
| 			 mmc_hostname(host), cmd->opcode, cmd->error); | ||||
| 		cmd->retries--; | ||||
| 		cmd->error = 0; | ||||
| 		host->ops->request(host, mrq); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -279,8 +334,14 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, | |||
| 		mmc_wait_for_req_done(host, host->areq->mrq); | ||||
| 		err = host->areq->err_check(host->card, host->areq); | ||||
| 		if (err) { | ||||
| 			/* post process the completed failed request */ | ||||
| 			mmc_post_req(host, host->areq->mrq, 0); | ||||
| 			if (areq) | ||||
| 				/*
 | ||||
| 				 * Cancel the new prepared request, because | ||||
| 				 * it can't run until the failed | ||||
| 				 * request has been properly handled. | ||||
| 				 */ | ||||
| 				mmc_post_req(host, areq->mrq, -EINVAL); | ||||
| 
 | ||||
| 			host->areq = NULL; | ||||
|  | @ -318,6 +379,63 @@ void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq) | |||
| } | ||||
| EXPORT_SYMBOL(mmc_wait_for_req); | ||||
| 
 | ||||
| /**
 | ||||
|  *	mmc_interrupt_hpi - Issue for High priority Interrupt | ||||
|  *	@card: the MMC card associated with the HPI transfer | ||||
|  * | ||||
|  *	Issued High Priority Interrupt, and check for card status | ||||
|  *	util out-of prg-state. | ||||
|  */ | ||||
| int mmc_interrupt_hpi(struct mmc_card *card) | ||||
| { | ||||
| 	int err; | ||||
| 	u32 status; | ||||
| 
 | ||||
| 	BUG_ON(!card); | ||||
| 
 | ||||
| 	if (!card->ext_csd.hpi_en) { | ||||
| 		pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host)); | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	mmc_claim_host(card->host); | ||||
| 	err = mmc_send_status(card, &status); | ||||
| 	if (err) { | ||||
| 		pr_err("%s: Get card status fail\n", mmc_hostname(card->host)); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If the card status is in PRG-state, we can send the HPI command. | ||||
| 	 */ | ||||
| 	if (R1_CURRENT_STATE(status) == R1_STATE_PRG) { | ||||
| 		do { | ||||
| 			/*
 | ||||
| 			 * We don't know when the HPI command will finish | ||||
| 			 * processing, so we need to resend HPI until out | ||||
| 			 * of prg-state, and keep checking the card status | ||||
| 			 * with SEND_STATUS.  If a timeout error occurs when | ||||
| 			 * sending the HPI command, we are already out of | ||||
| 			 * prg-state. | ||||
| 			 */ | ||||
| 			err = mmc_send_hpi_cmd(card, &status); | ||||
| 			if (err) | ||||
| 				pr_debug("%s: abort HPI (%d error)\n", | ||||
| 					 mmc_hostname(card->host), err); | ||||
| 
 | ||||
| 			err = mmc_send_status(card, &status); | ||||
| 			if (err) | ||||
| 				break; | ||||
| 		} while (R1_CURRENT_STATE(status) == R1_STATE_PRG); | ||||
| 	} else | ||||
| 		pr_debug("%s: Left prg-state\n", mmc_hostname(card->host)); | ||||
| 
 | ||||
| out: | ||||
| 	mmc_release_host(card->host); | ||||
| 	return err; | ||||
| } | ||||
| EXPORT_SYMBOL(mmc_interrupt_hpi); | ||||
| 
 | ||||
| /**
 | ||||
|  *	mmc_wait_for_cmd - start a command and wait for completion | ||||
|  *	@host: MMC host to start command | ||||
|  | @ -330,7 +448,7 @@ EXPORT_SYMBOL(mmc_wait_for_req); | |||
|  */ | ||||
| int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries) | ||||
| { | ||||
| 	struct mmc_request mrq = {0}; | ||||
| 	struct mmc_request mrq = {NULL}; | ||||
| 
 | ||||
| 	WARN_ON(!host->claimed); | ||||
| 
 | ||||
|  | @ -1119,13 +1237,11 @@ static void mmc_power_up(struct mmc_host *host) | |||
| 		bit = fls(host->ocr_avail) - 1; | ||||
| 
 | ||||
| 	host->ios.vdd = bit; | ||||
| 	if (mmc_host_is_spi(host)) { | ||||
| 	if (mmc_host_is_spi(host)) | ||||
| 		host->ios.chip_select = MMC_CS_HIGH; | ||||
| 		host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; | ||||
| 	} else { | ||||
| 	else | ||||
| 		host->ios.chip_select = MMC_CS_DONTCARE; | ||||
| 		host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; | ||||
| 	} | ||||
| 	host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; | ||||
| 	host->ios.power_mode = MMC_POWER_UP; | ||||
| 	host->ios.bus_width = MMC_BUS_WIDTH_1; | ||||
| 	host->ios.timing = MMC_TIMING_LEGACY; | ||||
|  | @ -1151,13 +1267,45 @@ static void mmc_power_up(struct mmc_host *host) | |||
| 	mmc_host_clk_release(host); | ||||
| } | ||||
| 
 | ||||
| static void mmc_power_off(struct mmc_host *host) | ||||
| void mmc_power_off(struct mmc_host *host) | ||||
| { | ||||
| 	struct mmc_card *card; | ||||
| 	unsigned int notify_type; | ||||
| 	unsigned int timeout; | ||||
| 	int err; | ||||
| 
 | ||||
| 	mmc_host_clk_hold(host); | ||||
| 
 | ||||
| 	card = host->card; | ||||
| 	host->ios.clock = 0; | ||||
| 	host->ios.vdd = 0; | ||||
| 
 | ||||
| 	if (card && mmc_card_mmc(card) && | ||||
| 	    (card->poweroff_notify_state == MMC_POWERED_ON)) { | ||||
| 
 | ||||
| 		if (host->power_notify_type == MMC_HOST_PW_NOTIFY_SHORT) { | ||||
| 			notify_type = EXT_CSD_POWER_OFF_SHORT; | ||||
| 			timeout = card->ext_csd.generic_cmd6_time; | ||||
| 			card->poweroff_notify_state = MMC_POWEROFF_SHORT; | ||||
| 		} else { | ||||
| 			notify_type = EXT_CSD_POWER_OFF_LONG; | ||||
| 			timeout = card->ext_csd.power_off_longtime; | ||||
| 			card->poweroff_notify_state = MMC_POWEROFF_LONG; | ||||
| 		} | ||||
| 
 | ||||
| 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||||
| 				 EXT_CSD_POWER_OFF_NOTIFICATION, | ||||
| 				 notify_type, timeout); | ||||
| 
 | ||||
| 		if (err && err != -EBADMSG) | ||||
| 			pr_err("Device failed to respond within %d poweroff " | ||||
| 			       "time. Forcefully powering down the device\n", | ||||
| 			       timeout); | ||||
| 
 | ||||
| 		/* Set the card state to no notification after the poweroff */ | ||||
| 		card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Reset ocr mask to be the highest possible voltage supported for | ||||
| 	 * this mmc host. This value will be used at next power up. | ||||
|  | @ -1173,6 +1321,13 @@ static void mmc_power_off(struct mmc_host *host) | |||
| 	host->ios.timing = MMC_TIMING_LEGACY; | ||||
| 	mmc_set_ios(host); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Some configurations, such as the 802.11 SDIO card in the OLPC | ||||
| 	 * XO-1.5, require a short delay after poweroff before the card | ||||
| 	 * can be successfully turned on again. | ||||
| 	 */ | ||||
| 	mmc_delay(1); | ||||
| 
 | ||||
| 	mmc_host_clk_release(host); | ||||
| } | ||||
| 
 | ||||
|  | @ -1241,8 +1396,7 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops) | |||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Remove the current bus handler from a host. Assumes that there are | ||||
|  * no interesting cards left, so the bus is powered down. | ||||
|  * Remove the current bus handler from a host. | ||||
|  */ | ||||
| void mmc_detach_bus(struct mmc_host *host) | ||||
| { | ||||
|  | @ -1259,8 +1413,6 @@ void mmc_detach_bus(struct mmc_host *host) | |||
| 
 | ||||
| 	spin_unlock_irqrestore(&host->lock, flags); | ||||
| 
 | ||||
| 	mmc_power_off(host); | ||||
| 
 | ||||
| 	mmc_bus_put(host); | ||||
| } | ||||
| 
 | ||||
|  | @ -1478,9 +1630,9 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, | |||
| 	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; | ||||
| 	err = mmc_wait_for_cmd(card->host, &cmd, 0); | ||||
| 	if (err) { | ||||
| 		printk(KERN_ERR "mmc_erase: group start error %d, " | ||||
| 		pr_err("mmc_erase: group start error %d, " | ||||
| 		       "status %#x\n", err, cmd.resp[0]); | ||||
| 		err = -EINVAL; | ||||
| 		err = -EIO; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -1493,9 +1645,9 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, | |||
| 	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; | ||||
| 	err = mmc_wait_for_cmd(card->host, &cmd, 0); | ||||
| 	if (err) { | ||||
| 		printk(KERN_ERR "mmc_erase: group end error %d, status %#x\n", | ||||
| 		pr_err("mmc_erase: group end error %d, status %#x\n", | ||||
| 		       err, cmd.resp[0]); | ||||
| 		err = -EINVAL; | ||||
| 		err = -EIO; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -1506,7 +1658,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, | |||
| 	cmd.cmd_timeout_ms = mmc_erase_timeout(card, arg, qty); | ||||
| 	err = mmc_wait_for_cmd(card->host, &cmd, 0); | ||||
| 	if (err) { | ||||
| 		printk(KERN_ERR "mmc_erase: erase error %d, status %#x\n", | ||||
| 		pr_err("mmc_erase: erase error %d, status %#x\n", | ||||
| 		       err, cmd.resp[0]); | ||||
| 		err = -EIO; | ||||
| 		goto out; | ||||
|  | @ -1523,7 +1675,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, | |||
| 		/* Do not retry else we can't see errors */ | ||||
| 		err = mmc_wait_for_cmd(card->host, &cmd, 0); | ||||
| 		if (err || (cmd.resp[0] & 0xFDF92000)) { | ||||
| 			printk(KERN_ERR "error %d requesting status %#x\n", | ||||
| 			pr_err("error %d requesting status %#x\n", | ||||
| 				err, cmd.resp[0]); | ||||
| 			err = -EIO; | ||||
| 			goto out; | ||||
|  | @ -1614,10 +1766,32 @@ int mmc_can_trim(struct mmc_card *card) | |||
| { | ||||
| 	if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN) | ||||
| 		return 1; | ||||
| 	if (mmc_can_discard(card)) | ||||
| 		return 1; | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL(mmc_can_trim); | ||||
| 
 | ||||
| int mmc_can_discard(struct mmc_card *card) | ||||
| { | ||||
| 	/*
 | ||||
| 	 * As there's no way to detect the discard support bit at v4.5 | ||||
| 	 * use the s/w feature support filed. | ||||
| 	 */ | ||||
| 	if (card->ext_csd.feature_support & MMC_DISCARD_FEATURE) | ||||
| 		return 1; | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL(mmc_can_discard); | ||||
| 
 | ||||
| int mmc_can_sanitize(struct mmc_card *card) | ||||
| { | ||||
| 	if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_SANITIZE) | ||||
| 		return 1; | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL(mmc_can_sanitize); | ||||
| 
 | ||||
| int mmc_can_secure_erase_trim(struct mmc_card *card) | ||||
| { | ||||
| 	if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_ER_EN) | ||||
|  | @ -1727,6 +1901,94 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen) | |||
| } | ||||
| EXPORT_SYMBOL(mmc_set_blocklen); | ||||
| 
 | ||||
| static void mmc_hw_reset_for_init(struct mmc_host *host) | ||||
| { | ||||
| 	if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) | ||||
| 		return; | ||||
| 	mmc_host_clk_hold(host); | ||||
| 	host->ops->hw_reset(host); | ||||
| 	mmc_host_clk_release(host); | ||||
| } | ||||
| 
 | ||||
| int mmc_can_reset(struct mmc_card *card) | ||||
| { | ||||
| 	u8 rst_n_function; | ||||
| 
 | ||||
| 	if (!mmc_card_mmc(card)) | ||||
| 		return 0; | ||||
| 	rst_n_function = card->ext_csd.rst_n_function; | ||||
| 	if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED) | ||||
| 		return 0; | ||||
| 	return 1; | ||||
| } | ||||
| EXPORT_SYMBOL(mmc_can_reset); | ||||
| 
 | ||||
| static int mmc_do_hw_reset(struct mmc_host *host, int check) | ||||
| { | ||||
| 	struct mmc_card *card = host->card; | ||||
| 
 | ||||
| 	if (!host->bus_ops->power_restore) | ||||
| 		return -EOPNOTSUPP; | ||||
| 
 | ||||
| 	if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) | ||||
| 		return -EOPNOTSUPP; | ||||
| 
 | ||||
| 	if (!card) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (!mmc_can_reset(card)) | ||||
| 		return -EOPNOTSUPP; | ||||
| 
 | ||||
| 	mmc_host_clk_hold(host); | ||||
| 	mmc_set_clock(host, host->f_init); | ||||
| 
 | ||||
| 	host->ops->hw_reset(host); | ||||
| 
 | ||||
| 	/* If the reset has happened, then a status command will fail */ | ||||
| 	if (check) { | ||||
| 		struct mmc_command cmd = {0}; | ||||
| 		int err; | ||||
| 
 | ||||
| 		cmd.opcode = MMC_SEND_STATUS; | ||||
| 		if (!mmc_host_is_spi(card->host)) | ||||
| 			cmd.arg = card->rca << 16; | ||||
| 		cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC; | ||||
| 		err = mmc_wait_for_cmd(card->host, &cmd, 0); | ||||
| 		if (!err) { | ||||
| 			mmc_host_clk_release(host); | ||||
| 			return -ENOSYS; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR); | ||||
| 	if (mmc_host_is_spi(host)) { | ||||
| 		host->ios.chip_select = MMC_CS_HIGH; | ||||
| 		host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; | ||||
| 	} else { | ||||
| 		host->ios.chip_select = MMC_CS_DONTCARE; | ||||
| 		host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; | ||||
| 	} | ||||
| 	host->ios.bus_width = MMC_BUS_WIDTH_1; | ||||
| 	host->ios.timing = MMC_TIMING_LEGACY; | ||||
| 	mmc_set_ios(host); | ||||
| 
 | ||||
| 	mmc_host_clk_release(host); | ||||
| 
 | ||||
| 	return host->bus_ops->power_restore(host); | ||||
| } | ||||
| 
 | ||||
| int mmc_hw_reset(struct mmc_host *host) | ||||
| { | ||||
| 	return mmc_do_hw_reset(host, 0); | ||||
| } | ||||
| EXPORT_SYMBOL(mmc_hw_reset); | ||||
| 
 | ||||
| int mmc_hw_reset_check(struct mmc_host *host) | ||||
| { | ||||
| 	return mmc_do_hw_reset(host, 1); | ||||
| } | ||||
| EXPORT_SYMBOL(mmc_hw_reset_check); | ||||
| 
 | ||||
| static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) | ||||
| { | ||||
| 	host->f_init = freq; | ||||
|  | @ -1737,6 +1999,12 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) | |||
| #endif | ||||
| 	mmc_power_up(host); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Some eMMCs (with VCCQ always on) may not be reset after power up, so | ||||
| 	 * do a hardware reset if possible. | ||||
| 	 */ | ||||
| 	mmc_hw_reset_for_init(host); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * sdio_reset sends CMD52 to reset card.  Since we do not know | ||||
| 	 * if the card is being re-initialized, just send it.  CMD52 | ||||
|  | @ -1845,6 +2113,7 @@ void mmc_stop_host(struct mmc_host *host) | |||
| 
 | ||||
| 		mmc_claim_host(host); | ||||
| 		mmc_detach_bus(host); | ||||
| 		mmc_power_off(host); | ||||
| 		mmc_release_host(host); | ||||
| 		mmc_bus_put(host); | ||||
| 		return; | ||||
|  | @ -1946,6 +2215,65 @@ int mmc_card_can_sleep(struct mmc_host *host) | |||
| } | ||||
| EXPORT_SYMBOL(mmc_card_can_sleep); | ||||
| 
 | ||||
| /*
 | ||||
|  * Flush the cache to the non-volatile storage. | ||||
|  */ | ||||
| int mmc_flush_cache(struct mmc_card *card) | ||||
| { | ||||
| 	struct mmc_host *host = card->host; | ||||
| 	int err = 0; | ||||
| 
 | ||||
| 	if (!(host->caps2 & MMC_CAP2_CACHE_CTRL)) | ||||
| 		return err; | ||||
| 
 | ||||
| 	if (mmc_card_mmc(card) && | ||||
| 			(card->ext_csd.cache_size > 0) && | ||||
| 			(card->ext_csd.cache_ctrl & 1)) { | ||||
| 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||||
| 				EXT_CSD_FLUSH_CACHE, 1, 0); | ||||
| 		if (err) | ||||
| 			pr_err("%s: cache flush error %d\n", | ||||
| 					mmc_hostname(card->host), err); | ||||
| 	} | ||||
| 
 | ||||
| 	return err; | ||||
| } | ||||
| EXPORT_SYMBOL(mmc_flush_cache); | ||||
| 
 | ||||
| /*
 | ||||
|  * Turn the cache ON/OFF. | ||||
|  * Turning the cache OFF shall trigger flushing of the data | ||||
|  * to the non-volatile storage. | ||||
|  */ | ||||
| int mmc_cache_ctrl(struct mmc_host *host, u8 enable) | ||||
| { | ||||
| 	struct mmc_card *card = host->card; | ||||
| 	int err = 0; | ||||
| 
 | ||||
| 	if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) || | ||||
| 			mmc_card_is_removable(host)) | ||||
| 		return err; | ||||
| 
 | ||||
| 	if (card && mmc_card_mmc(card) && | ||||
| 			(card->ext_csd.cache_size > 0)) { | ||||
| 		enable = !!enable; | ||||
| 
 | ||||
| 		if (card->ext_csd.cache_ctrl ^ enable) | ||||
| 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||||
| 					EXT_CSD_CACHE_CTRL, enable, 0); | ||||
| 		if (err) | ||||
| 			pr_err("%s: cache %s error %d\n", | ||||
| 					mmc_hostname(card->host), | ||||
| 					enable ? "on" : "off", | ||||
| 					err); | ||||
| 		else | ||||
| 			card->ext_csd.cache_ctrl = enable; | ||||
| 	} | ||||
| 
 | ||||
| 	return err; | ||||
| } | ||||
| EXPORT_SYMBOL(mmc_cache_ctrl); | ||||
| 
 | ||||
| #ifdef CONFIG_PM | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -1960,23 +2288,39 @@ int mmc_suspend_host(struct mmc_host *host) | |||
| 		cancel_delayed_work(&host->disable); | ||||
| 	cancel_delayed_work(&host->detect); | ||||
| 	mmc_flush_scheduled_work(); | ||||
| 	err = mmc_cache_ctrl(host, 0); | ||||
| 	if (err) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	mmc_bus_get(host); | ||||
| 	if (host->bus_ops && !host->bus_dead) { | ||||
| 		if (host->bus_ops->suspend) | ||||
| 			err = host->bus_ops->suspend(host); | ||||
| 		if (err == -ENOSYS || !host->bus_ops->resume) { | ||||
| 			/*
 | ||||
| 			 * We simply "remove" the card in this case. | ||||
| 			 * It will be redetected on resume. | ||||
| 			 */ | ||||
| 			if (host->bus_ops->remove) | ||||
| 				host->bus_ops->remove(host); | ||||
| 			mmc_claim_host(host); | ||||
| 			mmc_detach_bus(host); | ||||
| 			mmc_release_host(host); | ||||
| 			host->pm_flags = 0; | ||||
| 			err = 0; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * A long response time is not acceptable for device drivers | ||||
| 		 * when doing suspend. Prevent mmc_claim_host in the suspend | ||||
| 		 * sequence, to potentially wait "forever" by trying to | ||||
| 		 * pre-claim the host. | ||||
| 		 */ | ||||
| 		if (mmc_try_claim_host(host)) { | ||||
| 			if (host->bus_ops->suspend) | ||||
| 				err = host->bus_ops->suspend(host); | ||||
| 			if (err == -ENOSYS || !host->bus_ops->resume) { | ||||
| 				/*
 | ||||
| 				 * We simply "remove" the card in this case. | ||||
| 				 * It will be redetected on resume. | ||||
| 				 */ | ||||
| 				if (host->bus_ops->remove) | ||||
| 					host->bus_ops->remove(host); | ||||
| 				mmc_claim_host(host); | ||||
| 				mmc_detach_bus(host); | ||||
| 				mmc_power_off(host); | ||||
| 				mmc_release_host(host); | ||||
| 				host->pm_flags = 0; | ||||
| 				err = 0; | ||||
| 			} | ||||
| 			mmc_do_release_host(host); | ||||
| 		} else { | ||||
| 			err = -EBUSY; | ||||
| 		} | ||||
| 	} | ||||
| 	mmc_bus_put(host); | ||||
|  | @ -1984,6 +2328,7 @@ int mmc_suspend_host(struct mmc_host *host) | |||
| 	if (!err && !mmc_card_keep_power(host)) | ||||
| 		mmc_power_off(host); | ||||
| 
 | ||||
| out: | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
|  | @ -2018,7 +2363,7 @@ int mmc_resume_host(struct mmc_host *host) | |||
| 		BUG_ON(!host->bus_ops->resume); | ||||
| 		err = host->bus_ops->resume(host); | ||||
| 		if (err) { | ||||
| 			printk(KERN_WARNING "%s: error %d during resume " | ||||
| 			pr_warning("%s: error %d during resume " | ||||
| 					    "(card was removed?)\n", | ||||
| 					    mmc_hostname(host), err); | ||||
| 			err = 0; | ||||
|  | @ -2049,6 +2394,7 @@ int mmc_pm_notify(struct notifier_block *notify_block, | |||
| 
 | ||||
| 		spin_lock_irqsave(&host->lock, flags); | ||||
| 		host->rescan_disable = 1; | ||||
| 		host->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT; | ||||
| 		spin_unlock_irqrestore(&host->lock, flags); | ||||
| 		cancel_delayed_work_sync(&host->detect); | ||||
| 
 | ||||
|  | @ -2061,6 +2407,7 @@ int mmc_pm_notify(struct notifier_block *notify_block, | |||
| 			host->bus_ops->remove(host); | ||||
| 
 | ||||
| 		mmc_detach_bus(host); | ||||
| 		mmc_power_off(host); | ||||
| 		mmc_release_host(host); | ||||
| 		host->pm_flags = 0; | ||||
| 		break; | ||||
|  | @ -2071,6 +2418,7 @@ int mmc_pm_notify(struct notifier_block *notify_block, | |||
| 
 | ||||
| 		spin_lock_irqsave(&host->lock, flags); | ||||
| 		host->rescan_disable = 0; | ||||
| 		host->power_notify_type = MMC_HOST_PW_NOTIFY_LONG; | ||||
| 		spin_unlock_irqrestore(&host->lock, flags); | ||||
| 		mmc_detect_change(host, 0); | ||||
| 
 | ||||
|  |  | |||
|  | @ -43,6 +43,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, | |||
| 			   bool cmd11); | ||||
| void mmc_set_timing(struct mmc_host *host, unsigned int timing); | ||||
| void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type); | ||||
| void mmc_power_off(struct mmc_host *host); | ||||
| 
 | ||||
| static inline void mmc_delay(unsigned int ms) | ||||
| { | ||||
|  |  | |||
|  | @ -7,11 +7,13 @@ | |||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  */ | ||||
| #include <linux/moduleparam.h> | ||||
| #include <linux/debugfs.h> | ||||
| #include <linux/fs.h> | ||||
| #include <linux/seq_file.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/stat.h> | ||||
| #include <linux/fault-inject.h> | ||||
| 
 | ||||
| #include <linux/mmc/card.h> | ||||
| #include <linux/mmc/host.h> | ||||
|  | @ -19,6 +21,14 @@ | |||
| #include "core.h" | ||||
| #include "mmc_ops.h" | ||||
| 
 | ||||
| #ifdef CONFIG_FAIL_MMC_REQUEST | ||||
| 
 | ||||
| static DECLARE_FAULT_ATTR(fail_default_attr); | ||||
| static char *fail_request; | ||||
| module_param(fail_request, charp, 0); | ||||
| 
 | ||||
| #endif /* CONFIG_FAIL_MMC_REQUEST */ | ||||
| 
 | ||||
| /* The debugfs functions are optimized away when CONFIG_DEBUG_FS isn't set. */ | ||||
| static int mmc_ios_show(struct seq_file *s, void *data) | ||||
| { | ||||
|  | @ -113,6 +123,15 @@ static int mmc_ios_show(struct seq_file *s, void *data) | |||
| 	case MMC_TIMING_SD_HS: | ||||
| 		str = "sd high-speed"; | ||||
| 		break; | ||||
| 	case MMC_TIMING_UHS_SDR50: | ||||
| 		str = "sd uhs SDR50"; | ||||
| 		break; | ||||
| 	case MMC_TIMING_UHS_SDR104: | ||||
| 		str = "sd uhs SDR104"; | ||||
| 		break; | ||||
| 	case MMC_TIMING_UHS_DDR50: | ||||
| 		str = "sd uhs DDR50"; | ||||
| 		break; | ||||
| 	default: | ||||
| 		str = "invalid"; | ||||
| 		break; | ||||
|  | @ -187,6 +206,15 @@ void mmc_add_host_debugfs(struct mmc_host *host) | |||
| 	if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR), | ||||
| 				root, &host->clk_delay)) | ||||
| 		goto err_node; | ||||
| #endif | ||||
| #ifdef CONFIG_FAIL_MMC_REQUEST | ||||
| 	if (fail_request) | ||||
| 		setup_fault_attr(&fail_default_attr, fail_request); | ||||
| 	host->fail_mmc_request = fail_default_attr; | ||||
| 	if (IS_ERR(fault_create_debugfs_attr("fail_mmc_request", | ||||
| 					     root, | ||||
| 					     &host->fail_mmc_request))) | ||||
| 		goto err_node; | ||||
| #endif | ||||
| 	return; | ||||
| 
 | ||||
|  |  | |||
|  | @ -301,6 +301,17 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) | |||
| 	host->max_blk_size = 512; | ||||
| 	host->max_blk_count = PAGE_CACHE_SIZE / 512; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Enable runtime power management by default. This flag was added due | ||||
| 	 * to runtime power management causing disruption for some users, but | ||||
| 	 * the power on/off code has been improved since then. | ||||
| 	 * | ||||
| 	 * We'll enable this flag by default as an experiment, and if no | ||||
| 	 * problems are reported, we will follow up later and remove the flag | ||||
| 	 * altogether. | ||||
| 	 */ | ||||
| 	host->caps = MMC_CAP_POWER_OFF_CARD; | ||||
| 
 | ||||
| 	return host; | ||||
| 
 | ||||
| free: | ||||
|  |  | |||
|  | @ -101,7 +101,7 @@ static int mmc_decode_cid(struct mmc_card *card) | |||
| 		break; | ||||
| 
 | ||||
| 	default: | ||||
| 		printk(KERN_ERR "%s: card has unknown MMCA version %d\n", | ||||
| 		pr_err("%s: card has unknown MMCA version %d\n", | ||||
| 			mmc_hostname(card->host), card->csd.mmca_vsn); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | @ -135,7 +135,7 @@ static int mmc_decode_csd(struct mmc_card *card) | |||
| 	 */ | ||||
| 	csd->structure = UNSTUFF_BITS(resp, 126, 2); | ||||
| 	if (csd->structure == 0) { | ||||
| 		printk(KERN_ERR "%s: unrecognised CSD structure version %d\n", | ||||
| 		pr_err("%s: unrecognised CSD structure version %d\n", | ||||
| 			mmc_hostname(card->host), csd->structure); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | @ -195,7 +195,7 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) | |||
| 	 */ | ||||
| 	ext_csd = kmalloc(512, GFP_KERNEL); | ||||
| 	if (!ext_csd) { | ||||
| 		printk(KERN_ERR "%s: could not allocate a buffer to " | ||||
| 		pr_err("%s: could not allocate a buffer to " | ||||
| 			"receive the ext_csd.\n", mmc_hostname(card->host)); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
|  | @ -217,12 +217,12 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) | |||
| 		 * stored in their CSD. | ||||
| 		 */ | ||||
| 		if (card->csd.capacity == (4096 * 512)) { | ||||
| 			printk(KERN_ERR "%s: unable to read EXT_CSD " | ||||
| 			pr_err("%s: unable to read EXT_CSD " | ||||
| 				"on a possible high capacity card. " | ||||
| 				"Card will be ignored.\n", | ||||
| 				mmc_hostname(card->host)); | ||||
| 		} else { | ||||
| 			printk(KERN_WARNING "%s: unable to read " | ||||
| 			pr_warning("%s: unable to read " | ||||
| 				"EXT_CSD, performance might " | ||||
| 				"suffer.\n", | ||||
| 				mmc_hostname(card->host)); | ||||
|  | @ -239,7 +239,9 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd) | |||
|  */ | ||||
| static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) | ||||
| { | ||||
| 	int err = 0; | ||||
| 	int err = 0, idx; | ||||
| 	unsigned int part_size; | ||||
| 	u8 hc_erase_grp_sz = 0, hc_wp_grp_sz = 0; | ||||
| 
 | ||||
| 	BUG_ON(!card); | ||||
| 
 | ||||
|  | @ -250,7 +252,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) | |||
| 	card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE]; | ||||
| 	if (card->csd.structure == 3) { | ||||
| 		if (card->ext_csd.raw_ext_csd_structure > 2) { | ||||
| 			printk(KERN_ERR "%s: unrecognised EXT_CSD structure " | ||||
| 			pr_err("%s: unrecognised EXT_CSD structure " | ||||
| 				"version %d\n", mmc_hostname(card->host), | ||||
| 					card->ext_csd.raw_ext_csd_structure); | ||||
| 			err = -EINVAL; | ||||
|  | @ -260,7 +262,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) | |||
| 
 | ||||
| 	card->ext_csd.rev = ext_csd[EXT_CSD_REV]; | ||||
| 	if (card->ext_csd.rev > 6) { | ||||
| 		printk(KERN_ERR "%s: unrecognised EXT_CSD revision %d\n", | ||||
| 		pr_err("%s: unrecognised EXT_CSD revision %d\n", | ||||
| 			mmc_hostname(card->host), card->ext_csd.rev); | ||||
| 		err = -EINVAL; | ||||
| 		goto out; | ||||
|  | @ -306,7 +308,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) | |||
| 		break; | ||||
| 	default: | ||||
| 		/* MMC v4 spec says this cannot happen */ | ||||
| 		printk(KERN_WARNING "%s: card is mmc v4 but doesn't " | ||||
| 		pr_warning("%s: card is mmc v4 but doesn't " | ||||
| 			"support any high-speed modes.\n", | ||||
| 			mmc_hostname(card->host)); | ||||
| 	} | ||||
|  | @ -340,7 +342,14 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) | |||
| 		 * There are two boot regions of equal size, defined in | ||||
| 		 * multiples of 128K. | ||||
| 		 */ | ||||
| 		card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; | ||||
| 		if (ext_csd[EXT_CSD_BOOT_MULT] && mmc_boot_partition_access(card->host)) { | ||||
| 			for (idx = 0; idx < MMC_NUM_BOOT_PARTITION; idx++) { | ||||
| 				part_size = ext_csd[EXT_CSD_BOOT_MULT] << 17; | ||||
| 				mmc_part_add(card, part_size, | ||||
| 					EXT_CSD_PART_CONFIG_ACC_BOOT0 + idx, | ||||
| 					"boot%d", idx, true); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	card->ext_csd.raw_hc_erase_gap_size = | ||||
|  | @ -359,11 +368,12 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) | |||
| 		 * card has the Enhanced area enabled.  If so, export enhanced | ||||
| 		 * area offset and size to user by adding sysfs interface. | ||||
| 		 */ | ||||
| 		card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT]; | ||||
| 		if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) && | ||||
| 		    (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { | ||||
| 			u8 hc_erase_grp_sz = | ||||
| 			hc_erase_grp_sz = | ||||
| 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; | ||||
| 			u8 hc_wp_grp_sz = | ||||
| 			hc_wp_grp_sz = | ||||
| 				ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; | ||||
| 
 | ||||
| 			card->ext_csd.enhanced_area_en = 1; | ||||
|  | @ -392,6 +402,41 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) | |||
| 			card->ext_csd.enhanced_area_offset = -EINVAL; | ||||
| 			card->ext_csd.enhanced_area_size = -EINVAL; | ||||
| 		} | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * General purpose partition feature support -- | ||||
| 		 * If ext_csd has the size of general purpose partitions, | ||||
| 		 * set size, part_cfg, partition name in mmc_part. | ||||
| 		 */ | ||||
| 		if (ext_csd[EXT_CSD_PARTITION_SUPPORT] & | ||||
| 			EXT_CSD_PART_SUPPORT_PART_EN) { | ||||
| 			if (card->ext_csd.enhanced_area_en != 1) { | ||||
| 				hc_erase_grp_sz = | ||||
| 					ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; | ||||
| 				hc_wp_grp_sz = | ||||
| 					ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; | ||||
| 
 | ||||
| 				card->ext_csd.enhanced_area_en = 1; | ||||
| 			} | ||||
| 
 | ||||
| 			for (idx = 0; idx < MMC_NUM_GP_PARTITION; idx++) { | ||||
| 				if (!ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3] && | ||||
| 				!ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] && | ||||
| 				!ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2]) | ||||
| 					continue; | ||||
| 				part_size = | ||||
| 				(ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 2] | ||||
| 					<< 16) + | ||||
| 				(ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3 + 1] | ||||
| 					<< 8) + | ||||
| 				ext_csd[EXT_CSD_GP_SIZE_MULT + idx * 3]; | ||||
| 				part_size *= (size_t)(hc_erase_grp_sz * | ||||
| 					hc_wp_grp_sz); | ||||
| 				mmc_part_add(card, part_size << 19, | ||||
| 					EXT_CSD_PART_CONFIG_ACC_GP0 + idx, | ||||
| 					"gp%d", idx, false); | ||||
| 			} | ||||
| 		} | ||||
| 		card->ext_csd.sec_trim_mult = | ||||
| 			ext_csd[EXT_CSD_SEC_TRIM_MULT]; | ||||
| 		card->ext_csd.sec_erase_mult = | ||||
|  | @ -402,14 +447,48 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) | |||
| 			ext_csd[EXT_CSD_TRIM_MULT]; | ||||
| 	} | ||||
| 
 | ||||
| 	if (card->ext_csd.rev >= 5) | ||||
| 		card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; | ||||
| 	if (card->ext_csd.rev >= 5) { | ||||
| 		/* check whether the eMMC card supports HPI */ | ||||
| 		if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) { | ||||
| 			card->ext_csd.hpi = 1; | ||||
| 			if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2) | ||||
| 				card->ext_csd.hpi_cmd =	MMC_STOP_TRANSMISSION; | ||||
| 			else | ||||
| 				card->ext_csd.hpi_cmd = MMC_SEND_STATUS; | ||||
| 			/*
 | ||||
| 			 * Indicate the maximum timeout to close | ||||
| 			 * a command interrupted by HPI | ||||
| 			 */ | ||||
| 			card->ext_csd.out_of_int_time = | ||||
| 				ext_csd[EXT_CSD_OUT_OF_INTERRUPT_TIME] * 10; | ||||
| 		} | ||||
| 
 | ||||
| 		card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; | ||||
| 		card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; | ||||
| 	} | ||||
| 
 | ||||
| 	card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT]; | ||||
| 	if (ext_csd[EXT_CSD_ERASED_MEM_CONT]) | ||||
| 		card->erased_byte = 0xFF; | ||||
| 	else | ||||
| 		card->erased_byte = 0x0; | ||||
| 
 | ||||
| 	/* eMMC v4.5 or later */ | ||||
| 	if (card->ext_csd.rev >= 6) { | ||||
| 		card->ext_csd.feature_support |= MMC_DISCARD_FEATURE; | ||||
| 
 | ||||
| 		card->ext_csd.generic_cmd6_time = 10 * | ||||
| 			ext_csd[EXT_CSD_GENERIC_CMD6_TIME]; | ||||
| 		card->ext_csd.power_off_longtime = 10 * | ||||
| 			ext_csd[EXT_CSD_POWER_OFF_LONG_TIME]; | ||||
| 
 | ||||
| 		card->ext_csd.cache_size = | ||||
| 			ext_csd[EXT_CSD_CACHE_SIZE + 0] << 0 | | ||||
| 			ext_csd[EXT_CSD_CACHE_SIZE + 1] << 8 | | ||||
| 			ext_csd[EXT_CSD_CACHE_SIZE + 2] << 16 | | ||||
| 			ext_csd[EXT_CSD_CACHE_SIZE + 3] << 24; | ||||
| 	} | ||||
| 
 | ||||
| out: | ||||
| 	return err; | ||||
| } | ||||
|  | @ -529,6 +608,86 @@ static struct device_type mmc_type = { | |||
| 	.groups = mmc_attr_groups, | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * Select the PowerClass for the current bus width | ||||
|  * If power class is defined for 4/8 bit bus in the | ||||
|  * extended CSD register, select it by executing the | ||||
|  * mmc_switch command. | ||||
|  */ | ||||
| static int mmc_select_powerclass(struct mmc_card *card, | ||||
| 		unsigned int bus_width, u8 *ext_csd) | ||||
| { | ||||
| 	int err = 0; | ||||
| 	unsigned int pwrclass_val; | ||||
| 	unsigned int index = 0; | ||||
| 	struct mmc_host *host; | ||||
| 
 | ||||
| 	BUG_ON(!card); | ||||
| 
 | ||||
| 	host = card->host; | ||||
| 	BUG_ON(!host); | ||||
| 
 | ||||
| 	if (ext_csd == NULL) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	/* Power class selection is supported for versions >= 4.0 */ | ||||
| 	if (card->csd.mmca_vsn < CSD_SPEC_VER_4) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	/* Power class values are defined only for 4/8 bit bus */ | ||||
| 	if (bus_width == EXT_CSD_BUS_WIDTH_1) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	switch (1 << host->ios.vdd) { | ||||
| 	case MMC_VDD_165_195: | ||||
| 		if (host->ios.clock <= 26000000) | ||||
| 			index = EXT_CSD_PWR_CL_26_195; | ||||
| 		else if	(host->ios.clock <= 52000000) | ||||
| 			index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ? | ||||
| 				EXT_CSD_PWR_CL_52_195 : | ||||
| 				EXT_CSD_PWR_CL_DDR_52_195; | ||||
| 		else if (host->ios.clock <= 200000000) | ||||
| 			index = EXT_CSD_PWR_CL_200_195; | ||||
| 		break; | ||||
| 	case MMC_VDD_32_33: | ||||
| 	case MMC_VDD_33_34: | ||||
| 	case MMC_VDD_34_35: | ||||
| 	case MMC_VDD_35_36: | ||||
| 		if (host->ios.clock <= 26000000) | ||||
| 			index = EXT_CSD_PWR_CL_26_360; | ||||
| 		else if	(host->ios.clock <= 52000000) | ||||
| 			index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ? | ||||
| 				EXT_CSD_PWR_CL_52_360 : | ||||
| 				EXT_CSD_PWR_CL_DDR_52_360; | ||||
| 		else if (host->ios.clock <= 200000000) | ||||
| 			index = EXT_CSD_PWR_CL_200_360; | ||||
| 		break; | ||||
| 	default: | ||||
| 		pr_warning("%s: Voltage range not supported " | ||||
| 			   "for power class.\n", mmc_hostname(host)); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	pwrclass_val = ext_csd[index]; | ||||
| 
 | ||||
| 	if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8)) | ||||
| 		pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >> | ||||
| 				EXT_CSD_PWR_CL_8BIT_SHIFT; | ||||
| 	else | ||||
| 		pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_4BIT_MASK) >> | ||||
| 				EXT_CSD_PWR_CL_4BIT_SHIFT; | ||||
| 
 | ||||
| 	/* If the power class is different from the default value */ | ||||
| 	if (pwrclass_val > 0) { | ||||
| 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||||
| 				 EXT_CSD_POWER_CLASS, | ||||
| 				 pwrclass_val, | ||||
| 				 card->ext_csd.generic_cmd6_time); | ||||
| 	} | ||||
| 
 | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Handle the detection and initialisation of a card. | ||||
|  * | ||||
|  | @ -548,11 +707,16 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, | |||
| 	BUG_ON(!host); | ||||
| 	WARN_ON(!host->claimed); | ||||
| 
 | ||||
| 	/* Set correct bus mode for MMC before attempting init */ | ||||
| 	if (!mmc_host_is_spi(host)) | ||||
| 		mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Since we're changing the OCR value, we seem to | ||||
| 	 * need to tell some cards to go back to the idle | ||||
| 	 * state.  We wait 1ms to give cards time to | ||||
| 	 * respond. | ||||
| 	 * mmc_go_idle is needed for eMMC that are asleep | ||||
| 	 */ | ||||
| 	mmc_go_idle(host); | ||||
| 
 | ||||
|  | @ -668,7 +832,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, | |||
| 	 */ | ||||
| 	if (card->ext_csd.enhanced_area_en) { | ||||
| 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||||
| 				 EXT_CSD_ERASE_GROUP_DEF, 1, 0); | ||||
| 				 EXT_CSD_ERASE_GROUP_DEF, 1, | ||||
| 				 card->ext_csd.generic_cmd6_time); | ||||
| 
 | ||||
| 		if (err && err != -EBADMSG) | ||||
| 			goto free_card; | ||||
|  | @ -705,18 +870,36 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, | |||
| 			goto free_card; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If the host supports the power_off_notify capability then | ||||
| 	 * set the notification byte in the ext_csd register of device | ||||
| 	 */ | ||||
| 	if ((host->caps2 & MMC_CAP2_POWEROFF_NOTIFY) && | ||||
| 	    (card->poweroff_notify_state == MMC_NO_POWER_NOTIFICATION)) { | ||||
| 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||||
| 				 EXT_CSD_POWER_OFF_NOTIFICATION, | ||||
| 				 EXT_CSD_POWER_ON, | ||||
| 				 card->ext_csd.generic_cmd6_time); | ||||
| 		if (err && err != -EBADMSG) | ||||
| 			goto free_card; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!err) | ||||
| 		card->poweroff_notify_state = MMC_POWERED_ON; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Activate high speed (if supported) | ||||
| 	 */ | ||||
| 	if ((card->ext_csd.hs_max_dtr != 0) && | ||||
| 		(host->caps & MMC_CAP_MMC_HIGHSPEED)) { | ||||
| 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||||
| 				 EXT_CSD_HS_TIMING, 1, 0); | ||||
| 				 EXT_CSD_HS_TIMING, 1, | ||||
| 				 card->ext_csd.generic_cmd6_time); | ||||
| 		if (err && err != -EBADMSG) | ||||
| 			goto free_card; | ||||
| 
 | ||||
| 		if (err) { | ||||
| 			printk(KERN_WARNING "%s: switch to highspeed failed\n", | ||||
| 			pr_warning("%s: switch to highspeed failed\n", | ||||
| 			       mmc_hostname(card->host)); | ||||
| 			err = 0; | ||||
| 		} else { | ||||
|  | @ -725,6 +908,22 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Enable HPI feature (if supported) | ||||
| 	 */ | ||||
| 	if (card->ext_csd.hpi) { | ||||
| 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||||
| 			EXT_CSD_HPI_MGMT, 1, 0); | ||||
| 		if (err && err != -EBADMSG) | ||||
| 			goto free_card; | ||||
| 		if (err) { | ||||
| 			pr_warning("%s: Enabling HPI failed\n", | ||||
| 				   mmc_hostname(card->host)); | ||||
| 			err = 0; | ||||
| 		} else | ||||
| 			card->ext_csd.hpi_en = 1; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Compute bus speed. | ||||
| 	 */ | ||||
|  | @ -780,10 +979,18 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, | |||
| 			bus_width = bus_widths[idx]; | ||||
| 			if (bus_width == MMC_BUS_WIDTH_1) | ||||
| 				ddr = 0; /* no DDR for 1-bit width */ | ||||
| 			err = mmc_select_powerclass(card, ext_csd_bits[idx][0], | ||||
| 						    ext_csd); | ||||
| 			if (err) | ||||
| 				pr_err("%s: power class selection to " | ||||
| 				       "bus width %d failed\n", | ||||
| 				       mmc_hostname(card->host), | ||||
| 				       1 << bus_width); | ||||
| 
 | ||||
| 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||||
| 					 EXT_CSD_BUS_WIDTH, | ||||
| 					 ext_csd_bits[idx][0], | ||||
| 					 0); | ||||
| 					 card->ext_csd.generic_cmd6_time); | ||||
| 			if (!err) { | ||||
| 				mmc_set_bus_width(card->host, bus_width); | ||||
| 
 | ||||
|  | @ -803,13 +1010,21 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, | |||
| 		} | ||||
| 
 | ||||
| 		if (!err && ddr) { | ||||
| 			err = mmc_select_powerclass(card, ext_csd_bits[idx][1], | ||||
| 						    ext_csd); | ||||
| 			if (err) | ||||
| 				pr_err("%s: power class selection to " | ||||
| 				       "bus width %d ddr %d failed\n", | ||||
| 				       mmc_hostname(card->host), | ||||
| 				       1 << bus_width, ddr); | ||||
| 
 | ||||
| 			err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||||
| 					 EXT_CSD_BUS_WIDTH, | ||||
| 					 ext_csd_bits[idx][1], | ||||
| 					 0); | ||||
| 					 card->ext_csd.generic_cmd6_time); | ||||
| 		} | ||||
| 		if (err) { | ||||
| 			printk(KERN_WARNING "%s: switch to bus width %d ddr %d " | ||||
| 			pr_warning("%s: switch to bus width %d ddr %d " | ||||
| 				"failed\n", mmc_hostname(card->host), | ||||
| 				1 << bus_width, ddr); | ||||
| 			goto free_card; | ||||
|  | @ -840,6 +1055,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If cache size is higher than 0, this indicates | ||||
| 	 * the existence of cache and it can be turned on. | ||||
| 	 */ | ||||
| 	if ((host->caps2 & MMC_CAP2_CACHE_CTRL) && | ||||
| 			card->ext_csd.cache_size > 0) { | ||||
| 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||||
| 				EXT_CSD_CACHE_CTRL, 1, 0); | ||||
| 		if (err && err != -EBADMSG) | ||||
| 			goto free_card; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Only if no error, cache is turned on successfully. | ||||
| 		 */ | ||||
| 		card->ext_csd.cache_ctrl = err ? 0 : 1; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!oldcard) | ||||
| 		host->card = card; | ||||
| 
 | ||||
|  | @ -891,6 +1123,7 @@ static void mmc_detect(struct mmc_host *host) | |||
| 
 | ||||
| 		mmc_claim_host(host); | ||||
| 		mmc_detach_bus(host); | ||||
| 		mmc_power_off(host); | ||||
| 		mmc_release_host(host); | ||||
| 	} | ||||
| } | ||||
|  | @ -900,16 +1133,20 @@ static void mmc_detect(struct mmc_host *host) | |||
|  */ | ||||
| static int mmc_suspend(struct mmc_host *host) | ||||
| { | ||||
| 	int err = 0; | ||||
| 
 | ||||
| 	BUG_ON(!host); | ||||
| 	BUG_ON(!host->card); | ||||
| 
 | ||||
| 	mmc_claim_host(host); | ||||
| 	if (!mmc_host_is_spi(host)) | ||||
| 	if (mmc_card_can_sleep(host)) | ||||
| 		err = mmc_card_sleep(host); | ||||
| 	else if (!mmc_host_is_spi(host)) | ||||
| 		mmc_deselect_cards(host); | ||||
| 	host->card->state &= ~MMC_STATE_HIGHSPEED; | ||||
| 	mmc_release_host(host); | ||||
| 
 | ||||
| 	return 0; | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  | @ -1016,6 +1253,10 @@ int mmc_attach_mmc(struct mmc_host *host) | |||
| 	BUG_ON(!host); | ||||
| 	WARN_ON(!host->claimed); | ||||
| 
 | ||||
| 	/* Set correct bus mode for MMC before attempting attach */ | ||||
| 	if (!mmc_host_is_spi(host)) | ||||
| 		mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN); | ||||
| 
 | ||||
| 	err = mmc_send_op_cond(host, 0, &ocr); | ||||
| 	if (err) | ||||
| 		return err; | ||||
|  | @ -1038,7 +1279,7 @@ int mmc_attach_mmc(struct mmc_host *host) | |||
| 	 * support. | ||||
| 	 */ | ||||
| 	if (ocr & 0x7F) { | ||||
| 		printk(KERN_WARNING "%s: card claims to support voltages " | ||||
| 		pr_warning("%s: card claims to support voltages " | ||||
| 		       "below the defined range. These will be ignored.\n", | ||||
| 		       mmc_hostname(host)); | ||||
| 		ocr &= ~0x7F; | ||||
|  | @ -1077,7 +1318,7 @@ remove_card: | |||
| err: | ||||
| 	mmc_detach_bus(host); | ||||
| 
 | ||||
| 	printk(KERN_ERR "%s: error %d whilst initialising MMC card\n", | ||||
| 	pr_err("%s: error %d whilst initialising MMC card\n", | ||||
| 		mmc_hostname(host), err); | ||||
| 
 | ||||
| 	return err; | ||||
|  |  | |||
|  | @ -233,7 +233,7 @@ static int | |||
| mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host, | ||||
| 		u32 opcode, void *buf, unsigned len) | ||||
| { | ||||
| 	struct mmc_request mrq = {0}; | ||||
| 	struct mmc_request mrq = {NULL}; | ||||
| 	struct mmc_command cmd = {0}; | ||||
| 	struct mmc_data data = {0}; | ||||
| 	struct scatterlist sg; | ||||
|  | @ -414,7 +414,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, | |||
| 			return -EBADMSG; | ||||
| 	} else { | ||||
| 		if (status & 0xFDFFA000) | ||||
| 			printk(KERN_WARNING "%s: unexpected status %#x after " | ||||
| 			pr_warning("%s: unexpected status %#x after " | ||||
| 			       "switch", mmc_hostname(card->host), status); | ||||
| 		if (status & R1_SWITCH_ERROR) | ||||
| 			return -EBADMSG; | ||||
|  | @ -454,7 +454,7 @@ static int | |||
| mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, | ||||
| 		  u8 len) | ||||
| { | ||||
| 	struct mmc_request mrq = {0}; | ||||
| 	struct mmc_request mrq = {NULL}; | ||||
| 	struct mmc_command cmd = {0}; | ||||
| 	struct mmc_data data = {0}; | ||||
| 	struct scatterlist sg; | ||||
|  | @ -476,7 +476,7 @@ mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, | |||
| 	else if (len == 4) | ||||
| 		test_buf = testdata_4bit; | ||||
| 	else { | ||||
| 		printk(KERN_ERR "%s: Invalid bus_width %d\n", | ||||
| 		pr_err("%s: Invalid bus_width %d\n", | ||||
| 		       mmc_hostname(host), len); | ||||
| 		kfree(data_buf); | ||||
| 		return -EINVAL; | ||||
|  | @ -547,3 +547,34 @@ int mmc_bus_test(struct mmc_card *card, u8 bus_width) | |||
| 	err = mmc_send_bus_test(card, card->host, MMC_BUS_TEST_R, width); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status) | ||||
| { | ||||
| 	struct mmc_command cmd = {0}; | ||||
| 	unsigned int opcode; | ||||
| 	unsigned int flags; | ||||
| 	int err; | ||||
| 
 | ||||
| 	opcode = card->ext_csd.hpi_cmd; | ||||
| 	if (opcode == MMC_STOP_TRANSMISSION) | ||||
| 		flags = MMC_RSP_R1 | MMC_CMD_AC; | ||||
| 	else if (opcode == MMC_SEND_STATUS) | ||||
| 		flags = MMC_RSP_R1 | MMC_CMD_AC; | ||||
| 
 | ||||
| 	cmd.opcode = opcode; | ||||
| 	cmd.arg = card->rca << 16 | 1; | ||||
| 	cmd.flags = flags; | ||||
| 	cmd.cmd_timeout_ms = card->ext_csd.out_of_int_time; | ||||
| 
 | ||||
| 	err = mmc_wait_for_cmd(card->host, &cmd, 0); | ||||
| 	if (err) { | ||||
| 		pr_warn("%s: error %d interrupting operation. " | ||||
| 			"HPI command response %#x\n", mmc_hostname(card->host), | ||||
| 			err, cmd.resp[0]); | ||||
| 		return err; | ||||
| 	} | ||||
| 	if (status) | ||||
| 		*status = cmd.resp[0]; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  |  | |||
|  | @ -26,6 +26,7 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp); | |||
| int mmc_spi_set_crc(struct mmc_host *host, int use_crc); | ||||
| int mmc_card_sleepawake(struct mmc_host *host, int sleep); | ||||
| int mmc_bus_test(struct mmc_card *card, u8 bus_width); | ||||
| int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
|  |  | |||
|  | @ -21,6 +21,14 @@ | |||
| #define SDIO_DEVICE_ID_TI_WL1271	0x4076 | ||||
| #endif | ||||
| 
 | ||||
| #ifndef SDIO_VENDOR_ID_STE | ||||
| #define SDIO_VENDOR_ID_STE		0x0020 | ||||
| #endif | ||||
| 
 | ||||
| #ifndef SDIO_DEVICE_ID_STE_CW1200 | ||||
| #define SDIO_DEVICE_ID_STE_CW1200	0x2280 | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  * This hook just adds a quirk for all sdio devices | ||||
|  */ | ||||
|  | @ -46,6 +54,9 @@ static const struct mmc_fixup mmc_fixup_methods[] = { | |||
| 	SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, | ||||
| 		   add_quirk, MMC_QUIRK_DISABLE_CD), | ||||
| 
 | ||||
| 	SDIO_FIXUP(SDIO_VENDOR_ID_STE, SDIO_DEVICE_ID_STE_CW1200, | ||||
| 		   add_quirk, MMC_QUIRK_BROKEN_BYTE_MODE_512), | ||||
| 
 | ||||
| 	END_FIXUP | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -163,7 +163,7 @@ static int mmc_decode_csd(struct mmc_card *card) | |||
| 		csd->erase_size = 1; | ||||
| 		break; | ||||
| 	default: | ||||
| 		printk(KERN_ERR "%s: unrecognised CSD structure version %d\n", | ||||
| 		pr_err("%s: unrecognised CSD structure version %d\n", | ||||
| 			mmc_hostname(card->host), csd_struct); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | @ -187,7 +187,7 @@ static int mmc_decode_scr(struct mmc_card *card) | |||
| 
 | ||||
| 	scr_struct = UNSTUFF_BITS(resp, 60, 4); | ||||
| 	if (scr_struct != 0) { | ||||
| 		printk(KERN_ERR "%s: unrecognised SCR structure version %d\n", | ||||
| 		pr_err("%s: unrecognised SCR structure version %d\n", | ||||
| 			mmc_hostname(card->host), scr_struct); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | @ -218,7 +218,7 @@ static int mmc_read_ssr(struct mmc_card *card) | |||
| 	u32 *ssr; | ||||
| 
 | ||||
| 	if (!(card->csd.cmdclass & CCC_APP_SPEC)) { | ||||
| 		printk(KERN_WARNING "%s: card lacks mandatory SD Status " | ||||
| 		pr_warning("%s: card lacks mandatory SD Status " | ||||
| 			"function.\n", mmc_hostname(card->host)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | @ -229,7 +229,7 @@ static int mmc_read_ssr(struct mmc_card *card) | |||
| 
 | ||||
| 	err = mmc_app_sd_status(card, ssr); | ||||
| 	if (err) { | ||||
| 		printk(KERN_WARNING "%s: problem reading SD Status " | ||||
| 		pr_warning("%s: problem reading SD Status " | ||||
| 			"register.\n", mmc_hostname(card->host)); | ||||
| 		err = 0; | ||||
| 		goto out; | ||||
|  | @ -253,7 +253,7 @@ static int mmc_read_ssr(struct mmc_card *card) | |||
| 			card->ssr.erase_offset = eo * 1000; | ||||
| 		} | ||||
| 	} else { | ||||
| 		printk(KERN_WARNING "%s: SD Status: Invalid Allocation Unit " | ||||
| 		pr_warning("%s: SD Status: Invalid Allocation Unit " | ||||
| 			"size.\n", mmc_hostname(card->host)); | ||||
| 	} | ||||
| out: | ||||
|  | @ -273,7 +273,7 @@ static int mmc_read_switch(struct mmc_card *card) | |||
| 		return 0; | ||||
| 
 | ||||
| 	if (!(card->csd.cmdclass & CCC_SWITCH)) { | ||||
| 		printk(KERN_WARNING "%s: card lacks mandatory switch " | ||||
| 		pr_warning("%s: card lacks mandatory switch " | ||||
| 			"function, performance might suffer.\n", | ||||
| 			mmc_hostname(card->host)); | ||||
| 		return 0; | ||||
|  | @ -283,7 +283,7 @@ static int mmc_read_switch(struct mmc_card *card) | |||
| 
 | ||||
| 	status = kmalloc(64, GFP_KERNEL); | ||||
| 	if (!status) { | ||||
| 		printk(KERN_ERR "%s: could not allocate a buffer for " | ||||
| 		pr_err("%s: could not allocate a buffer for " | ||||
| 			"switch capabilities.\n", | ||||
| 			mmc_hostname(card->host)); | ||||
| 		return -ENOMEM; | ||||
|  | @ -299,13 +299,16 @@ static int mmc_read_switch(struct mmc_card *card) | |||
| 		if (err != -EINVAL && err != -ENOSYS && err != -EFAULT) | ||||
| 			goto out; | ||||
| 
 | ||||
| 		printk(KERN_WARNING "%s: problem reading Bus Speed modes.\n", | ||||
| 		pr_warning("%s: problem reading Bus Speed modes.\n", | ||||
| 			mmc_hostname(card->host)); | ||||
| 		err = 0; | ||||
| 
 | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	if (status[13] & UHS_SDR50_BUS_SPEED) | ||||
| 		card->sw_caps.hs_max_dtr = 50000000; | ||||
| 
 | ||||
| 	if (card->scr.sda_spec3) { | ||||
| 		card->sw_caps.sd3_bus_mode = status[13]; | ||||
| 
 | ||||
|  | @ -319,7 +322,7 @@ static int mmc_read_switch(struct mmc_card *card) | |||
| 			if (err != -EINVAL && err != -ENOSYS && err != -EFAULT) | ||||
| 				goto out; | ||||
| 
 | ||||
| 			printk(KERN_WARNING "%s: problem reading " | ||||
| 			pr_warning("%s: problem reading " | ||||
| 				"Driver Strength.\n", | ||||
| 				mmc_hostname(card->host)); | ||||
| 			err = 0; | ||||
|  | @ -339,7 +342,7 @@ static int mmc_read_switch(struct mmc_card *card) | |||
| 			if (err != -EINVAL && err != -ENOSYS && err != -EFAULT) | ||||
| 				goto out; | ||||
| 
 | ||||
| 			printk(KERN_WARNING "%s: problem reading " | ||||
| 			pr_warning("%s: problem reading " | ||||
| 				"Current Limit.\n", | ||||
| 				mmc_hostname(card->host)); | ||||
| 			err = 0; | ||||
|  | @ -348,9 +351,6 @@ static int mmc_read_switch(struct mmc_card *card) | |||
| 		} | ||||
| 
 | ||||
| 		card->sw_caps.sd3_curr_limit = status[7]; | ||||
| 	} else { | ||||
| 		if (status[13] & 0x02) | ||||
| 			card->sw_caps.hs_max_dtr = 50000000; | ||||
| 	} | ||||
| 
 | ||||
| out: | ||||
|  | @ -383,7 +383,7 @@ int mmc_sd_switch_hs(struct mmc_card *card) | |||
| 
 | ||||
| 	status = kmalloc(64, GFP_KERNEL); | ||||
| 	if (!status) { | ||||
| 		printk(KERN_ERR "%s: could not allocate a buffer for " | ||||
| 		pr_err("%s: could not allocate a buffer for " | ||||
| 			"switch capabilities.\n", mmc_hostname(card->host)); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
|  | @ -393,7 +393,7 @@ int mmc_sd_switch_hs(struct mmc_card *card) | |||
| 		goto out; | ||||
| 
 | ||||
| 	if ((status[16] & 0xF) != 1) { | ||||
| 		printk(KERN_WARNING "%s: Problem switching card " | ||||
| 		pr_warning("%s: Problem switching card " | ||||
| 			"into high-speed mode!\n", | ||||
| 			mmc_hostname(card->host)); | ||||
| 		err = 0; | ||||
|  | @ -459,7 +459,7 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status) | |||
| 		return err; | ||||
| 
 | ||||
| 	if ((status[15] & 0xF) != drive_strength) { | ||||
| 		printk(KERN_WARNING "%s: Problem setting drive strength!\n", | ||||
| 		pr_warning("%s: Problem setting drive strength!\n", | ||||
| 			mmc_hostname(card->host)); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | @ -538,7 +538,7 @@ static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status) | |||
| 		return err; | ||||
| 
 | ||||
| 	if ((status[16] & 0xF) != card->sd_bus_speed) | ||||
| 		printk(KERN_WARNING "%s: Problem setting bus speed mode!\n", | ||||
| 		pr_warning("%s: Problem setting bus speed mode!\n", | ||||
| 			mmc_hostname(card->host)); | ||||
| 	else { | ||||
| 		mmc_set_timing(card->host, timing); | ||||
|  | @ -600,7 +600,7 @@ static int sd_set_current_limit(struct mmc_card *card, u8 *status) | |||
| 		return err; | ||||
| 
 | ||||
| 	if (((status[15] >> 4) & 0x0F) != current_limit) | ||||
| 		printk(KERN_WARNING "%s: Problem setting current limit!\n", | ||||
| 		pr_warning("%s: Problem setting current limit!\n", | ||||
| 			mmc_hostname(card->host)); | ||||
| 
 | ||||
| 	return 0; | ||||
|  | @ -622,7 +622,7 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card) | |||
| 
 | ||||
| 	status = kmalloc(64, GFP_KERNEL); | ||||
| 	if (!status) { | ||||
| 		printk(KERN_ERR "%s: could not allocate a buffer for " | ||||
| 		pr_err("%s: could not allocate a buffer for " | ||||
| 			"switch capabilities.\n", mmc_hostname(card->host)); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
|  | @ -852,7 +852,7 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card, | |||
| 			ro = host->ops->get_ro(host); | ||||
| 
 | ||||
| 		if (ro < 0) { | ||||
| 			printk(KERN_WARNING "%s: host does not " | ||||
| 			pr_warning("%s: host does not " | ||||
| 				"support reading read-only " | ||||
| 				"switch. assuming write-enable.\n", | ||||
| 				mmc_hostname(host)); | ||||
|  | @ -929,8 +929,6 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, | |||
| 		err = mmc_send_relative_addr(host, &card->rca); | ||||
| 		if (err) | ||||
| 			return err; | ||||
| 
 | ||||
| 		mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); | ||||
| 	} | ||||
| 
 | ||||
| 	if (!oldcard) { | ||||
|  | @ -1043,6 +1041,7 @@ static void mmc_sd_detect(struct mmc_host *host) | |||
| 
 | ||||
| 		mmc_claim_host(host); | ||||
| 		mmc_detach_bus(host); | ||||
| 		mmc_power_off(host); | ||||
| 		mmc_release_host(host); | ||||
| 	} | ||||
| } | ||||
|  | @ -1167,7 +1166,7 @@ int mmc_attach_sd(struct mmc_host *host) | |||
| 	 * support. | ||||
| 	 */ | ||||
| 	if (ocr & 0x7F) { | ||||
| 		printk(KERN_WARNING "%s: card claims to support voltages " | ||||
| 		pr_warning("%s: card claims to support voltages " | ||||
| 		       "below the defined range. These will be ignored.\n", | ||||
| 		       mmc_hostname(host)); | ||||
| 		ocr &= ~0x7F; | ||||
|  | @ -1175,7 +1174,7 @@ int mmc_attach_sd(struct mmc_host *host) | |||
| 
 | ||||
| 	if ((ocr & MMC_VDD_165_195) && | ||||
| 	    !(host->ocr_avail_sd & MMC_VDD_165_195)) { | ||||
| 		printk(KERN_WARNING "%s: SD card claims to support the " | ||||
| 		pr_warning("%s: SD card claims to support the " | ||||
| 		       "incompletely defined 'low voltage range'. This " | ||||
| 		       "will be ignored.\n", mmc_hostname(host)); | ||||
| 		ocr &= ~MMC_VDD_165_195; | ||||
|  | @ -1214,7 +1213,7 @@ remove_card: | |||
| err: | ||||
| 	mmc_detach_bus(host); | ||||
| 
 | ||||
| 	printk(KERN_ERR "%s: error %d whilst initialising SD card\n", | ||||
| 	pr_err("%s: error %d whilst initialising SD card\n", | ||||
| 		mmc_hostname(host), err); | ||||
| 
 | ||||
| 	return err; | ||||
|  |  | |||
|  | @ -67,7 +67,7 @@ EXPORT_SYMBOL_GPL(mmc_app_cmd); | |||
| int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, | ||||
| 	struct mmc_command *cmd, int retries) | ||||
| { | ||||
| 	struct mmc_request mrq = {0}; | ||||
| 	struct mmc_request mrq = {NULL}; | ||||
| 
 | ||||
| 	int i, err; | ||||
| 
 | ||||
|  | @ -244,7 +244,7 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca) | |||
| int mmc_app_send_scr(struct mmc_card *card, u32 *scr) | ||||
| { | ||||
| 	int err; | ||||
| 	struct mmc_request mrq = {0}; | ||||
| 	struct mmc_request mrq = {NULL}; | ||||
| 	struct mmc_command cmd = {0}; | ||||
| 	struct mmc_data data = {0}; | ||||
| 	struct scatterlist sg; | ||||
|  | @ -303,7 +303,7 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr) | |||
| int mmc_sd_switch(struct mmc_card *card, int mode, int group, | ||||
| 	u8 value, u8 *resp) | ||||
| { | ||||
| 	struct mmc_request mrq = {0}; | ||||
| 	struct mmc_request mrq = {NULL}; | ||||
| 	struct mmc_command cmd = {0}; | ||||
| 	struct mmc_data data = {0}; | ||||
| 	struct scatterlist sg; | ||||
|  | @ -348,7 +348,7 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group, | |||
| int mmc_app_sd_status(struct mmc_card *card, void *ssr) | ||||
| { | ||||
| 	int err; | ||||
| 	struct mmc_request mrq = {0}; | ||||
| 	struct mmc_request mrq = {NULL}; | ||||
| 	struct mmc_command cmd = {0}; | ||||
| 	struct mmc_data data = {0}; | ||||
| 	struct scatterlist sg; | ||||
|  |  | |||
|  | @ -111,8 +111,8 @@ static int sdio_read_cccr(struct mmc_card *card) | |||
| 
 | ||||
| 	cccr_vsn = data & 0x0f; | ||||
| 
 | ||||
| 	if (cccr_vsn > SDIO_CCCR_REV_1_20) { | ||||
| 		printk(KERN_ERR "%s: unrecognised CCCR structure version %d\n", | ||||
| 	if (cccr_vsn > SDIO_CCCR_REV_3_00) { | ||||
| 		pr_err("%s: unrecognised CCCR structure version %d\n", | ||||
| 			mmc_hostname(card->host), cccr_vsn); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | @ -408,8 +408,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, | |||
| 		 */ | ||||
| 		if (oldcard) | ||||
| 			oldcard->rca = card->rca; | ||||
| 
 | ||||
| 		mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
|  | @ -597,6 +595,7 @@ out: | |||
| 
 | ||||
| 		mmc_claim_host(host); | ||||
| 		mmc_detach_bus(host); | ||||
| 		mmc_power_off(host); | ||||
| 		mmc_release_host(host); | ||||
| 	} | ||||
| } | ||||
|  | @ -778,7 +777,7 @@ int mmc_attach_sdio(struct mmc_host *host) | |||
| 	 * support. | ||||
| 	 */ | ||||
| 	if (ocr & 0x7F) { | ||||
| 		printk(KERN_WARNING "%s: card claims to support voltages " | ||||
| 		pr_warning("%s: card claims to support voltages " | ||||
| 		       "below the defined range. These will be ignored.\n", | ||||
| 		       mmc_hostname(host)); | ||||
| 		ocr &= ~0x7F; | ||||
|  | @ -875,7 +874,7 @@ remove: | |||
| err: | ||||
| 	mmc_detach_bus(host); | ||||
| 
 | ||||
| 	printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n", | ||||
| 	pr_err("%s: error %d whilst initialising SDIO card\n", | ||||
| 		mmc_hostname(host), err); | ||||
| 
 | ||||
| 	return err; | ||||
|  |  | |||
|  | @ -173,7 +173,7 @@ static int sdio_bus_remove(struct device *dev) | |||
| 	drv->remove(func); | ||||
| 
 | ||||
| 	if (func->irq_handler) { | ||||
| 		printk(KERN_WARNING "WARNING: driver %s did not remove " | ||||
| 		pr_warning("WARNING: driver %s did not remove " | ||||
| 			"its interrupt handler!\n", drv->name); | ||||
| 		sdio_claim_host(func); | ||||
| 		sdio_release_irq(func); | ||||
|  |  | |||
|  | @ -132,7 +132,7 @@ static int cis_tpl_parse(struct mmc_card *card, struct sdio_func *func, | |||
| 			ret = -EINVAL; | ||||
| 		} | ||||
| 		if (ret && ret != -EILSEQ && ret != -ENOENT) { | ||||
| 			printk(KERN_ERR "%s: bad %s tuple 0x%02x (%u bytes)\n", | ||||
| 			pr_err("%s: bad %s tuple 0x%02x (%u bytes)\n", | ||||
| 			       mmc_hostname(card->host), tpl_descr, code, size); | ||||
| 		} | ||||
| 	} else { | ||||
|  | @ -313,7 +313,7 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) | |||
| 
 | ||||
| 			if (ret == -ENOENT) { | ||||
| 				/* warn about unknown tuples */ | ||||
| 				printk(KERN_WARNING "%s: queuing unknown" | ||||
| 				pr_warning("%s: queuing unknown" | ||||
| 				       " CIS tuple 0x%02x (%u bytes)\n", | ||||
| 				       mmc_hostname(card->host), | ||||
| 				       tpl_code, tpl_link); | ||||
|  |  | |||
|  | @ -45,7 +45,7 @@ static int process_sdio_pending_irqs(struct mmc_card *card) | |||
| 
 | ||||
| 	ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending); | ||||
| 	if (ret) { | ||||
| 		printk(KERN_DEBUG "%s: error %d reading SDIO_CCCR_INTx\n", | ||||
| 		pr_debug("%s: error %d reading SDIO_CCCR_INTx\n", | ||||
| 		       mmc_card_id(card), ret); | ||||
| 		return ret; | ||||
| 	} | ||||
|  | @ -55,7 +55,7 @@ static int process_sdio_pending_irqs(struct mmc_card *card) | |||
| 		if (pending & (1 << i)) { | ||||
| 			func = card->sdio_func[i - 1]; | ||||
| 			if (!func) { | ||||
| 				printk(KERN_WARNING "%s: pending IRQ for " | ||||
| 				pr_warning("%s: pending IRQ for " | ||||
| 					"non-existent function\n", | ||||
| 					mmc_card_id(card)); | ||||
| 				ret = -EINVAL; | ||||
|  | @ -63,7 +63,7 @@ static int process_sdio_pending_irqs(struct mmc_card *card) | |||
| 				func->irq_handler(func); | ||||
| 				count++; | ||||
| 			} else { | ||||
| 				printk(KERN_WARNING "%s: pending IRQ with no handler\n", | ||||
| 				pr_warning("%s: pending IRQ with no handler\n", | ||||
| 				       sdio_func_id(func)); | ||||
| 				ret = -EINVAL; | ||||
| 			} | ||||
|  |  | |||
|  | @ -121,7 +121,7 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn, | |||
| int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, | ||||
| 	unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz) | ||||
| { | ||||
| 	struct mmc_request mrq = {0}; | ||||
| 	struct mmc_request mrq = {NULL}; | ||||
| 	struct mmc_command cmd = {0}; | ||||
| 	struct mmc_data data = {0}; | ||||
| 	struct scatterlist sg; | ||||
|  | @ -144,8 +144,11 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, | |||
| 	cmd.arg |= fn << 28; | ||||
| 	cmd.arg |= incr_addr ? 0x04000000 : 0x00000000; | ||||
| 	cmd.arg |= addr << 9; | ||||
| 	if (blocks == 1 && blksz <= 512) | ||||
| 		cmd.arg |= (blksz == 512) ? 0 : blksz;	/* byte mode */ | ||||
| 	if (blocks == 1 && blksz < 512) | ||||
| 		cmd.arg |= blksz;			/* byte mode */ | ||||
| 	else if (blocks == 1 && blksz == 512 && | ||||
| 		 !(mmc_card_broken_byte_mode_512(card))) | ||||
| 		cmd.arg |= 0;				/* byte mode, 0==512 */ | ||||
| 	else | ||||
| 		cmd.arg |= 0x08000000 | blocks;		/* block mode */ | ||||
| 	cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; | ||||
|  |  | |||
|  | @ -130,13 +130,13 @@ config MMC_SDHCI_CNS3XXX | |||
| 	  If unsure, say N. | ||||
| 
 | ||||
| config MMC_SDHCI_ESDHC_IMX | ||||
| 	tristate "SDHCI platform support for the Freescale eSDHC i.MX controller" | ||||
| 	depends on ARCH_MX25 || ARCH_MX35 || ARCH_MX5 | ||||
| 	tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller" | ||||
| 	depends on ARCH_MXC | ||||
| 	depends on MMC_SDHCI_PLTFM | ||||
| 	select MMC_SDHCI_IO_ACCESSORS | ||||
| 	help | ||||
| 	  This selects the Freescale eSDHC controller support on the platform | ||||
| 	  bus, found on platforms like mx35/51. | ||||
| 	  This selects the Freescale eSDHC/uSDHC controller support | ||||
| 	  found on i.MX25, i.MX35 i.MX5x and i.MX6x. | ||||
| 
 | ||||
| 	  If you have a controller with this interface, say Y or M here. | ||||
| 
 | ||||
|  | @ -326,11 +326,11 @@ config MMC_MSM | |||
| 	  support for SDIO devices. | ||||
| 
 | ||||
| config MMC_MXC | ||||
| 	tristate "Freescale i.MX2/3 Multimedia Card Interface support" | ||||
| 	depends on MACH_MX21 || MACH_MX27 || ARCH_MX31 | ||||
| 	tristate "Freescale i.MX21/27/31 Multimedia Card Interface support" | ||||
| 	depends on ARCH_MXC | ||||
| 	help | ||||
| 	  This selects the Freescale i.MX2/3 Multimedia card Interface. | ||||
| 	  If you have a i.MX platform with a Multimedia Card slot, | ||||
| 	  This selects the Freescale i.MX21, i.MX27 and i.MX31 Multimedia card | ||||
| 	  Interface. If you have a i.MX platform with a Multimedia Card slot, | ||||
| 	  say Y or M here. | ||||
| 
 | ||||
| 	  If unsure, say N. | ||||
|  |  | |||
|  | @ -869,7 +869,11 @@ static irqreturn_t at91_mci_irq(int irq, void *devid) | |||
| static irqreturn_t at91_mmc_det_irq(int irq, void *_host) | ||||
| { | ||||
| 	struct at91mci_host *host = _host; | ||||
| 	int present = !gpio_get_value(irq_to_gpio(irq)); | ||||
| 	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, | ||||
|  |  | |||
|  | @ -17,112 +17,126 @@ | |||
| #define __DRIVERS_MMC_ATMEL_MCI_H__ | ||||
| 
 | ||||
| /* MCI Register Definitions */ | ||||
| #define MCI_CR			0x0000	/* Control */ | ||||
| # define MCI_CR_MCIEN		(  1 <<  0)	/* MCI Enable */ | ||||
| # define MCI_CR_MCIDIS		(  1 <<  1)	/* MCI Disable */ | ||||
| # define MCI_CR_PWSEN		(  1 <<  2)	/* Power Save Enable */ | ||||
| # define MCI_CR_PWSDIS		(  1 <<  3)	/* Power Save Disable */ | ||||
| # define MCI_CR_SWRST		(  1 <<  7)	/* Software Reset */ | ||||
| #define MCI_MR			0x0004	/* Mode */ | ||||
| # define MCI_MR_CLKDIV(x)	((x) <<  0)	/* Clock Divider */ | ||||
| # define MCI_MR_PWSDIV(x)	((x) <<  8)	/* Power Saving Divider */ | ||||
| # define MCI_MR_RDPROOF		(  1 << 11)	/* Read Proof */ | ||||
| # define MCI_MR_WRPROOF		(  1 << 12)	/* Write Proof */ | ||||
| # define MCI_MR_PDCFBYTE	(  1 << 13)	/* Force Byte Transfer */ | ||||
| # define MCI_MR_PDCPADV		(  1 << 14)	/* Padding Value */ | ||||
| # define MCI_MR_PDCMODE		(  1 << 15)	/* PDC-oriented Mode */ | ||||
| #define MCI_DTOR		0x0008	/* Data Timeout */ | ||||
| # define MCI_DTOCYC(x)		((x) <<  0)	/* Data Timeout Cycles */ | ||||
| # define MCI_DTOMUL(x)		((x) <<  4)	/* Data Timeout Multiplier */ | ||||
| #define MCI_SDCR		0x000c	/* SD Card / SDIO */ | ||||
| # define MCI_SDCSEL_SLOT_A	(  0 <<  0)	/* Select SD slot A */ | ||||
| # define MCI_SDCSEL_SLOT_B	(  1 <<  0)	/* Select SD slot A */ | ||||
| # define MCI_SDCSEL_MASK	(  3 <<  0) | ||||
| # define MCI_SDCBUS_1BIT	(  0 <<  6)	/* 1-bit data bus */ | ||||
| # define MCI_SDCBUS_4BIT	(  2 <<  6)	/* 4-bit data bus */ | ||||
| # define MCI_SDCBUS_8BIT	(  3 <<  6)	/* 8-bit data bus[2] */ | ||||
| # define MCI_SDCBUS_MASK	(  3 <<  6) | ||||
| #define MCI_ARGR		0x0010	/* Command Argument */ | ||||
| #define MCI_CMDR		0x0014	/* Command */ | ||||
| # define MCI_CMDR_CMDNB(x)	((x) <<  0)	/* Command Opcode */ | ||||
| # define MCI_CMDR_RSPTYP_NONE	(  0 <<  6)	/* No response */ | ||||
| # define MCI_CMDR_RSPTYP_48BIT	(  1 <<  6)	/* 48-bit response */ | ||||
| # define MCI_CMDR_RSPTYP_136BIT	(  2 <<  6)	/* 136-bit response */ | ||||
| # define MCI_CMDR_SPCMD_INIT	(  1 <<  8)	/* Initialization command */ | ||||
| # define MCI_CMDR_SPCMD_SYNC	(  2 <<  8)	/* Synchronized command */ | ||||
| # define MCI_CMDR_SPCMD_INT	(  4 <<  8)	/* Interrupt command */ | ||||
| # define MCI_CMDR_SPCMD_INTRESP	(  5 <<  8)	/* Interrupt response */ | ||||
| # define MCI_CMDR_OPDCMD	(  1 << 11)	/* Open Drain */ | ||||
| # define MCI_CMDR_MAXLAT_5CYC	(  0 << 12)	/* Max latency 5 cycles */ | ||||
| # define MCI_CMDR_MAXLAT_64CYC	(  1 << 12)	/* Max latency 64 cycles */ | ||||
| # define MCI_CMDR_START_XFER	(  1 << 16)	/* Start data transfer */ | ||||
| # define MCI_CMDR_STOP_XFER	(  2 << 16)	/* Stop data transfer */ | ||||
| # define MCI_CMDR_TRDIR_WRITE	(  0 << 18)	/* Write data */ | ||||
| # define MCI_CMDR_TRDIR_READ	(  1 << 18)	/* Read data */ | ||||
| # define MCI_CMDR_BLOCK		(  0 << 19)	/* Single-block transfer */ | ||||
| # define MCI_CMDR_MULTI_BLOCK	(  1 << 19)	/* Multi-block transfer */ | ||||
| # define MCI_CMDR_STREAM	(  2 << 19)	/* MMC Stream transfer */ | ||||
| # define MCI_CMDR_SDIO_BYTE	(  4 << 19)	/* SDIO Byte transfer */ | ||||
| # define MCI_CMDR_SDIO_BLOCK	(  5 << 19)	/* SDIO Block transfer */ | ||||
| # define MCI_CMDR_SDIO_SUSPEND	(  1 << 24)	/* SDIO Suspend Command */ | ||||
| # define MCI_CMDR_SDIO_RESUME	(  2 << 24)	/* SDIO Resume Command */ | ||||
| #define MCI_BLKR		0x0018	/* Block */ | ||||
| # define MCI_BCNT(x)		((x) <<  0)	/* Data Block Count */ | ||||
| # define MCI_BLKLEN(x)		((x) << 16)	/* Data Block Length */ | ||||
| #define MCI_CSTOR		0x001c	/* Completion Signal Timeout[2] */ | ||||
| # define MCI_CSTOCYC(x)		((x) <<  0)	/* CST cycles */ | ||||
| # define MCI_CSTOMUL(x)		((x) <<  4)	/* CST multiplier */ | ||||
| #define MCI_RSPR		0x0020	/* Response 0 */ | ||||
| #define MCI_RSPR1		0x0024	/* Response 1 */ | ||||
| #define MCI_RSPR2		0x0028	/* Response 2 */ | ||||
| #define MCI_RSPR3		0x002c	/* Response 3 */ | ||||
| #define MCI_RDR			0x0030	/* Receive Data */ | ||||
| #define MCI_TDR			0x0034	/* Transmit Data */ | ||||
| #define MCI_SR			0x0040	/* Status */ | ||||
| #define MCI_IER			0x0044	/* Interrupt Enable */ | ||||
| #define MCI_IDR			0x0048	/* Interrupt Disable */ | ||||
| #define MCI_IMR			0x004c	/* Interrupt Mask */ | ||||
| # define MCI_CMDRDY		(  1 <<   0)	/* Command Ready */ | ||||
| # define MCI_RXRDY		(  1 <<   1)	/* Receiver Ready */ | ||||
| # define MCI_TXRDY		(  1 <<   2)	/* Transmitter Ready */ | ||||
| # define MCI_BLKE		(  1 <<   3)	/* Data Block Ended */ | ||||
| # define MCI_DTIP		(  1 <<   4)	/* Data Transfer In Progress */ | ||||
| # define MCI_NOTBUSY		(  1 <<   5)	/* Data Not Busy */ | ||||
| # define MCI_SDIOIRQA		(  1 <<   8)	/* SDIO IRQ in slot A */ | ||||
| # define MCI_SDIOIRQB		(  1 <<   9)	/* SDIO IRQ in slot B */ | ||||
| # define MCI_RINDE		(  1 <<  16)	/* Response Index Error */ | ||||
| # define MCI_RDIRE		(  1 <<  17)	/* Response Direction Error */ | ||||
| # define MCI_RCRCE		(  1 <<  18)	/* Response CRC Error */ | ||||
| # define MCI_RENDE		(  1 <<  19)	/* Response End Bit Error */ | ||||
| # define MCI_RTOE		(  1 <<  20)	/* Response Time-Out Error */ | ||||
| # define MCI_DCRCE		(  1 <<  21)	/* Data CRC Error */ | ||||
| # define MCI_DTOE		(  1 <<  22)	/* Data Time-Out Error */ | ||||
| # define MCI_OVRE		(  1 <<  30)	/* RX Overrun Error */ | ||||
| # define MCI_UNRE		(  1 <<  31)	/* TX Underrun Error */ | ||||
| #define MCI_DMA			0x0050	/* DMA Configuration[2] */ | ||||
| # define MCI_DMA_OFFSET(x)	((x) <<  0)	/* DMA Write Buffer Offset */ | ||||
| # define MCI_DMA_CHKSIZE(x)	((x) <<  4)	/* DMA Channel Read and Write Chunk Size */ | ||||
| # define MCI_DMAEN		(  1 <<  8)	/* DMA Hardware Handshaking Enable */ | ||||
| #define MCI_CFG			0x0054	/* Configuration[2] */ | ||||
| # define MCI_CFG_FIFOMODE_1DATA	(  1 <<  0)	/* MCI Internal FIFO control mode */ | ||||
| # define MCI_CFG_FERRCTRL_COR	(  1 <<  4)	/* Flow Error flag reset control mode */ | ||||
| # define MCI_CFG_HSMODE		(  1 <<  8)	/* High Speed Mode */ | ||||
| # define MCI_CFG_LSYNC		(  1 << 12)	/* Synchronize on the last block */ | ||||
| #define MCI_WPMR		0x00e4	/* Write Protection Mode[2] */ | ||||
| # define MCI_WP_EN		(  1 <<  0)	/* WP Enable */ | ||||
| # define MCI_WP_KEY		(0x4d4349 << 8)	/* WP Key */ | ||||
| #define MCI_WPSR		0x00e8	/* Write Protection Status[2] */ | ||||
| # define MCI_GET_WP_VS(x)	((x) & 0x0f) | ||||
| # define MCI_GET_WP_VSRC(x)	(((x) >> 8) & 0xffff) | ||||
| #define MCI_FIFO_APERTURE	0x0200	/* FIFO Aperture[2] */ | ||||
| #define ATMCI_CR			0x0000	/* Control */ | ||||
| # define ATMCI_CR_MCIEN			(  1 <<  0)	/* MCI Enable */ | ||||
| # define ATMCI_CR_MCIDIS		(  1 <<  1)	/* MCI Disable */ | ||||
| # define ATMCI_CR_PWSEN			(  1 <<  2)	/* Power Save Enable */ | ||||
| # define ATMCI_CR_PWSDIS		(  1 <<  3)	/* Power Save Disable */ | ||||
| # define ATMCI_CR_SWRST			(  1 <<  7)	/* Software Reset */ | ||||
| #define ATMCI_MR			0x0004	/* Mode */ | ||||
| # define ATMCI_MR_CLKDIV(x)		((x) <<  0)	/* Clock Divider */ | ||||
| # define ATMCI_MR_PWSDIV(x)		((x) <<  8)	/* Power Saving Divider */ | ||||
| # define ATMCI_MR_RDPROOF		(  1 << 11)	/* Read Proof */ | ||||
| # define ATMCI_MR_WRPROOF		(  1 << 12)	/* Write Proof */ | ||||
| # define ATMCI_MR_PDCFBYTE		(  1 << 13)	/* Force Byte Transfer */ | ||||
| # define ATMCI_MR_PDCPADV		(  1 << 14)	/* Padding Value */ | ||||
| # define ATMCI_MR_PDCMODE		(  1 << 15)	/* PDC-oriented Mode */ | ||||
| #define ATMCI_DTOR			0x0008	/* Data Timeout */ | ||||
| # define ATMCI_DTOCYC(x)		((x) <<  0)	/* Data Timeout Cycles */ | ||||
| # define ATMCI_DTOMUL(x)		((x) <<  4)	/* Data Timeout Multiplier */ | ||||
| #define ATMCI_SDCR			0x000c	/* SD Card / SDIO */ | ||||
| # define ATMCI_SDCSEL_SLOT_A		(  0 <<  0)	/* Select SD slot A */ | ||||
| # define ATMCI_SDCSEL_SLOT_B		(  1 <<  0)	/* Select SD slot A */ | ||||
| # define ATMCI_SDCSEL_MASK		(  3 <<  0) | ||||
| # define ATMCI_SDCBUS_1BIT		(  0 <<  6)	/* 1-bit data bus */ | ||||
| # define ATMCI_SDCBUS_4BIT		(  2 <<  6)	/* 4-bit data bus */ | ||||
| # define ATMCI_SDCBUS_8BIT		(  3 <<  6)	/* 8-bit data bus[2] */ | ||||
| # define ATMCI_SDCBUS_MASK		(  3 <<  6) | ||||
| #define ATMCI_ARGR			0x0010	/* Command Argument */ | ||||
| #define ATMCI_CMDR			0x0014	/* Command */ | ||||
| # define ATMCI_CMDR_CMDNB(x)		((x) <<  0)	/* Command Opcode */ | ||||
| # define ATMCI_CMDR_RSPTYP_NONE		(  0 <<  6)	/* No response */ | ||||
| # define ATMCI_CMDR_RSPTYP_48BIT	(  1 <<  6)	/* 48-bit response */ | ||||
| # define ATMCI_CMDR_RSPTYP_136BIT	(  2 <<  6)	/* 136-bit response */ | ||||
| # define ATMCI_CMDR_SPCMD_INIT		(  1 <<  8)	/* Initialization command */ | ||||
| # define ATMCI_CMDR_SPCMD_SYNC		(  2 <<  8)	/* Synchronized command */ | ||||
| # define ATMCI_CMDR_SPCMD_INT		(  4 <<  8)	/* Interrupt command */ | ||||
| # define ATMCI_CMDR_SPCMD_INTRESP	(  5 <<  8)	/* Interrupt response */ | ||||
| # define ATMCI_CMDR_OPDCMD		(  1 << 11)	/* Open Drain */ | ||||
| # define ATMCI_CMDR_MAXLAT_5CYC		(  0 << 12)	/* Max latency 5 cycles */ | ||||
| # define ATMCI_CMDR_MAXLAT_64CYC	(  1 << 12)	/* Max latency 64 cycles */ | ||||
| # define ATMCI_CMDR_START_XFER		(  1 << 16)	/* Start data transfer */ | ||||
| # define ATMCI_CMDR_STOP_XFER		(  2 << 16)	/* Stop data transfer */ | ||||
| # define ATMCI_CMDR_TRDIR_WRITE		(  0 << 18)	/* Write data */ | ||||
| # define ATMCI_CMDR_TRDIR_READ		(  1 << 18)	/* Read data */ | ||||
| # define ATMCI_CMDR_BLOCK		(  0 << 19)	/* Single-block transfer */ | ||||
| # define ATMCI_CMDR_MULTI_BLOCK		(  1 << 19)	/* Multi-block transfer */ | ||||
| # define ATMCI_CMDR_STREAM		(  2 << 19)	/* MMC Stream transfer */ | ||||
| # define ATMCI_CMDR_SDIO_BYTE		(  4 << 19)	/* SDIO Byte transfer */ | ||||
| # define ATMCI_CMDR_SDIO_BLOCK		(  5 << 19)	/* SDIO Block transfer */ | ||||
| # define ATMCI_CMDR_SDIO_SUSPEND	(  1 << 24)	/* SDIO Suspend Command */ | ||||
| # define ATMCI_CMDR_SDIO_RESUME		(  2 << 24)	/* SDIO Resume Command */ | ||||
| #define ATMCI_BLKR			0x0018	/* Block */ | ||||
| # define ATMCI_BCNT(x)			((x) <<  0)	/* Data Block Count */ | ||||
| # define ATMCI_BLKLEN(x)		((x) << 16)	/* Data Block Length */ | ||||
| #define ATMCI_CSTOR			0x001c	/* Completion Signal Timeout[2] */ | ||||
| # define ATMCI_CSTOCYC(x)		((x) <<  0)	/* CST cycles */ | ||||
| # define ATMCI_CSTOMUL(x)		((x) <<  4)	/* CST multiplier */ | ||||
| #define ATMCI_RSPR			0x0020	/* Response 0 */ | ||||
| #define ATMCI_RSPR1			0x0024	/* Response 1 */ | ||||
| #define ATMCI_RSPR2			0x0028	/* Response 2 */ | ||||
| #define ATMCI_RSPR3			0x002c	/* Response 3 */ | ||||
| #define ATMCI_RDR			0x0030	/* Receive Data */ | ||||
| #define ATMCI_TDR			0x0034	/* Transmit Data */ | ||||
| #define ATMCI_SR			0x0040	/* Status */ | ||||
| #define ATMCI_IER			0x0044	/* Interrupt Enable */ | ||||
| #define ATMCI_IDR			0x0048	/* Interrupt Disable */ | ||||
| #define ATMCI_IMR			0x004c	/* Interrupt Mask */ | ||||
| # define ATMCI_CMDRDY			(  1 <<   0)	/* Command Ready */ | ||||
| # define ATMCI_RXRDY			(  1 <<   1)	/* Receiver Ready */ | ||||
| # define ATMCI_TXRDY			(  1 <<   2)	/* Transmitter Ready */ | ||||
| # define ATMCI_BLKE			(  1 <<   3)	/* Data Block Ended */ | ||||
| # define ATMCI_DTIP			(  1 <<   4)	/* Data Transfer In Progress */ | ||||
| # define ATMCI_NOTBUSY			(  1 <<   5)	/* Data Not Busy */ | ||||
| # define ATMCI_ENDRX			(  1 <<   6)    /* End of RX Buffer */ | ||||
| # define ATMCI_ENDTX			(  1 <<   7)    /* End of TX Buffer */ | ||||
| # define ATMCI_SDIOIRQA			(  1 <<   8)	/* SDIO IRQ in slot A */ | ||||
| # define ATMCI_SDIOIRQB			(  1 <<   9)	/* SDIO IRQ in slot B */ | ||||
| # define ATMCI_SDIOWAIT			(  1 <<  12)    /* SDIO Read Wait Operation Status */ | ||||
| # define ATMCI_CSRCV			(  1 <<  13)    /* CE-ATA Completion Signal Received */ | ||||
| # define ATMCI_RXBUFF			(  1 <<  14)    /* RX Buffer Full */ | ||||
| # define ATMCI_TXBUFE			(  1 <<  15)    /* TX Buffer Empty */ | ||||
| # define ATMCI_RINDE			(  1 <<  16)	/* Response Index Error */ | ||||
| # define ATMCI_RDIRE			(  1 <<  17)	/* Response Direction Error */ | ||||
| # define ATMCI_RCRCE			(  1 <<  18)	/* Response CRC Error */ | ||||
| # define ATMCI_RENDE			(  1 <<  19)	/* Response End Bit Error */ | ||||
| # define ATMCI_RTOE			(  1 <<  20)	/* Response Time-Out Error */ | ||||
| # define ATMCI_DCRCE			(  1 <<  21)	/* Data CRC Error */ | ||||
| # define ATMCI_DTOE			(  1 <<  22)	/* Data Time-Out Error */ | ||||
| # define ATMCI_CSTOE			(  1 <<  23)    /* Completion Signal Time-out Error */ | ||||
| # define ATMCI_BLKOVRE			(  1 <<  24)    /* DMA Block Overrun Error */ | ||||
| # define ATMCI_DMADONE			(  1 <<  25)    /* DMA Transfer Done */ | ||||
| # define ATMCI_FIFOEMPTY		(  1 <<  26)    /* FIFO Empty Flag */ | ||||
| # define ATMCI_XFRDONE			(  1 <<  27)    /* Transfer Done Flag */ | ||||
| # define ATMCI_ACKRCV			(  1 <<  28)    /* Boot Operation Acknowledge Received */ | ||||
| # define ATMCI_ACKRCVE			(  1 <<  29)    /* Boot Operation Acknowledge Error */ | ||||
| # define ATMCI_OVRE			(  1 <<  30)	/* RX Overrun Error */ | ||||
| # define ATMCI_UNRE			(  1 <<  31)	/* TX Underrun Error */ | ||||
| #define ATMCI_DMA			0x0050	/* DMA Configuration[2] */ | ||||
| # define ATMCI_DMA_OFFSET(x)		((x) <<  0)	/* DMA Write Buffer Offset */ | ||||
| # define ATMCI_DMA_CHKSIZE(x)		((x) <<  4)	/* DMA Channel Read and Write Chunk Size */ | ||||
| # define ATMCI_DMAEN			(  1 <<  8)	/* DMA Hardware Handshaking Enable */ | ||||
| #define ATMCI_CFG			0x0054	/* Configuration[2] */ | ||||
| # define ATMCI_CFG_FIFOMODE_1DATA	(  1 <<  0)	/* MCI Internal FIFO control mode */ | ||||
| # define ATMCI_CFG_FERRCTRL_COR		(  1 <<  4)	/* Flow Error flag reset control mode */ | ||||
| # define ATMCI_CFG_HSMODE		(  1 <<  8)	/* High Speed Mode */ | ||||
| # define ATMCI_CFG_LSYNC		(  1 << 12)	/* Synchronize on the last block */ | ||||
| #define ATMCI_WPMR			0x00e4	/* Write Protection Mode[2] */ | ||||
| # define ATMCI_WP_EN			(  1 <<  0)	/* WP Enable */ | ||||
| # define ATMCI_WP_KEY			(0x4d4349 << 8)	/* WP Key */ | ||||
| #define ATMCI_WPSR			0x00e8	/* Write Protection Status[2] */ | ||||
| # define ATMCI_GET_WP_VS(x)		((x) & 0x0f) | ||||
| # define ATMCI_GET_WP_VSRC(x)		(((x) >> 8) & 0xffff) | ||||
| #define ATMCI_VERSION			0x00FC  /* Version */ | ||||
| #define ATMCI_FIFO_APERTURE		0x0200	/* FIFO Aperture[2] */ | ||||
| 
 | ||||
| /* This is not including the FIFO Aperture on MCI2 */ | ||||
| #define MCI_REGS_SIZE		0x100 | ||||
| #define ATMCI_REGS_SIZE		0x100 | ||||
| 
 | ||||
| /* Register access macros */ | ||||
| #define mci_readl(port,reg)				\ | ||||
| 	__raw_readl((port)->regs + MCI_##reg) | ||||
| #define mci_writel(port,reg,value)			\ | ||||
| 	__raw_writel((value), (port)->regs + MCI_##reg) | ||||
| #define atmci_readl(port,reg)				\ | ||||
| 	__raw_readl((port)->regs + reg) | ||||
| #define atmci_writel(port,reg,value)			\ | ||||
| 	__raw_writel((value), (port)->regs + reg) | ||||
| 
 | ||||
| #endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */ | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -55,7 +55,7 @@ | |||
| 
 | ||||
| #ifdef DEBUG | ||||
| #define DBG(fmt, idx, args...)	\ | ||||
| 	printk(KERN_DEBUG "au1xmmc(%d): DEBUG: " fmt, idx, ##args) | ||||
| 	pr_debug("au1xmmc(%d): DEBUG: " fmt, idx, ##args) | ||||
| #else | ||||
| #define DBG(fmt, idx, args...) do {} while (0) | ||||
| #endif | ||||
|  | @ -268,7 +268,7 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait, | |||
| 		mmccmd |= SD_CMD_RT_3; | ||||
| 		break; | ||||
| 	default: | ||||
| 		printk(KERN_INFO "au1xmmc: unhandled response type %02x\n", | ||||
| 		pr_info("au1xmmc: unhandled response type %02x\n", | ||||
| 			mmc_resp_type(cmd)); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | @ -1031,7 +1031,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev) | |||
| #ifdef CONFIG_SOC_AU1200 | ||||
| 	ret = au1xmmc_dbdma_init(host); | ||||
| 	if (ret) | ||||
| 		printk(KERN_INFO DRIVER_NAME ": DBDMA init failed; using PIO\n"); | ||||
| 		pr_info(DRIVER_NAME ": DBDMA init failed; using PIO\n"); | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_LEDS_CLASS | ||||
|  | @ -1056,7 +1056,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev) | |||
| 
 | ||||
| 	platform_set_drvdata(pdev, host); | ||||
| 
 | ||||
| 	printk(KERN_INFO DRIVER_NAME ": MMC Controller %d set up at %8.8X" | ||||
| 	pr_info(DRIVER_NAME ": MMC Controller %d set up at %8.8X" | ||||
| 		" (mode=%s)\n", pdev->id, host->iobase, | ||||
| 		host->flags & HOST_F_DMA ? "dma" : "pio"); | ||||
| 
 | ||||
|  | @ -1188,7 +1188,7 @@ static int __init au1xmmc_init(void) | |||
| 	 */ | ||||
| 	memid = au1xxx_ddma_add_device(&au1xmmc_mem_dbdev); | ||||
| 	if (!memid) | ||||
| 		printk(KERN_ERR "au1xmmc: cannot add memory dbdma dev\n"); | ||||
| 		pr_err("au1xmmc: cannot add memory dbdma dev\n"); | ||||
| #endif | ||||
| 	return platform_driver_register(&au1xmmc_driver); | ||||
| } | ||||
|  |  | |||
|  | @ -764,11 +764,29 @@ static int dw_mci_get_cd(struct mmc_host *mmc) | |||
| 	return present; | ||||
| } | ||||
| 
 | ||||
| static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb) | ||||
| { | ||||
| 	struct dw_mci_slot *slot = mmc_priv(mmc); | ||||
| 	struct dw_mci *host = slot->host; | ||||
| 	u32 int_mask; | ||||
| 
 | ||||
| 	/* Enable/disable Slot Specific SDIO interrupt */ | ||||
| 	int_mask = mci_readl(host, INTMASK); | ||||
| 	if (enb) { | ||||
| 		mci_writel(host, INTMASK, | ||||
| 			   (int_mask | (1 << SDMMC_INT_SDIO(slot->id)))); | ||||
| 	} else { | ||||
| 		mci_writel(host, INTMASK, | ||||
| 			   (int_mask & ~(1 << SDMMC_INT_SDIO(slot->id)))); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static const struct mmc_host_ops dw_mci_ops = { | ||||
| 	.request	= dw_mci_request, | ||||
| 	.set_ios	= dw_mci_set_ios, | ||||
| 	.get_ro		= dw_mci_get_ro, | ||||
| 	.get_cd		= dw_mci_get_cd, | ||||
| 	.request		= dw_mci_request, | ||||
| 	.set_ios		= dw_mci_set_ios, | ||||
| 	.get_ro			= dw_mci_get_ro, | ||||
| 	.get_cd			= dw_mci_get_cd, | ||||
| 	.enable_sdio_irq	= dw_mci_enable_sdio_irq, | ||||
| }; | ||||
| 
 | ||||
| static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) | ||||
|  | @ -1025,7 +1043,8 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) | |||
| 		buf += len; | ||||
| 		cnt -= len; | ||||
| 		if (!sg_next(host->sg) || host->part_buf_count == 2) { | ||||
| 			mci_writew(host, DATA, host->part_buf16); | ||||
| 			mci_writew(host, DATA(host->data_offset), | ||||
| 					host->part_buf16); | ||||
| 			host->part_buf_count = 0; | ||||
| 		} | ||||
| 	} | ||||
|  | @ -1042,21 +1061,23 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt) | |||
| 			cnt -= len; | ||||
| 			/* push data from aligned buffer into fifo */ | ||||
| 			for (i = 0; i < items; ++i) | ||||
| 				mci_writew(host, DATA, aligned_buf[i]); | ||||
| 				mci_writew(host, DATA(host->data_offset), | ||||
| 						aligned_buf[i]); | ||||
| 		} | ||||
| 	} else | ||||
| #endif | ||||
| 	{ | ||||
| 		u16 *pdata = buf; | ||||
| 		for (; cnt >= 2; cnt -= 2) | ||||
| 			mci_writew(host, DATA, *pdata++); | ||||
| 			mci_writew(host, DATA(host->data_offset), *pdata++); | ||||
| 		buf = pdata; | ||||
| 	} | ||||
| 	/* put anything remaining in the part_buf */ | ||||
| 	if (cnt) { | ||||
| 		dw_mci_set_part_bytes(host, buf, cnt); | ||||
| 		if (!sg_next(host->sg)) | ||||
| 			mci_writew(host, DATA, host->part_buf16); | ||||
| 			mci_writew(host, DATA(host->data_offset), | ||||
| 					host->part_buf16); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -1071,7 +1092,8 @@ static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) | |||
| 			int items = len >> 1; | ||||
| 			int i; | ||||
| 			for (i = 0; i < items; ++i) | ||||
| 				aligned_buf[i] = mci_readw(host, DATA); | ||||
| 				aligned_buf[i] = mci_readw(host, | ||||
| 						DATA(host->data_offset)); | ||||
| 			/* memcpy from aligned buffer into output buffer */ | ||||
| 			memcpy(buf, aligned_buf, len); | ||||
| 			buf += len; | ||||
|  | @ -1082,11 +1104,11 @@ static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt) | |||
| 	{ | ||||
| 		u16 *pdata = buf; | ||||
| 		for (; cnt >= 2; cnt -= 2) | ||||
| 			*pdata++ = mci_readw(host, DATA); | ||||
| 			*pdata++ = mci_readw(host, DATA(host->data_offset)); | ||||
| 		buf = pdata; | ||||
| 	} | ||||
| 	if (cnt) { | ||||
| 		host->part_buf16 = mci_readw(host, DATA); | ||||
| 		host->part_buf16 = mci_readw(host, DATA(host->data_offset)); | ||||
| 		dw_mci_pull_final_bytes(host, buf, cnt); | ||||
| 	} | ||||
| } | ||||
|  | @ -1099,7 +1121,8 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) | |||
| 		buf += len; | ||||
| 		cnt -= len; | ||||
| 		if (!sg_next(host->sg) || host->part_buf_count == 4) { | ||||
| 			mci_writel(host, DATA, host->part_buf32); | ||||
| 			mci_writel(host, DATA(host->data_offset), | ||||
| 					host->part_buf32); | ||||
| 			host->part_buf_count = 0; | ||||
| 		} | ||||
| 	} | ||||
|  | @ -1116,21 +1139,23 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt) | |||
| 			cnt -= len; | ||||
| 			/* push data from aligned buffer into fifo */ | ||||
| 			for (i = 0; i < items; ++i) | ||||
| 				mci_writel(host, DATA, aligned_buf[i]); | ||||
| 				mci_writel(host, DATA(host->data_offset), | ||||
| 						aligned_buf[i]); | ||||
| 		} | ||||
| 	} else | ||||
| #endif | ||||
| 	{ | ||||
| 		u32 *pdata = buf; | ||||
| 		for (; cnt >= 4; cnt -= 4) | ||||
| 			mci_writel(host, DATA, *pdata++); | ||||
| 			mci_writel(host, DATA(host->data_offset), *pdata++); | ||||
| 		buf = pdata; | ||||
| 	} | ||||
| 	/* put anything remaining in the part_buf */ | ||||
| 	if (cnt) { | ||||
| 		dw_mci_set_part_bytes(host, buf, cnt); | ||||
| 		if (!sg_next(host->sg)) | ||||
| 			mci_writel(host, DATA, host->part_buf32); | ||||
| 			mci_writel(host, DATA(host->data_offset), | ||||
| 						host->part_buf32); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -1145,7 +1170,8 @@ static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) | |||
| 			int items = len >> 2; | ||||
| 			int i; | ||||
| 			for (i = 0; i < items; ++i) | ||||
| 				aligned_buf[i] = mci_readl(host, DATA); | ||||
| 				aligned_buf[i] = mci_readl(host, | ||||
| 						DATA(host->data_offset)); | ||||
| 			/* memcpy from aligned buffer into output buffer */ | ||||
| 			memcpy(buf, aligned_buf, len); | ||||
| 			buf += len; | ||||
|  | @ -1156,11 +1182,11 @@ static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt) | |||
| 	{ | ||||
| 		u32 *pdata = buf; | ||||
| 		for (; cnt >= 4; cnt -= 4) | ||||
| 			*pdata++ = mci_readl(host, DATA); | ||||
| 			*pdata++ = mci_readl(host, DATA(host->data_offset)); | ||||
| 		buf = pdata; | ||||
| 	} | ||||
| 	if (cnt) { | ||||
| 		host->part_buf32 = mci_readl(host, DATA); | ||||
| 		host->part_buf32 = mci_readl(host, DATA(host->data_offset)); | ||||
| 		dw_mci_pull_final_bytes(host, buf, cnt); | ||||
| 	} | ||||
| } | ||||
|  | @ -1173,7 +1199,8 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) | |||
| 		buf += len; | ||||
| 		cnt -= len; | ||||
| 		if (!sg_next(host->sg) || host->part_buf_count == 8) { | ||||
| 			mci_writew(host, DATA, host->part_buf); | ||||
| 			mci_writew(host, DATA(host->data_offset), | ||||
| 					host->part_buf); | ||||
| 			host->part_buf_count = 0; | ||||
| 		} | ||||
| 	} | ||||
|  | @ -1190,21 +1217,23 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt) | |||
| 			cnt -= len; | ||||
| 			/* push data from aligned buffer into fifo */ | ||||
| 			for (i = 0; i < items; ++i) | ||||
| 				mci_writeq(host, DATA, aligned_buf[i]); | ||||
| 				mci_writeq(host, DATA(host->data_offset), | ||||
| 						aligned_buf[i]); | ||||
| 		} | ||||
| 	} else | ||||
| #endif | ||||
| 	{ | ||||
| 		u64 *pdata = buf; | ||||
| 		for (; cnt >= 8; cnt -= 8) | ||||
| 			mci_writeq(host, DATA, *pdata++); | ||||
| 			mci_writeq(host, DATA(host->data_offset), *pdata++); | ||||
| 		buf = pdata; | ||||
| 	} | ||||
| 	/* put anything remaining in the part_buf */ | ||||
| 	if (cnt) { | ||||
| 		dw_mci_set_part_bytes(host, buf, cnt); | ||||
| 		if (!sg_next(host->sg)) | ||||
| 			mci_writeq(host, DATA, host->part_buf); | ||||
| 			mci_writeq(host, DATA(host->data_offset), | ||||
| 					host->part_buf); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -1219,7 +1248,8 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) | |||
| 			int items = len >> 3; | ||||
| 			int i; | ||||
| 			for (i = 0; i < items; ++i) | ||||
| 				aligned_buf[i] = mci_readq(host, DATA); | ||||
| 				aligned_buf[i] = mci_readq(host, | ||||
| 						DATA(host->data_offset)); | ||||
| 			/* memcpy from aligned buffer into output buffer */ | ||||
| 			memcpy(buf, aligned_buf, len); | ||||
| 			buf += len; | ||||
|  | @ -1230,11 +1260,11 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt) | |||
| 	{ | ||||
| 		u64 *pdata = buf; | ||||
| 		for (; cnt >= 8; cnt -= 8) | ||||
| 			*pdata++ = mci_readq(host, DATA); | ||||
| 			*pdata++ = mci_readq(host, DATA(host->data_offset)); | ||||
| 		buf = pdata; | ||||
| 	} | ||||
| 	if (cnt) { | ||||
| 		host->part_buf = mci_readq(host, DATA); | ||||
| 		host->part_buf = mci_readq(host, DATA(host->data_offset)); | ||||
| 		dw_mci_pull_final_bytes(host, buf, cnt); | ||||
| 	} | ||||
| } | ||||
|  | @ -1406,6 +1436,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) | |||
| 	struct dw_mci *host = dev_id; | ||||
| 	u32 status, pending; | ||||
| 	unsigned int pass_count = 0; | ||||
| 	int i; | ||||
| 
 | ||||
| 	do { | ||||
| 		status = mci_readl(host, RINTSTS); | ||||
|  | @ -1477,6 +1508,15 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) | |||
| 			queue_work(dw_mci_card_workqueue, &host->card_work); | ||||
| 		} | ||||
| 
 | ||||
| 		/* Handle SDIO Interrupts */ | ||||
| 		for (i = 0; i < host->num_slots; i++) { | ||||
| 			struct dw_mci_slot *slot = host->slot[i]; | ||||
| 			if (pending & SDMMC_INT_SDIO(i)) { | ||||
| 				mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i)); | ||||
| 				mmc_signal_sdio_irq(slot->mmc); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 	} while (pass_count++ < 5); | ||||
| 
 | ||||
| #ifdef CONFIG_MMC_DW_IDMAC | ||||
|  | @ -1673,7 +1713,7 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id) | |||
| 
 | ||||
| 	host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); | ||||
| 	if (IS_ERR(host->vmmc)) { | ||||
| 		printk(KERN_INFO "%s: no vmmc regulator found\n", mmc_hostname(mmc)); | ||||
| 		pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); | ||||
| 		host->vmmc = NULL; | ||||
| 	} else | ||||
| 		regulator_enable(host->vmmc); | ||||
|  | @ -1923,6 +1963,18 @@ static int dw_mci_probe(struct platform_device *pdev) | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * In 2.40a spec, Data offset is changed. | ||||
| 	 * Need to check the version-id and set data-offset for DATA register. | ||||
| 	 */ | ||||
| 	host->verid = SDMMC_GET_VERID(mci_readl(host, VERID)); | ||||
| 	dev_info(&pdev->dev, "Version ID is %04x\n", host->verid); | ||||
| 
 | ||||
| 	if (host->verid < DW_MMC_240A) | ||||
| 		host->data_offset = DATA_OFFSET; | ||||
| 	else | ||||
| 		host->data_offset = DATA_240A_OFFSET; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Enable interrupts for command done, data over, data empty, card det, | ||||
| 	 * receive ready and error such as transmit, receive timeout, crc error | ||||
|  |  | |||
|  | @ -14,6 +14,8 @@ | |||
| #ifndef _DW_MMC_H_ | ||||
| #define _DW_MMC_H_ | ||||
| 
 | ||||
| #define DW_MMC_240A		0x240a | ||||
| 
 | ||||
| #define SDMMC_CTRL		0x000 | ||||
| #define SDMMC_PWREN		0x004 | ||||
| #define SDMMC_CLKDIV		0x008 | ||||
|  | @ -51,7 +53,14 @@ | |||
| #define SDMMC_IDINTEN		0x090 | ||||
| #define SDMMC_DSCADDR		0x094 | ||||
| #define SDMMC_BUFADDR		0x098 | ||||
| #define SDMMC_DATA		0x100 | ||||
| #define SDMMC_DATA(x)		(x) | ||||
| 
 | ||||
| /*
 | ||||
|  * Data offset is difference according to Version | ||||
|  * Lower than 2.40a : data register offest is 0x100 | ||||
|  */ | ||||
| #define DATA_OFFSET		0x100 | ||||
| #define DATA_240A_OFFSET	0x200 | ||||
| 
 | ||||
| /* shift bit field */ | ||||
| #define _SBF(f, v)		((v) << (f)) | ||||
|  | @ -82,7 +91,7 @@ | |||
| #define SDMMC_CTYPE_4BIT		BIT(0) | ||||
| #define SDMMC_CTYPE_1BIT		0 | ||||
| /* Interrupt status & mask register defines */ | ||||
| #define SDMMC_INT_SDIO			BIT(16) | ||||
| #define SDMMC_INT_SDIO(n)		BIT(16 + (n)) | ||||
| #define SDMMC_INT_EBE			BIT(15) | ||||
| #define SDMMC_INT_ACD			BIT(14) | ||||
| #define SDMMC_INT_SBE			BIT(13) | ||||
|  | @ -130,6 +139,8 @@ | |||
| #define SDMMC_IDMAC_ENABLE		BIT(7) | ||||
| #define SDMMC_IDMAC_FB			BIT(1) | ||||
| #define SDMMC_IDMAC_SWRESET		BIT(0) | ||||
| /* Version ID register define */ | ||||
| #define SDMMC_GET_VERID(x)		((x) & 0xFFFF) | ||||
| 
 | ||||
| /* Register access macros */ | ||||
| #define mci_readl(dev, reg)			\ | ||||
|  |  | |||
|  | @ -942,7 +942,7 @@ static int __init imxmci_probe(struct platform_device *pdev) | |||
| 	int ret = 0, irq; | ||||
| 	u16 rev_no; | ||||
| 
 | ||||
| 	printk(KERN_INFO "i.MX mmc driver\n"); | ||||
| 	pr_info("i.MX mmc driver\n"); | ||||
| 
 | ||||
| 	r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||||
| 	irq = platform_get_irq(pdev, 0); | ||||
|  |  | |||
|  | @ -27,6 +27,7 @@ | |||
| #include <linux/sched.h> | ||||
| #include <linux/delay.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/bio.h> | ||||
| #include <linux/dma-mapping.h> | ||||
| #include <linux/crc7.h> | ||||
|  |  | |||
|  | @ -466,7 +466,7 @@ static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data) | |||
| 	struct mmci_host_next *next = &host->next_data; | ||||
| 
 | ||||
| 	if (data->host_cookie && data->host_cookie != next->cookie) { | ||||
| 		printk(KERN_WARNING "[%s] invalid cookie: data->host_cookie %d" | ||||
| 		pr_warning("[%s] invalid cookie: data->host_cookie %d" | ||||
| 		       " host->next_data.cookie %d\n", | ||||
| 		       __func__, data->host_cookie, host->next_data.cookie); | ||||
| 		data->host_cookie = 0; | ||||
|  | @ -531,7 +531,7 @@ static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq, | |||
| 	if (chan) { | ||||
| 		if (err) | ||||
| 			dmaengine_terminate_all(chan); | ||||
| 		if (err || data->host_cookie) | ||||
| 		if (data->host_cookie) | ||||
| 			dma_unmap_sg(mmc_dev(host->mmc), data->sg, | ||||
| 				     data->sg_len, dir); | ||||
| 		mrq->data->host_cookie = 0; | ||||
|  |  | |||
|  | @ -213,7 +213,8 @@ msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd) | |||
| 	msmsdcc_writel(host, host->cmd_timeout, MMCIDATATIMER); | ||||
| 	msmsdcc_writel(host, (unsigned int)host->curr.xfer_size, | ||||
| 		       MMCIDATALENGTH); | ||||
| 	msmsdcc_writel(host, host->cmd_pio_irqmask, MMCIMASK1); | ||||
| 	msmsdcc_writel(host, (msmsdcc_readl(host, MMCIMASK0) & | ||||
| 			(~MCI_IRQ_PIO)) | host->cmd_pio_irqmask, MMCIMASK0); | ||||
| 	msmsdcc_writel(host, host->cmd_datactrl, MMCIDATACTRL); | ||||
| 
 | ||||
| 	if (host->cmd_cmd) { | ||||
|  | @ -388,7 +389,7 @@ static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) | |||
| 	n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, | ||||
| 			host->dma.num_ents, host->dma.dir); | ||||
| 	if (n == 0) { | ||||
| 		printk(KERN_ERR "%s: Unable to map in all sg elements\n", | ||||
| 		pr_err("%s: Unable to map in all sg elements\n", | ||||
| 			mmc_hostname(host->mmc)); | ||||
| 		host->dma.sg = NULL; | ||||
| 		host->dma.num_ents = 0; | ||||
|  | @ -474,7 +475,7 @@ msmsdcc_start_command_deferred(struct msmsdcc_host *host, | |||
| 		*c |= MCI_CSPM_MCIABORT; | ||||
| 
 | ||||
| 	if (host->curr.cmd != NULL) { | ||||
| 		printk(KERN_ERR "%s: Overlapping command requests\n", | ||||
| 		pr_err("%s: Overlapping command requests\n", | ||||
| 			mmc_hostname(host->mmc)); | ||||
| 	} | ||||
| 	host->curr.cmd = cmd; | ||||
|  | @ -543,7 +544,9 @@ msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data, | |||
| 
 | ||||
| 		msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH); | ||||
| 
 | ||||
| 		msmsdcc_writel(host, pio_irqmask, MMCIMASK1); | ||||
| 		msmsdcc_writel(host, (msmsdcc_readl(host, MMCIMASK0) & | ||||
| 				(~MCI_IRQ_PIO)) | pio_irqmask, MMCIMASK0); | ||||
| 
 | ||||
| 		msmsdcc_writel(host, datactrl, MMCIDATACTRL); | ||||
| 
 | ||||
| 		if (cmd) { | ||||
|  | @ -659,8 +662,13 @@ msmsdcc_pio_irq(int irq, void *dev_id) | |||
| { | ||||
| 	struct msmsdcc_host	*host = dev_id; | ||||
| 	uint32_t		status; | ||||
| 	u32 mci_mask0; | ||||
| 
 | ||||
| 	status = msmsdcc_readl(host, MMCISTATUS); | ||||
| 	mci_mask0 = msmsdcc_readl(host, MMCIMASK0); | ||||
| 
 | ||||
| 	if (((mci_mask0 & status) & MCI_IRQ_PIO) == 0) | ||||
| 		return IRQ_NONE; | ||||
| 
 | ||||
| 	do { | ||||
| 		unsigned long flags; | ||||
|  | @ -719,10 +727,12 @@ msmsdcc_pio_irq(int irq, void *dev_id) | |||
| 	} while (1); | ||||
| 
 | ||||
| 	if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) | ||||
| 		msmsdcc_writel(host, MCI_RXDATAAVLBLMASK, MMCIMASK1); | ||||
| 		msmsdcc_writel(host, (mci_mask0 & (~MCI_IRQ_PIO)) | | ||||
| 					MCI_RXDATAAVLBLMASK, MMCIMASK0); | ||||
| 
 | ||||
| 	if (!host->curr.xfer_remain) | ||||
| 		msmsdcc_writel(host, 0, MMCIMASK1); | ||||
| 		msmsdcc_writel(host, (mci_mask0 & (~MCI_IRQ_PIO)) | 0, | ||||
| 					MMCIMASK0); | ||||
| 
 | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
|  | @ -854,6 +864,8 @@ msmsdcc_irq(int irq, void *dev_id) | |||
| 	do { | ||||
| 		status = msmsdcc_readl(host, MMCISTATUS); | ||||
| 		status &= msmsdcc_readl(host, MMCIMASK0); | ||||
| 		if ((status & (~MCI_IRQ_PIO)) == 0) | ||||
| 			break; | ||||
| 		msmsdcc_writel(host, status, MMCICLEAR); | ||||
| 
 | ||||
| 		if (status & MCI_SDIOINTR) | ||||
|  | @ -939,7 +951,7 @@ static void msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable) | |||
| 	struct msm_mmc_gpio_data *curr; | ||||
| 	int i, rc = 0; | ||||
| 
 | ||||
| 	if (!host->plat->gpio_data && host->gpio_config_status == enable) | ||||
| 	if (!host->plat->gpio_data || host->gpio_config_status == enable) | ||||
| 		return; | ||||
| 
 | ||||
| 	curr = host->plat->gpio_data; | ||||
|  | @ -1052,10 +1064,19 @@ static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) | |||
| 	spin_unlock_irqrestore(&host->lock, flags); | ||||
| } | ||||
| 
 | ||||
| static void msmsdcc_init_card(struct mmc_host *mmc, struct mmc_card *card) | ||||
| { | ||||
| 	struct msmsdcc_host *host = mmc_priv(mmc); | ||||
| 
 | ||||
| 	if (host->plat->init_card) | ||||
| 		host->plat->init_card(card); | ||||
| } | ||||
| 
 | ||||
| static const struct mmc_host_ops msmsdcc_ops = { | ||||
| 	.request	= msmsdcc_request, | ||||
| 	.set_ios	= msmsdcc_set_ios, | ||||
| 	.enable_sdio_irq = msmsdcc_enable_sdio_irq, | ||||
| 	.init_card	= msmsdcc_init_card, | ||||
| }; | ||||
| 
 | ||||
| static void | ||||
|  | @ -1092,7 +1113,7 @@ msmsdcc_platform_status_irq(int irq, void *dev_id) | |||
| { | ||||
| 	struct msmsdcc_host *host = dev_id; | ||||
| 
 | ||||
| 	printk(KERN_DEBUG "%s: %d\n", __func__, irq); | ||||
| 	pr_debug("%s: %d\n", __func__, irq); | ||||
| 	msmsdcc_check_status((unsigned long) host); | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
|  | @ -1102,7 +1123,7 @@ msmsdcc_status_notify_cb(int card_present, void *dev_id) | |||
| { | ||||
| 	struct msmsdcc_host *host = dev_id; | ||||
| 
 | ||||
| 	printk(KERN_DEBUG "%s: card_present %d\n", mmc_hostname(host->mmc), | ||||
| 	pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc), | ||||
| 	       card_present); | ||||
| 	msmsdcc_check_status((unsigned long) host); | ||||
| } | ||||
|  | @ -1150,7 +1171,6 @@ msmsdcc_probe(struct platform_device *pdev) | |||
| 	struct msmsdcc_host *host; | ||||
| 	struct mmc_host *mmc; | ||||
| 	struct resource *cmd_irqres = NULL; | ||||
| 	struct resource *pio_irqres = NULL; | ||||
| 	struct resource *stat_irqres = NULL; | ||||
| 	struct resource *memres = NULL; | ||||
| 	struct resource *dmares = NULL; | ||||
|  | @ -1175,12 +1195,10 @@ msmsdcc_probe(struct platform_device *pdev) | |||
| 	dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||||
| 	cmd_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, | ||||
| 						  "cmd_irq"); | ||||
| 	pio_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, | ||||
| 						  "pio_irq"); | ||||
| 	stat_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, | ||||
| 						   "status_irq"); | ||||
| 
 | ||||
| 	if (!cmd_irqres || !pio_irqres || !memres) { | ||||
| 	if (!cmd_irqres || !memres) { | ||||
| 		pr_err("%s: Invalid resource\n", __func__); | ||||
| 		return -ENXIO; | ||||
| 	} | ||||
|  | @ -1200,17 +1218,20 @@ msmsdcc_probe(struct platform_device *pdev) | |||
| 	host->plat = plat; | ||||
| 	host->mmc = mmc; | ||||
| 	host->curr.cmd = NULL; | ||||
| 	init_timer(&host->busclk_timer); | ||||
| 	host->busclk_timer.data = (unsigned long) host; | ||||
| 	host->busclk_timer.function = msmsdcc_busclk_expired; | ||||
| 
 | ||||
| 
 | ||||
| 	host->cmdpoll = 1; | ||||
| 
 | ||||
| 	host->base = ioremap(memres->start, PAGE_SIZE); | ||||
| 	if (!host->base) { | ||||
| 		ret = -ENOMEM; | ||||
| 		goto out; | ||||
| 		goto host_free; | ||||
| 	} | ||||
| 
 | ||||
| 	host->cmd_irqres = cmd_irqres; | ||||
| 	host->pio_irqres = pio_irqres; | ||||
| 	host->memres = memres; | ||||
| 	host->dmares = dmares; | ||||
| 	spin_lock_init(&host->lock); | ||||
|  | @ -1221,13 +1242,19 @@ msmsdcc_probe(struct platform_device *pdev) | |||
| 	/*
 | ||||
| 	 * Setup DMA | ||||
| 	 */ | ||||
| 	msmsdcc_init_dma(host); | ||||
| 	if (host->dmares) { | ||||
| 		ret = msmsdcc_init_dma(host); | ||||
| 		if (ret) | ||||
| 			goto ioremap_free; | ||||
| 	} else { | ||||
| 		host->dma.channel = -1; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Get our clocks */ | ||||
| 	host->pclk = clk_get(&pdev->dev, "sdc_pclk"); | ||||
| 	if (IS_ERR(host->pclk)) { | ||||
| 		ret = PTR_ERR(host->pclk); | ||||
| 		goto host_free; | ||||
| 		goto dma_free; | ||||
| 	} | ||||
| 
 | ||||
| 	host->clk = clk_get(&pdev->dev, "sdc_clk"); | ||||
|  | @ -1236,17 +1263,17 @@ msmsdcc_probe(struct platform_device *pdev) | |||
| 		goto pclk_put; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = clk_set_rate(host->clk, msmsdcc_fmin); | ||||
| 	if (ret) { | ||||
| 		pr_err("%s: Clock rate set failed (%d)\n", __func__, ret); | ||||
| 		goto clk_put; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Enable clocks */ | ||||
| 	ret = msmsdcc_enable_clocks(host); | ||||
| 	if (ret) | ||||
| 		goto clk_put; | ||||
| 
 | ||||
| 	ret = clk_set_rate(host->clk, msmsdcc_fmin); | ||||
| 	if (ret) { | ||||
| 		pr_err("%s: Clock rate set failed (%d)\n", __func__, ret); | ||||
| 		goto clk_disable; | ||||
| 	} | ||||
| 
 | ||||
| 	host->pclk_rate = clk_get_rate(host->pclk); | ||||
| 	host->clk_rate = clk_get_rate(host->clk); | ||||
| 
 | ||||
|  | @ -1316,16 +1343,12 @@ msmsdcc_probe(struct platform_device *pdev) | |||
| 		host->eject = !host->oldstat; | ||||
| 	} | ||||
| 
 | ||||
| 	init_timer(&host->busclk_timer); | ||||
| 	host->busclk_timer.data = (unsigned long) host; | ||||
| 	host->busclk_timer.function = msmsdcc_busclk_expired; | ||||
| 
 | ||||
| 	ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, | ||||
| 			  DRIVER_NAME " (cmd)", host); | ||||
| 	if (ret) | ||||
| 		goto stat_irq_free; | ||||
| 
 | ||||
| 	ret = request_irq(pio_irqres->start, msmsdcc_pio_irq, IRQF_SHARED, | ||||
| 	ret = request_irq(cmd_irqres->start, msmsdcc_pio_irq, IRQF_SHARED, | ||||
| 			  DRIVER_NAME " (pio)", host); | ||||
| 	if (ret) | ||||
| 		goto cmd_irq_free; | ||||
|  | @ -1368,6 +1391,13 @@ msmsdcc_probe(struct platform_device *pdev) | |||
| 	clk_put(host->clk); | ||||
|  pclk_put: | ||||
| 	clk_put(host->pclk); | ||||
| dma_free: | ||||
| 	if (host->dmares) | ||||
| 		dma_free_coherent(NULL, sizeof(struct msmsdcc_nc_dmadata), | ||||
| 					host->dma.nc, host->dma.nc_busaddr); | ||||
| ioremap_free: | ||||
| 	tasklet_kill(&host->dma_tlet); | ||||
| 	iounmap(host->base); | ||||
|  host_free: | ||||
| 	mmc_free_host(mmc); | ||||
|  out: | ||||
|  |  | |||
|  | @ -140,6 +140,11 @@ | |||
| 	MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK|	\ | ||||
| 	MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATAENDMASK|MCI_PROGDONEMASK) | ||||
| 
 | ||||
| #define MCI_IRQ_PIO \ | ||||
| 	(MCI_RXDATAAVLBLMASK | MCI_TXDATAAVLBLMASK | MCI_RXFIFOEMPTYMASK | \ | ||||
| 	 MCI_TXFIFOEMPTYMASK | MCI_RXFIFOFULLMASK | MCI_TXFIFOFULLMASK | \ | ||||
| 	 MCI_RXFIFOHALFFULLMASK | MCI_TXFIFOHALFEMPTYMASK | \ | ||||
| 	 MCI_RXACTIVEMASK | MCI_TXACTIVEMASK) | ||||
| /*
 | ||||
|  * The size of the FIFO in bytes. | ||||
|  */ | ||||
|  | @ -202,7 +207,6 @@ struct msmsdcc_stats { | |||
| 
 | ||||
| struct msmsdcc_host { | ||||
| 	struct resource		*cmd_irqres; | ||||
| 	struct resource		*pio_irqres; | ||||
| 	struct resource		*memres; | ||||
| 	struct resource		*dmares; | ||||
| 	void __iomem		*base; | ||||
|  |  | |||
|  | @ -117,7 +117,7 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data) | |||
| 		host->pio_size = data->blocks * data->blksz; | ||||
| 		host->pio_ptr = sg_virt(data->sg); | ||||
| 		if (!nodma) | ||||
| 			printk(KERN_DEBUG "%s: fallback to PIO for data " | ||||
| 			pr_debug("%s: fallback to PIO for data " | ||||
| 					  "at 0x%p size %d\n", | ||||
| 					  mmc_hostname(host->mmc), | ||||
| 					  host->pio_ptr, host->pio_size); | ||||
|  | @ -471,7 +471,7 @@ static irqreturn_t mvsd_irq(int irq, void *dev) | |||
| 		if (mrq->data) | ||||
| 			err_status = mvsd_finish_data(host, mrq->data, err_status); | ||||
| 		if (err_status) { | ||||
| 			printk(KERN_ERR "%s: unhandled error status %#04x\n", | ||||
| 			pr_err("%s: unhandled error status %#04x\n", | ||||
| 					mmc_hostname(host->mmc), err_status); | ||||
| 			cmd->error = -ENOMSG; | ||||
| 		} | ||||
|  | @ -489,7 +489,7 @@ static irqreturn_t mvsd_irq(int irq, void *dev) | |||
| 	if (irq_handled) | ||||
| 		return IRQ_HANDLED; | ||||
| 
 | ||||
| 	printk(KERN_ERR "%s: unhandled interrupt status=0x%04x en=0x%04x " | ||||
| 	pr_err("%s: unhandled interrupt status=0x%04x en=0x%04x " | ||||
| 			"pio=%d\n", mmc_hostname(host->mmc), intr_status, | ||||
| 			host->intr_en, host->pio_size); | ||||
| 	return IRQ_NONE; | ||||
|  | @ -505,9 +505,9 @@ static void mvsd_timeout_timer(unsigned long data) | |||
| 	spin_lock_irqsave(&host->lock, flags); | ||||
| 	mrq = host->mrq; | ||||
| 	if (mrq) { | ||||
| 		printk(KERN_ERR "%s: Timeout waiting for hardware interrupt.\n", | ||||
| 		pr_err("%s: Timeout waiting for hardware interrupt.\n", | ||||
| 				mmc_hostname(host->mmc)); | ||||
| 		printk(KERN_ERR "%s: hw_state=0x%04x, intr_status=0x%04x " | ||||
| 		pr_err("%s: hw_state=0x%04x, intr_status=0x%04x " | ||||
| 				"intr_en=0x%04x\n", mmc_hostname(host->mmc), | ||||
| 				mvsd_read(MVSD_HW_STATE), | ||||
| 				mvsd_read(MVSD_NOR_INTR_STATUS), | ||||
|  | @ -762,7 +762,7 @@ static int __init mvsd_probe(struct platform_device *pdev) | |||
| 
 | ||||
| 	ret = request_irq(irq, mvsd_irq, 0, DRIVER_NAME, host); | ||||
| 	if (ret) { | ||||
| 		printk(KERN_ERR "%s: cannot assign irq %d\n", DRIVER_NAME, irq); | ||||
| 		pr_err("%s: cannot assign irq %d\n", DRIVER_NAME, irq); | ||||
| 		goto out; | ||||
| 	} else | ||||
| 		host->irq = irq; | ||||
|  | @ -802,7 +802,7 @@ static int __init mvsd_probe(struct platform_device *pdev) | |||
| 	if (ret) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	printk(KERN_NOTICE "%s: %s driver initialized, ", | ||||
| 	pr_notice("%s: %s driver initialized, ", | ||||
| 			   mmc_hostname(mmc), DRIVER_NAME); | ||||
| 	if (host->gpio_card_detect) | ||||
| 		printk("using GPIO %d for card detection\n", | ||||
|  |  | |||
|  | @ -842,7 +842,7 @@ static int mxcmci_probe(struct platform_device *pdev) | |||
| 	int ret = 0, irq; | ||||
| 	dma_cap_mask_t mask; | ||||
| 
 | ||||
| 	printk(KERN_INFO "i.MX SDHC driver\n"); | ||||
| 	pr_info("i.MX SDHC driver\n"); | ||||
| 
 | ||||
| 	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||||
| 	irq = platform_get_irq(pdev, 0); | ||||
|  |  | |||
|  | @ -37,6 +37,7 @@ | |||
| #include <linux/mmc/sdio.h> | ||||
| #include <linux/gpio.h> | ||||
| #include <linux/regulator/consumer.h> | ||||
| #include <linux/module.h> | ||||
| 
 | ||||
| #include <mach/mxs.h> | ||||
| #include <mach/common.h> | ||||
|  |  | |||
|  | @ -450,15 +450,14 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) | |||
| 		* framework is fixed, we need a workaround like this | ||||
| 		* (which is safe for MMC, but not in general). | ||||
| 		*/ | ||||
| 		if (regulator_is_enabled(host->vcc) > 0) { | ||||
| 			regulator_enable(host->vcc); | ||||
| 			regulator_disable(host->vcc); | ||||
| 		} | ||||
| 		if (host->vcc_aux) { | ||||
| 			if (regulator_is_enabled(reg) > 0) { | ||||
| 				regulator_enable(reg); | ||||
| 				regulator_disable(reg); | ||||
| 			} | ||||
| 		if (regulator_is_enabled(host->vcc) > 0 || | ||||
| 		    (host->vcc_aux && regulator_is_enabled(host->vcc_aux))) { | ||||
| 			int vdd = ffs(mmc_slot(host).ocr_mask) - 1; | ||||
| 
 | ||||
| 			mmc_slot(host).set_power(host->dev, host->slot_id, | ||||
| 						 1, vdd); | ||||
| 			mmc_slot(host).set_power(host->dev, host->slot_id, | ||||
| 						 0, 0); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -1264,14 +1263,14 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host) | |||
| 	host->reqs_blocked = 0; | ||||
| 	if (mmc_slot(host).get_cover_state(host->dev, host->slot_id)) { | ||||
| 		if (host->protect_card) { | ||||
| 			printk(KERN_INFO "%s: cover is closed, " | ||||
| 			pr_info("%s: cover is closed, " | ||||
| 					 "card is now accessible\n", | ||||
| 					 mmc_hostname(host->mmc)); | ||||
| 			host->protect_card = 0; | ||||
| 		} | ||||
| 	} else { | ||||
| 		if (!host->protect_card) { | ||||
| 			printk(KERN_INFO "%s: cover is open, " | ||||
| 			pr_info"%s: cover is open, " | ||||
| 					 "card is now inaccessible\n", | ||||
| 					 mmc_hostname(host->mmc)); | ||||
| 			host->protect_card = 1; | ||||
|  | @ -1422,7 +1421,7 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host, | |||
| 
 | ||||
| 	if (!next && data->host_cookie && | ||||
| 	    data->host_cookie != host->next_data.cookie) { | ||||
| 		printk(KERN_WARNING "[%s] invalid cookie: data->host_cookie %d" | ||||
| 		pr_warning("[%s] invalid cookie: data->host_cookie %d" | ||||
| 		       " host->next_data.cookie %d\n", | ||||
| 		       __func__, data->host_cookie, host->next_data.cookie); | ||||
| 		data->host_cookie = 0; | ||||
|  | @ -1943,6 +1942,10 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) | |||
| 	omap_hsmmc_context_save(host); | ||||
| 
 | ||||
| 	mmc->caps |= MMC_CAP_DISABLE; | ||||
| 	if (host->pdata->controller_flags & OMAP_HSMMC_BROKEN_MULTIBLOCK_READ) { | ||||
| 		dev_info(&pdev->dev, "multiblock reads disabled due to 35xx erratum 2.1.1.128; MMC read performance may suffer\n"); | ||||
| 		mmc->caps2 |= MMC_CAP2_NO_MULTI_READ; | ||||
| 	} | ||||
| 
 | ||||
| 	pm_runtime_enable(host->dev); | ||||
| 	pm_runtime_get_sync(host->dev); | ||||
|  | @ -2015,7 +2018,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) | |||
| 	} | ||||
| 
 | ||||
| 	/* Request IRQ for MMC operations */ | ||||
| 	ret = request_irq(host->irq, omap_hsmmc_irq, IRQF_DISABLED, | ||||
| 	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"); | ||||
|  | @ -2043,8 +2046,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) | |||
| 	if ((mmc_slot(host).card_detect_irq)) { | ||||
| 		ret = request_irq(mmc_slot(host).card_detect_irq, | ||||
| 				  omap_hsmmc_cd_handler, | ||||
| 				  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | ||||
| 					  | IRQF_DISABLED, | ||||
| 				  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, | ||||
| 				  mmc_hostname(mmc), host); | ||||
| 		if (ret) { | ||||
| 			dev_dbg(mmc_dev(host->mmc), | ||||
|  |  | |||
|  | @ -558,7 +558,7 @@ static void pxamci_dma_irq(int dma, void *devid) | |||
| 	if (dcsr & DCSR_ENDINTR) { | ||||
| 		writel(BUF_PART_FULL, host->base + MMC_PRTBUF); | ||||
| 	} else { | ||||
| 		printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n", | ||||
| 		pr_err("%s: DMA error on channel %d (DCSR=%#x)\n", | ||||
| 		       mmc_hostname(host->mmc), dma, dcsr); | ||||
| 		host->data->error = -EIO; | ||||
| 		pxamci_data_done(host, 0); | ||||
|  |  | |||
|  | @ -247,7 +247,7 @@ static void s3cmci_check_sdio_irq(struct s3cmci_host *host) | |||
| { | ||||
| 	if (host->sdio_irqen) { | ||||
| 		if (gpio_get_value(S3C2410_GPE(8)) == 0) { | ||||
| 			printk(KERN_DEBUG "%s: signalling irq\n", __func__); | ||||
| 			pr_debug("%s: signalling irq\n", __func__); | ||||
| 			mmc_signal_sdio_irq(host->mmc); | ||||
| 		} | ||||
| 	} | ||||
|  | @ -344,7 +344,7 @@ static void s3cmci_disable_irq(struct s3cmci_host *host, bool transfer) | |||
| 
 | ||||
| 	local_irq_save(flags); | ||||
| 
 | ||||
| 	//printk(KERN_DEBUG "%s: transfer %d\n", __func__, transfer);
 | ||||
| 	/* pr_debug("%s: transfer %d\n", __func__, transfer); */ | ||||
| 
 | ||||
| 	host->irq_disabled = transfer; | ||||
| 
 | ||||
|  |  | |||
|  | @ -32,6 +32,15 @@ | |||
| /* VENDOR SPEC register */ | ||||
| #define SDHCI_VENDOR_SPEC		0xC0 | ||||
| #define  SDHCI_VENDOR_SPEC_SDIO_QUIRK	0x00000002 | ||||
| #define SDHCI_MIX_CTRL			0x48 | ||||
| 
 | ||||
| /*
 | ||||
|  * There is an INT DMA ERR mis-match between eSDHC and STD SDHC SPEC: | ||||
|  * Bit25 is used in STD SPEC, and is reserved in fsl eSDHC design, | ||||
|  * but bit28 is used as the INT DMA ERR in fsl eSDHC design. | ||||
|  * Define this macro DMA error INT for fsl eSDHC | ||||
|  */ | ||||
| #define SDHCI_INT_VENDOR_SPEC_DMA_ERR	0x10000000 | ||||
| 
 | ||||
| /*
 | ||||
|  * The CMDTYPE of the CMD register (offset 0xE) should be set to | ||||
|  | @ -51,6 +60,7 @@ enum imx_esdhc_type { | |||
| 	IMX35_ESDHC, | ||||
| 	IMX51_ESDHC, | ||||
| 	IMX53_ESDHC, | ||||
| 	IMX6Q_USDHC, | ||||
| }; | ||||
| 
 | ||||
| struct pltfm_imx_data { | ||||
|  | @ -73,6 +83,9 @@ static struct platform_device_id imx_esdhc_devtype[] = { | |||
| 	}, { | ||||
| 		.name = "sdhci-esdhc-imx53", | ||||
| 		.driver_data = IMX53_ESDHC, | ||||
| 	}, { | ||||
| 		.name = "sdhci-usdhc-imx6q", | ||||
| 		.driver_data = IMX6Q_USDHC, | ||||
| 	}, { | ||||
| 		/* sentinel */ | ||||
| 	} | ||||
|  | @ -84,6 +97,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = { | |||
| 	{ .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], }, | ||||
| 	{ .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], }, | ||||
| 	{ .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], }, | ||||
| 	{ .compatible = "fsl,imx6q-usdhc", .data = &imx_esdhc_devtype[IMX6Q_USDHC], }, | ||||
| 	{ /* sentinel */ } | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); | ||||
|  | @ -108,6 +122,11 @@ static inline int is_imx53_esdhc(struct pltfm_imx_data *data) | |||
| 	return data->devtype == IMX53_ESDHC; | ||||
| } | ||||
| 
 | ||||
| static inline int is_imx6q_usdhc(struct pltfm_imx_data *data) | ||||
| { | ||||
| 	return data->devtype == IMX6Q_USDHC; | ||||
| } | ||||
| 
 | ||||
| static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) | ||||
| { | ||||
| 	void __iomem *base = host->ioaddr + (reg & ~0x3); | ||||
|  | @ -135,6 +154,27 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) | |||
| 			val |= SDHCI_CARD_PRESENT; | ||||
| 	} | ||||
| 
 | ||||
| 	if (unlikely(reg == SDHCI_CAPABILITIES)) { | ||||
| 		/* In FSL esdhc IC module, only bit20 is used to indicate the
 | ||||
| 		 * ADMA2 capability of esdhc, but this bit is messed up on | ||||
| 		 * some SOCs (e.g. on MX25, MX35 this bit is set, but they | ||||
| 		 * don't actually support ADMA2). So set the BROKEN_ADMA | ||||
| 		 * uirk on MX25/35 platforms. | ||||
| 		 */ | ||||
| 
 | ||||
| 		if (val & SDHCI_CAN_DO_ADMA1) { | ||||
| 			val &= ~SDHCI_CAN_DO_ADMA1; | ||||
| 			val |= SDHCI_CAN_DO_ADMA2; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (unlikely(reg == SDHCI_INT_STATUS)) { | ||||
| 		if (val & SDHCI_INT_VENDOR_SPEC_DMA_ERR) { | ||||
| 			val &= ~SDHCI_INT_VENDOR_SPEC_DMA_ERR; | ||||
| 			val |= SDHCI_INT_ADMA_ERROR; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return val; | ||||
| } | ||||
| 
 | ||||
|  | @ -179,13 +219,28 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) | |||
| 			writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); | ||||
| 	} | ||||
| 
 | ||||
| 	if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) { | ||||
| 		if (val & SDHCI_INT_ADMA_ERROR) { | ||||
| 			val &= ~SDHCI_INT_ADMA_ERROR; | ||||
| 			val |= SDHCI_INT_VENDOR_SPEC_DMA_ERR; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	writel(val, host->ioaddr + reg); | ||||
| } | ||||
| 
 | ||||
| static u16 esdhc_readw_le(struct sdhci_host *host, int reg) | ||||
| { | ||||
| 	if (unlikely(reg == SDHCI_HOST_VERSION)) | ||||
| 		reg ^= 2; | ||||
| 	if (unlikely(reg == SDHCI_HOST_VERSION)) { | ||||
| 		u16 val = readw(host->ioaddr + (reg ^ 2)); | ||||
| 		/*
 | ||||
| 		 * uSDHC supports SDHCI v3.0, but it's encoded as value | ||||
| 		 * 0x3 in host controller version register, which violates | ||||
| 		 * SDHCI_SPEC_300 definition.  Work it around here. | ||||
| 		 */ | ||||
| 		if ((val & SDHCI_SPEC_VER_MASK) == 3) | ||||
| 			return --val; | ||||
| 	} | ||||
| 
 | ||||
| 	return readw(host->ioaddr + reg); | ||||
| } | ||||
|  | @ -216,8 +271,17 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) | |||
| 		if ((host->cmd->opcode == MMC_STOP_TRANSMISSION) | ||||
| 			&& (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) | ||||
| 			val |= SDHCI_CMD_ABORTCMD; | ||||
| 		writel(val << 16 | imx_data->scratchpad, | ||||
| 			host->ioaddr + SDHCI_TRANSFER_MODE); | ||||
| 
 | ||||
| 		if (is_imx6q_usdhc(imx_data)) { | ||||
| 			u32 m = readl(host->ioaddr + SDHCI_MIX_CTRL); | ||||
| 			m = imx_data->scratchpad | (m & 0xffff0000); | ||||
| 			writel(m, host->ioaddr + SDHCI_MIX_CTRL); | ||||
| 			writel(val << 16, | ||||
| 			       host->ioaddr + SDHCI_TRANSFER_MODE); | ||||
| 		} else { | ||||
| 			writel(val << 16 | imx_data->scratchpad, | ||||
| 			       host->ioaddr + SDHCI_TRANSFER_MODE); | ||||
| 		} | ||||
| 		return; | ||||
| 	case SDHCI_BLOCK_SIZE: | ||||
| 		val &= ~SDHCI_MAKE_BLKSZ(0x7, 0); | ||||
|  | @ -311,9 +375,10 @@ static struct sdhci_ops sdhci_esdhc_ops = { | |||
| }; | ||||
| 
 | ||||
| static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { | ||||
| 	.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA | ||||
| 	.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_HISPD_BIT | ||||
| 			| SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | ||||
| 			| SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | ||||
| 			| SDHCI_QUIRK_BROKEN_CARD_DETECTION, | ||||
| 	/* ADMA has issues. Might be fixable */ | ||||
| 	.ops = &sdhci_esdhc_ops, | ||||
| }; | ||||
| 
 | ||||
|  | @ -405,7 +470,8 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) | |||
| 
 | ||||
| 	if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data)) | ||||
| 		/* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */ | ||||
| 		host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK; | ||||
| 		host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK | ||||
| 			| SDHCI_QUIRK_BROKEN_ADMA; | ||||
| 
 | ||||
| 	if (is_imx53_esdhc(imx_data)) | ||||
| 		imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| /*
 | ||||
|  * Freescale eSDHC controller driver. | ||||
|  * | ||||
|  * Copyright (c) 2007 Freescale Semiconductor, Inc. | ||||
|  * Copyright (c) 2007, 2010 Freescale Semiconductor, Inc. | ||||
|  * Copyright (c) 2009 MontaVista Software, Inc. | ||||
|  * | ||||
|  * Authors: Xiaobo Xie <X.Xie@freescale.com> | ||||
|  | @ -15,6 +15,7 @@ | |||
| 
 | ||||
| #include <linux/io.h> | ||||
| #include <linux/delay.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/mmc/host.h> | ||||
| #include "sdhci-pltfm.h" | ||||
| #include "sdhci-esdhc.h" | ||||
|  | @ -22,11 +23,21 @@ | |||
| static u16 esdhc_readw(struct sdhci_host *host, int reg) | ||||
| { | ||||
| 	u16 ret; | ||||
| 	int base = reg & ~0x3; | ||||
| 	int shift = (reg & 0x2) * 8; | ||||
| 
 | ||||
| 	if (unlikely(reg == SDHCI_HOST_VERSION)) | ||||
| 		ret = in_be16(host->ioaddr + reg); | ||||
| 		ret = in_be32(host->ioaddr + base) & 0xffff; | ||||
| 	else | ||||
| 		ret = sdhci_be32bs_readw(host, reg); | ||||
| 		ret = (in_be32(host->ioaddr + base) >> shift) & 0xffff; | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static u8 esdhc_readb(struct sdhci_host *host, int reg) | ||||
| { | ||||
| 	int base = reg & ~0x3; | ||||
| 	int shift = (reg & 0x3) * 8; | ||||
| 	u8 ret = (in_be32(host->ioaddr + base) >> shift) & 0xff; | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
|  | @ -74,7 +85,7 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host) | |||
| static struct sdhci_ops sdhci_esdhc_ops = { | ||||
| 	.read_l = sdhci_be32bs_readl, | ||||
| 	.read_w = esdhc_readw, | ||||
| 	.read_b = sdhci_be32bs_readb, | ||||
| 	.read_b = esdhc_readb, | ||||
| 	.write_l = sdhci_be32bs_writel, | ||||
| 	.write_w = esdhc_writew, | ||||
| 	.write_b = esdhc_writeb, | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ | |||
|  */ | ||||
| 
 | ||||
| #include <linux/delay.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/mmc/host.h> | ||||
| #include "sdhci-pltfm.h" | ||||
| 
 | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ | |||
| 
 | ||||
| #include <linux/delay.h> | ||||
| #include <linux/highmem.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/pci.h> | ||||
| #include <linux/dma-mapping.h> | ||||
| #include <linux/slab.h> | ||||
|  | @ -21,6 +22,9 @@ | |||
| #include <linux/mmc/host.h> | ||||
| #include <linux/scatterlist.h> | ||||
| #include <linux/io.h> | ||||
| #include <linux/gpio.h> | ||||
| #include <linux/sfi.h> | ||||
| #include <linux/pm_runtime.h> | ||||
| 
 | ||||
| #include "sdhci.h" | ||||
| 
 | ||||
|  | @ -43,6 +47,7 @@ struct sdhci_pci_slot; | |||
| 
 | ||||
| struct sdhci_pci_fixes { | ||||
| 	unsigned int		quirks; | ||||
| 	bool			allow_runtime_pm; | ||||
| 
 | ||||
| 	int			(*probe) (struct sdhci_pci_chip *); | ||||
| 
 | ||||
|  | @ -59,12 +64,16 @@ struct sdhci_pci_slot { | |||
| 	struct sdhci_host	*host; | ||||
| 
 | ||||
| 	int			pci_bar; | ||||
| 	int			rst_n_gpio; | ||||
| 	int			cd_gpio; | ||||
| 	int			cd_irq; | ||||
| }; | ||||
| 
 | ||||
| struct sdhci_pci_chip { | ||||
| 	struct pci_dev		*pdev; | ||||
| 
 | ||||
| 	unsigned int		quirks; | ||||
| 	bool			allow_runtime_pm; | ||||
| 	const struct sdhci_pci_fixes *fixes; | ||||
| 
 | ||||
| 	int			num_slots;	/* Slots on controller */ | ||||
|  | @ -163,12 +172,129 @@ static int mrst_hc_probe(struct sdhci_pci_chip *chip) | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* Medfield eMMC hardware reset GPIOs */ | ||||
| static int mfd_emmc0_rst_gpio = -EINVAL; | ||||
| static int mfd_emmc1_rst_gpio = -EINVAL; | ||||
| 
 | ||||
| static int mfd_emmc_gpio_parse(struct sfi_table_header *table) | ||||
| { | ||||
| 	struct sfi_table_simple *sb = (struct sfi_table_simple *)table; | ||||
| 	struct sfi_gpio_table_entry *entry; | ||||
| 	int i, num; | ||||
| 
 | ||||
| 	num = SFI_GET_NUM_ENTRIES(sb, struct sfi_gpio_table_entry); | ||||
| 	entry = (struct sfi_gpio_table_entry *)sb->pentry; | ||||
| 
 | ||||
| 	for (i = 0; i < num; i++, entry++) { | ||||
| 		if (!strncmp(entry->pin_name, "emmc0_rst", SFI_NAME_LEN)) | ||||
| 			mfd_emmc0_rst_gpio = entry->pin_no; | ||||
| 		else if (!strncmp(entry->pin_name, "emmc1_rst", SFI_NAME_LEN)) | ||||
| 			mfd_emmc1_rst_gpio = entry->pin_no; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_PM_RUNTIME | ||||
| 
 | ||||
| static irqreturn_t mfd_sd_cd(int irq, void *dev_id) | ||||
| { | ||||
| 	struct sdhci_pci_slot *slot = dev_id; | ||||
| 	struct sdhci_host *host = slot->host; | ||||
| 
 | ||||
| 	mmc_detect_change(host->mmc, msecs_to_jiffies(200)); | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
| 
 | ||||
| #define MFLD_SD_CD_PIN 69 | ||||
| 
 | ||||
| static int mfd_sd_probe_slot(struct sdhci_pci_slot *slot) | ||||
| { | ||||
| 	int err, irq, gpio = MFLD_SD_CD_PIN; | ||||
| 
 | ||||
| 	slot->cd_gpio = -EINVAL; | ||||
| 	slot->cd_irq = -EINVAL; | ||||
| 
 | ||||
| 	err = gpio_request(gpio, "sd_cd"); | ||||
| 	if (err < 0) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	err = gpio_direction_input(gpio); | ||||
| 	if (err < 0) | ||||
| 		goto out_free; | ||||
| 
 | ||||
| 	irq = gpio_to_irq(gpio); | ||||
| 	if (irq < 0) | ||||
| 		goto out_free; | ||||
| 
 | ||||
| 	err = request_irq(irq, mfd_sd_cd, IRQF_TRIGGER_RISING | | ||||
| 			  IRQF_TRIGGER_FALLING, "sd_cd", slot); | ||||
| 	if (err) | ||||
| 		goto out_free; | ||||
| 
 | ||||
| 	slot->cd_gpio = gpio; | ||||
| 	slot->cd_irq = irq; | ||||
| 	slot->host->quirks2 |= SDHCI_QUIRK2_OWN_CARD_DETECTION; | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| out_free: | ||||
| 	gpio_free(gpio); | ||||
| out: | ||||
| 	dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n"); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void mfd_sd_remove_slot(struct sdhci_pci_slot *slot, int dead) | ||||
| { | ||||
| 	if (slot->cd_irq >= 0) | ||||
| 		free_irq(slot->cd_irq, slot); | ||||
| 	gpio_free(slot->cd_gpio); | ||||
| } | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| #define mfd_sd_probe_slot	NULL | ||||
| #define mfd_sd_remove_slot	NULL | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) | ||||
| { | ||||
| 	slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA; | ||||
| 	const char *name = NULL; | ||||
| 	int gpio = -EINVAL; | ||||
| 
 | ||||
| 	sfi_table_parse(SFI_SIG_GPIO, NULL, NULL, mfd_emmc_gpio_parse); | ||||
| 
 | ||||
| 	switch (slot->chip->pdev->device) { | ||||
| 	case PCI_DEVICE_ID_INTEL_MFD_EMMC0: | ||||
| 		gpio = mfd_emmc0_rst_gpio; | ||||
| 		name = "eMMC0_reset"; | ||||
| 		break; | ||||
| 	case PCI_DEVICE_ID_INTEL_MFD_EMMC1: | ||||
| 		gpio = mfd_emmc1_rst_gpio; | ||||
| 		name = "eMMC1_reset"; | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!gpio_request(gpio, name)) { | ||||
| 		gpio_direction_output(gpio, 1); | ||||
| 		slot->rst_n_gpio = gpio; | ||||
| 		slot->host->mmc->caps |= MMC_CAP_HW_RESET; | ||||
| 	} | ||||
| 
 | ||||
| 	slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE; | ||||
| 
 | ||||
| 	slot->host->mmc->caps2 = MMC_CAP2_BOOTPART_NOACC; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void mfd_emmc_remove_slot(struct sdhci_pci_slot *slot, int dead) | ||||
| { | ||||
| 	gpio_free(slot->rst_n_gpio); | ||||
| } | ||||
| 
 | ||||
| static const struct sdhci_pci_fixes sdhci_intel_mrst_hc0 = { | ||||
| 	.quirks		= SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_NO_HISPD_BIT, | ||||
| 	.probe_slot	= mrst_hc_probe_slot, | ||||
|  | @ -181,15 +307,21 @@ static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = { | |||
| 
 | ||||
| static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = { | ||||
| 	.quirks		= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, | ||||
| 	.allow_runtime_pm = true, | ||||
| 	.probe_slot	= mfd_sd_probe_slot, | ||||
| 	.remove_slot	= mfd_sd_remove_slot, | ||||
| }; | ||||
| 
 | ||||
| static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = { | ||||
| 	.quirks		= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, | ||||
| 	.allow_runtime_pm = true, | ||||
| }; | ||||
| 
 | ||||
| static const struct sdhci_pci_fixes sdhci_intel_mfd_emmc = { | ||||
| 	.quirks		= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, | ||||
| 	.allow_runtime_pm = true, | ||||
| 	.probe_slot	= mfd_emmc_probe_slot, | ||||
| 	.remove_slot	= mfd_emmc_remove_slot, | ||||
| }; | ||||
| 
 | ||||
| /* O2Micro extra registers */ | ||||
|  | @ -832,9 +964,25 @@ static int sdhci_pci_8bit_width(struct sdhci_host *host, int width) | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void sdhci_pci_hw_reset(struct sdhci_host *host) | ||||
| { | ||||
| 	struct sdhci_pci_slot *slot = sdhci_priv(host); | ||||
| 	int rst_n_gpio = slot->rst_n_gpio; | ||||
| 
 | ||||
| 	if (!gpio_is_valid(rst_n_gpio)) | ||||
| 		return; | ||||
| 	gpio_set_value_cansleep(rst_n_gpio, 0); | ||||
| 	/* For eMMC, minimum is 1us but give it 10us for good measure */ | ||||
| 	udelay(10); | ||||
| 	gpio_set_value_cansleep(rst_n_gpio, 1); | ||||
| 	/* For eMMC, minimum is 200us but give it 300us for good measure */ | ||||
| 	usleep_range(300, 1000); | ||||
| } | ||||
| 
 | ||||
| static struct sdhci_ops sdhci_pci_ops = { | ||||
| 	.enable_dma	= sdhci_pci_enable_dma, | ||||
| 	.platform_8bit_width	= sdhci_pci_8bit_width, | ||||
| 	.hw_reset		= sdhci_pci_hw_reset, | ||||
| }; | ||||
| 
 | ||||
| /*****************************************************************************\
 | ||||
|  | @ -944,6 +1092,95 @@ static int sdhci_pci_resume(struct pci_dev *pdev) | |||
| 
 | ||||
| #endif /* CONFIG_PM */ | ||||
| 
 | ||||
| #ifdef CONFIG_PM_RUNTIME | ||||
| 
 | ||||
| static int sdhci_pci_runtime_suspend(struct device *dev) | ||||
| { | ||||
| 	struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); | ||||
| 	struct sdhci_pci_chip *chip; | ||||
| 	struct sdhci_pci_slot *slot; | ||||
| 	pm_message_t state = { .event = PM_EVENT_SUSPEND }; | ||||
| 	int i, ret; | ||||
| 
 | ||||
| 	chip = pci_get_drvdata(pdev); | ||||
| 	if (!chip) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	for (i = 0; i < chip->num_slots; i++) { | ||||
| 		slot = chip->slots[i]; | ||||
| 		if (!slot) | ||||
| 			continue; | ||||
| 
 | ||||
| 		ret = sdhci_runtime_suspend_host(slot->host); | ||||
| 
 | ||||
| 		if (ret) { | ||||
| 			for (i--; i >= 0; i--) | ||||
| 				sdhci_runtime_resume_host(chip->slots[i]->host); | ||||
| 			return ret; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (chip->fixes && chip->fixes->suspend) { | ||||
| 		ret = chip->fixes->suspend(chip, state); | ||||
| 		if (ret) { | ||||
| 			for (i = chip->num_slots - 1; i >= 0; i--) | ||||
| 				sdhci_runtime_resume_host(chip->slots[i]->host); | ||||
| 			return ret; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int sdhci_pci_runtime_resume(struct device *dev) | ||||
| { | ||||
| 	struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); | ||||
| 	struct sdhci_pci_chip *chip; | ||||
| 	struct sdhci_pci_slot *slot; | ||||
| 	int i, ret; | ||||
| 
 | ||||
| 	chip = pci_get_drvdata(pdev); | ||||
| 	if (!chip) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (chip->fixes && chip->fixes->resume) { | ||||
| 		ret = chip->fixes->resume(chip); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < chip->num_slots; i++) { | ||||
| 		slot = chip->slots[i]; | ||||
| 		if (!slot) | ||||
| 			continue; | ||||
| 
 | ||||
| 		ret = sdhci_runtime_resume_host(slot->host); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int sdhci_pci_runtime_idle(struct device *dev) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #else | ||||
| 
 | ||||
| #define sdhci_pci_runtime_suspend	NULL | ||||
| #define sdhci_pci_runtime_resume	NULL | ||||
| #define sdhci_pci_runtime_idle		NULL | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| static const struct dev_pm_ops sdhci_pci_pm_ops = { | ||||
| 	.runtime_suspend = sdhci_pci_runtime_suspend, | ||||
| 	.runtime_resume = sdhci_pci_runtime_resume, | ||||
| 	.runtime_idle = sdhci_pci_runtime_idle, | ||||
| }; | ||||
| 
 | ||||
| /*****************************************************************************\
 | ||||
|  *                                                                           * | ||||
|  * Device probing/removal                                                    * | ||||
|  | @ -988,6 +1225,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( | |||
| 	slot->chip = chip; | ||||
| 	slot->host = host; | ||||
| 	slot->pci_bar = bar; | ||||
| 	slot->rst_n_gpio = -EINVAL; | ||||
| 
 | ||||
| 	host->hw_name = "PCI"; | ||||
| 	host->ops = &sdhci_pci_ops; | ||||
|  | @ -1058,6 +1296,21 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) | |||
| 	sdhci_free_host(slot->host); | ||||
| } | ||||
| 
 | ||||
| static void __devinit sdhci_pci_runtime_pm_allow(struct device *dev) | ||||
| { | ||||
| 	pm_runtime_put_noidle(dev); | ||||
| 	pm_runtime_allow(dev); | ||||
| 	pm_runtime_set_autosuspend_delay(dev, 50); | ||||
| 	pm_runtime_use_autosuspend(dev); | ||||
| 	pm_suspend_ignore_children(dev, 1); | ||||
| } | ||||
| 
 | ||||
| static void __devexit sdhci_pci_runtime_pm_forbid(struct device *dev) | ||||
| { | ||||
| 	pm_runtime_forbid(dev); | ||||
| 	pm_runtime_get_noresume(dev); | ||||
| } | ||||
| 
 | ||||
| static int __devinit sdhci_pci_probe(struct pci_dev *pdev, | ||||
| 				     const struct pci_device_id *ent) | ||||
| { | ||||
|  | @ -1107,8 +1360,10 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev, | |||
| 
 | ||||
| 	chip->pdev = pdev; | ||||
| 	chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data; | ||||
| 	if (chip->fixes) | ||||
| 	if (chip->fixes) { | ||||
| 		chip->quirks = chip->fixes->quirks; | ||||
| 		chip->allow_runtime_pm = chip->fixes->allow_runtime_pm; | ||||
| 	} | ||||
| 	chip->num_slots = slots; | ||||
| 
 | ||||
| 	pci_set_drvdata(pdev, chip); | ||||
|  | @ -1133,6 +1388,9 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev, | |||
| 		chip->slots[i] = slot; | ||||
| 	} | ||||
| 
 | ||||
| 	if (chip->allow_runtime_pm) | ||||
| 		sdhci_pci_runtime_pm_allow(&pdev->dev); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| free: | ||||
|  | @ -1152,6 +1410,9 @@ static void __devexit sdhci_pci_remove(struct pci_dev *pdev) | |||
| 	chip = pci_get_drvdata(pdev); | ||||
| 
 | ||||
| 	if (chip) { | ||||
| 		if (chip->allow_runtime_pm) | ||||
| 			sdhci_pci_runtime_pm_forbid(&pdev->dev); | ||||
| 
 | ||||
| 		for (i = 0; i < chip->num_slots; i++) | ||||
| 			sdhci_pci_remove_slot(chip->slots[i]); | ||||
| 
 | ||||
|  | @ -1169,6 +1430,9 @@ static struct pci_driver sdhci_driver = { | |||
| 	.remove =	__devexit_p(sdhci_pci_remove), | ||||
| 	.suspend =	sdhci_pci_suspend, | ||||
| 	.resume	=	sdhci_pci_resume, | ||||
| 	.driver =	{ | ||||
| 		.pm =   &sdhci_pci_pm_ops | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| /*****************************************************************************\
 | ||||
|  |  | |||
|  | @ -29,6 +29,7 @@ | |||
|  */ | ||||
| 
 | ||||
| #include <linux/err.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/of.h> | ||||
| #ifdef CONFIG_PPC | ||||
| #include <asm/machdep.h> | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ | |||
| #include <linux/init.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/clk.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/io.h> | ||||
| #include <linux/gpio.h> | ||||
| #include <linux/mmc/card.h> | ||||
|  | @ -59,7 +60,7 @@ static void pxav2_set_private_registers(struct sdhci_host *host, u8 mask) | |||
| 		 * tune timing of read data/command when crc error happen | ||||
| 		 * no performance impact | ||||
| 		 */ | ||||
| 		if (pdata->clk_delay_sel == 1) { | ||||
| 		if (pdata && pdata->clk_delay_sel == 1) { | ||||
| 			tmp = readw(host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP); | ||||
| 
 | ||||
| 			tmp &= ~(SDCLK_DELAY_MASK << SDCLK_DELAY_SHIFT); | ||||
|  | @ -71,7 +72,7 @@ static void pxav2_set_private_registers(struct sdhci_host *host, u8 mask) | |||
| 			writew(tmp, host->ioaddr + SD_CLOCK_BURST_SIZE_SETUP); | ||||
| 		} | ||||
| 
 | ||||
| 		if (pdata->flags & PXA_FLAG_ENABLE_CLOCK_GATING) { | ||||
| 		if (pdata && (pdata->flags & PXA_FLAG_ENABLE_CLOCK_GATING)) { | ||||
| 			tmp = readw(host->ioaddr + SD_FIFO_PARAM); | ||||
| 			tmp &= ~CLK_GATE_SETTING_BITS; | ||||
| 			writew(tmp, host->ioaddr + SD_FIFO_PARAM); | ||||
|  |  | |||
|  | @ -27,6 +27,7 @@ | |||
| #include <linux/platform_data/pxa_sdhci.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/delay.h> | ||||
| #include <linux/module.h> | ||||
| #include "sdhci.h" | ||||
| #include "sdhci-pltfm.h" | ||||
| 
 | ||||
|  |  | |||
|  | @ -203,17 +203,23 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock) | |||
| 		writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); | ||||
| 	} | ||||
| 
 | ||||
| 	/* reconfigure the hardware for new clock rate */ | ||||
| 	/* reprogram default hardware configuration */ | ||||
| 	writel(S3C64XX_SDHCI_CONTROL4_DRIVE_9mA, | ||||
| 		host->ioaddr + S3C64XX_SDHCI_CONTROL4); | ||||
| 
 | ||||
| 	{ | ||||
| 		struct mmc_ios ios; | ||||
| 	ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2); | ||||
| 	ctrl |= (S3C64XX_SDHCI_CTRL2_ENSTAASYNCCLR | | ||||
| 		  S3C64XX_SDHCI_CTRL2_ENCMDCNFMSK | | ||||
| 		  S3C_SDHCI_CTRL2_ENFBCLKRX | | ||||
| 		  S3C_SDHCI_CTRL2_DFCNT_NONE | | ||||
| 		  S3C_SDHCI_CTRL2_ENCLKOUTHOLD); | ||||
| 	writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2); | ||||
| 
 | ||||
| 		ios.clock = clock; | ||||
| 
 | ||||
| 		if (ourhost->pdata->cfg_card) | ||||
| 			(ourhost->pdata->cfg_card)(ourhost->pdev, host->ioaddr, | ||||
| 						   &ios, NULL); | ||||
| 	} | ||||
| 	/* reconfigure the controller for new clock rate */ | ||||
| 	ctrl = (S3C_SDHCI_CTRL3_FCSEL1 | S3C_SDHCI_CTRL3_FCSEL0); | ||||
| 	if (clock < 25 * 1000000) | ||||
| 		ctrl |= (S3C_SDHCI_CTRL3_FCSEL3 | S3C_SDHCI_CTRL3_FCSEL2); | ||||
| 	writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL3); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -561,8 +567,10 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) | |||
| 
 | ||||
|  err_req_regs: | ||||
| 	for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) { | ||||
| 		clk_disable(sc->clk_bus[ptr]); | ||||
| 		clk_put(sc->clk_bus[ptr]); | ||||
| 		if (sc->clk_bus[ptr]) { | ||||
| 			clk_disable(sc->clk_bus[ptr]); | ||||
| 			clk_put(sc->clk_bus[ptr]); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  err_no_busclks: | ||||
|  |  | |||
|  | @ -17,6 +17,7 @@ | |||
| #include <linux/delay.h> | ||||
| #include <linux/gpio.h> | ||||
| #include <linux/highmem.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/interrupt.h> | ||||
| #include <linux/irq.h> | ||||
| #include <linux/platform_device.h> | ||||
|  | @ -177,8 +178,6 @@ static int __devinit sdhci_probe(struct platform_device *pdev) | |||
| 					sdhci->data->card_power_gpio); | ||||
| 			goto err_pgpio_direction; | ||||
| 		} | ||||
| 
 | ||||
| 		gpio_set_value(sdhci->data->card_power_gpio, 1); | ||||
| 	} | ||||
| 
 | ||||
| 	if (sdhci->data->card_int_gpio >= 0) { | ||||
|  |  | |||
|  | @ -17,9 +17,12 @@ | |||
| #include <linux/platform_device.h> | ||||
| #include <linux/clk.h> | ||||
| #include <linux/io.h> | ||||
| #include <linux/of.h> | ||||
| #include <linux/of_gpio.h> | ||||
| #include <linux/gpio.h> | ||||
| #include <linux/mmc/card.h> | ||||
| #include <linux/mmc/host.h> | ||||
| #include <linux/module.h> | ||||
| 
 | ||||
| #include <asm/gpio.h> | ||||
| 
 | ||||
|  | @ -75,10 +78,8 @@ static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg) | |||
| 
 | ||||
| static unsigned int tegra_sdhci_get_ro(struct sdhci_host *sdhci) | ||||
| { | ||||
| 	struct platform_device *pdev = to_platform_device(mmc_dev(sdhci->mmc)); | ||||
| 	struct tegra_sdhci_platform_data *plat; | ||||
| 
 | ||||
| 	plat = pdev->dev.platform_data; | ||||
| 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(sdhci); | ||||
| 	struct tegra_sdhci_platform_data *plat = pltfm_host->priv; | ||||
| 
 | ||||
| 	if (!gpio_is_valid(plat->wp_gpio)) | ||||
| 		return -1; | ||||
|  | @ -96,12 +97,10 @@ static irqreturn_t carddetect_irq(int irq, void *data) | |||
| 
 | ||||
| static int tegra_sdhci_8bit(struct sdhci_host *host, int bus_width) | ||||
| { | ||||
| 	struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); | ||||
| 	struct tegra_sdhci_platform_data *plat; | ||||
| 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | ||||
| 	struct tegra_sdhci_platform_data *plat = pltfm_host->priv; | ||||
| 	u32 ctrl; | ||||
| 
 | ||||
| 	plat = pdev->dev.platform_data; | ||||
| 
 | ||||
| 	ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); | ||||
| 	if (plat->is_8bit && bus_width == MMC_BUS_WIDTH_8) { | ||||
| 		ctrl &= ~SDHCI_CTRL_4BITBUS; | ||||
|  | @ -133,6 +132,36 @@ static struct sdhci_pltfm_data sdhci_tegra_pdata = { | |||
| 	.ops  = &tegra_sdhci_ops, | ||||
| }; | ||||
| 
 | ||||
| static const struct of_device_id sdhci_tegra_dt_match[] __devinitdata = { | ||||
| 	{ .compatible = "nvidia,tegra20-sdhci", }, | ||||
| 	{} | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(of, sdhci_dt_ids); | ||||
| 
 | ||||
| static struct tegra_sdhci_platform_data * __devinit sdhci_tegra_dt_parse_pdata( | ||||
| 						struct platform_device *pdev) | ||||
| { | ||||
| 	struct tegra_sdhci_platform_data *plat; | ||||
| 	struct device_node *np = pdev->dev.of_node; | ||||
| 
 | ||||
| 	if (!np) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); | ||||
| 	if (!plat) { | ||||
| 		dev_err(&pdev->dev, "Can't allocate platform data\n"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	plat->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); | ||||
| 	plat->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); | ||||
| 	plat->power_gpio = of_get_named_gpio(np, "power-gpios", 0); | ||||
| 	if (of_find_property(np, "support-8bit", NULL)) | ||||
| 		plat->is_8bit = 1; | ||||
| 
 | ||||
| 	return plat; | ||||
| } | ||||
| 
 | ||||
| static int __devinit sdhci_tegra_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	struct sdhci_pltfm_host *pltfm_host; | ||||
|  | @ -149,12 +178,17 @@ static int __devinit sdhci_tegra_probe(struct platform_device *pdev) | |||
| 
 | ||||
| 	plat = pdev->dev.platform_data; | ||||
| 
 | ||||
| 	if (plat == NULL) | ||||
| 		plat = sdhci_tegra_dt_parse_pdata(pdev); | ||||
| 
 | ||||
| 	if (plat == NULL) { | ||||
| 		dev_err(mmc_dev(host->mmc), "missing platform data\n"); | ||||
| 		rc = -ENXIO; | ||||
| 		goto err_no_plat; | ||||
| 	} | ||||
| 
 | ||||
| 	pltfm_host->priv = plat; | ||||
| 
 | ||||
| 	if (gpio_is_valid(plat->power_gpio)) { | ||||
| 		rc = gpio_request(plat->power_gpio, "sdhci_power"); | ||||
| 		if (rc) { | ||||
|  | @ -249,13 +283,11 @@ static int __devexit sdhci_tegra_remove(struct platform_device *pdev) | |||
| { | ||||
| 	struct sdhci_host *host = platform_get_drvdata(pdev); | ||||
| 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | ||||
| 	struct tegra_sdhci_platform_data *plat; | ||||
| 	struct tegra_sdhci_platform_data *plat = pltfm_host->priv; | ||||
| 	int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); | ||||
| 
 | ||||
| 	sdhci_remove_host(host, dead); | ||||
| 
 | ||||
| 	plat = pdev->dev.platform_data; | ||||
| 
 | ||||
| 	if (gpio_is_valid(plat->wp_gpio)) { | ||||
| 		tegra_gpio_disable(plat->wp_gpio); | ||||
| 		gpio_free(plat->wp_gpio); | ||||
|  | @ -284,6 +316,7 @@ static struct platform_driver sdhci_tegra_driver = { | |||
| 	.driver		= { | ||||
| 		.name	= "sdhci-tegra", | ||||
| 		.owner	= THIS_MODULE, | ||||
| 		.of_match_table = sdhci_tegra_dt_match, | ||||
| 	}, | ||||
| 	.probe		= sdhci_tegra_probe, | ||||
| 	.remove		= __devexit_p(sdhci_tegra_remove), | ||||
|  |  | |||
|  | @ -16,10 +16,12 @@ | |||
| #include <linux/delay.h> | ||||
| #include <linux/highmem.h> | ||||
| #include <linux/io.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/dma-mapping.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/scatterlist.h> | ||||
| #include <linux/regulator/consumer.h> | ||||
| #include <linux/pm_runtime.h> | ||||
| 
 | ||||
| #include <linux/leds.h> | ||||
| 
 | ||||
|  | @ -41,6 +43,7 @@ | |||
| #define MAX_TUNING_LOOP 40 | ||||
| 
 | ||||
| static unsigned int debug_quirks = 0; | ||||
| static unsigned int debug_quirks2; | ||||
| 
 | ||||
| static void sdhci_finish_data(struct sdhci_host *); | ||||
| 
 | ||||
|  | @ -49,53 +52,67 @@ static void sdhci_finish_command(struct sdhci_host *); | |||
| static int sdhci_execute_tuning(struct mmc_host *mmc); | ||||
| static void sdhci_tuning_timer(unsigned long data); | ||||
| 
 | ||||
| #ifdef CONFIG_PM_RUNTIME | ||||
| static int sdhci_runtime_pm_get(struct sdhci_host *host); | ||||
| static int sdhci_runtime_pm_put(struct sdhci_host *host); | ||||
| #else | ||||
| static inline int sdhci_runtime_pm_get(struct sdhci_host *host) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| static inline int sdhci_runtime_pm_put(struct sdhci_host *host) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static void sdhci_dumpregs(struct sdhci_host *host) | ||||
| { | ||||
| 	printk(KERN_DEBUG DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", | ||||
| 	pr_debug(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", | ||||
| 		mmc_hostname(host->mmc)); | ||||
| 
 | ||||
| 	printk(KERN_DEBUG DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n", | ||||
| 	pr_debug(DRIVER_NAME ": Sys addr: 0x%08x | Version:  0x%08x\n", | ||||
| 		sdhci_readl(host, SDHCI_DMA_ADDRESS), | ||||
| 		sdhci_readw(host, SDHCI_HOST_VERSION)); | ||||
| 	printk(KERN_DEBUG DRIVER_NAME ": Blk size: 0x%08x | Blk cnt:  0x%08x\n", | ||||
| 	pr_debug(DRIVER_NAME ": Blk size: 0x%08x | Blk cnt:  0x%08x\n", | ||||
| 		sdhci_readw(host, SDHCI_BLOCK_SIZE), | ||||
| 		sdhci_readw(host, SDHCI_BLOCK_COUNT)); | ||||
| 	printk(KERN_DEBUG DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", | ||||
| 	pr_debug(DRIVER_NAME ": Argument: 0x%08x | Trn mode: 0x%08x\n", | ||||
| 		sdhci_readl(host, SDHCI_ARGUMENT), | ||||
| 		sdhci_readw(host, SDHCI_TRANSFER_MODE)); | ||||
| 	printk(KERN_DEBUG DRIVER_NAME ": Present:  0x%08x | Host ctl: 0x%08x\n", | ||||
| 	pr_debug(DRIVER_NAME ": Present:  0x%08x | Host ctl: 0x%08x\n", | ||||
| 		sdhci_readl(host, SDHCI_PRESENT_STATE), | ||||
| 		sdhci_readb(host, SDHCI_HOST_CONTROL)); | ||||
| 	printk(KERN_DEBUG DRIVER_NAME ": Power:    0x%08x | Blk gap:  0x%08x\n", | ||||
| 	pr_debug(DRIVER_NAME ": Power:    0x%08x | Blk gap:  0x%08x\n", | ||||
| 		sdhci_readb(host, SDHCI_POWER_CONTROL), | ||||
| 		sdhci_readb(host, SDHCI_BLOCK_GAP_CONTROL)); | ||||
| 	printk(KERN_DEBUG DRIVER_NAME ": Wake-up:  0x%08x | Clock:    0x%08x\n", | ||||
| 	pr_debug(DRIVER_NAME ": Wake-up:  0x%08x | Clock:    0x%08x\n", | ||||
| 		sdhci_readb(host, SDHCI_WAKE_UP_CONTROL), | ||||
| 		sdhci_readw(host, SDHCI_CLOCK_CONTROL)); | ||||
| 	printk(KERN_DEBUG DRIVER_NAME ": Timeout:  0x%08x | Int stat: 0x%08x\n", | ||||
| 	pr_debug(DRIVER_NAME ": Timeout:  0x%08x | Int stat: 0x%08x\n", | ||||
| 		sdhci_readb(host, SDHCI_TIMEOUT_CONTROL), | ||||
| 		sdhci_readl(host, SDHCI_INT_STATUS)); | ||||
| 	printk(KERN_DEBUG DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", | ||||
| 	pr_debug(DRIVER_NAME ": Int enab: 0x%08x | Sig enab: 0x%08x\n", | ||||
| 		sdhci_readl(host, SDHCI_INT_ENABLE), | ||||
| 		sdhci_readl(host, SDHCI_SIGNAL_ENABLE)); | ||||
| 	printk(KERN_DEBUG DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n", | ||||
| 	pr_debug(DRIVER_NAME ": AC12 err: 0x%08x | Slot int: 0x%08x\n", | ||||
| 		sdhci_readw(host, SDHCI_ACMD12_ERR), | ||||
| 		sdhci_readw(host, SDHCI_SLOT_INT_STATUS)); | ||||
| 	printk(KERN_DEBUG DRIVER_NAME ": Caps:     0x%08x | Caps_1:   0x%08x\n", | ||||
| 	pr_debug(DRIVER_NAME ": Caps:     0x%08x | Caps_1:   0x%08x\n", | ||||
| 		sdhci_readl(host, SDHCI_CAPABILITIES), | ||||
| 		sdhci_readl(host, SDHCI_CAPABILITIES_1)); | ||||
| 	printk(KERN_DEBUG DRIVER_NAME ": Cmd:      0x%08x | Max curr: 0x%08x\n", | ||||
| 	pr_debug(DRIVER_NAME ": Cmd:      0x%08x | Max curr: 0x%08x\n", | ||||
| 		sdhci_readw(host, SDHCI_COMMAND), | ||||
| 		sdhci_readl(host, SDHCI_MAX_CURRENT)); | ||||
| 	printk(KERN_DEBUG DRIVER_NAME ": Host ctl2: 0x%08x\n", | ||||
| 	pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n", | ||||
| 		sdhci_readw(host, SDHCI_HOST_CONTROL2)); | ||||
| 
 | ||||
| 	if (host->flags & SDHCI_USE_ADMA) | ||||
| 		printk(KERN_DEBUG DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n", | ||||
| 		pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n", | ||||
| 		       readl(host->ioaddr + SDHCI_ADMA_ERROR), | ||||
| 		       readl(host->ioaddr + SDHCI_ADMA_ADDRESS)); | ||||
| 
 | ||||
| 	printk(KERN_DEBUG DRIVER_NAME ": ===========================================\n"); | ||||
| 	pr_debug(DRIVER_NAME ": ===========================================\n"); | ||||
| } | ||||
| 
 | ||||
| /*****************************************************************************\
 | ||||
|  | @ -132,6 +149,9 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable) | |||
| 	if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (host->quirks2 & SDHCI_QUIRK2_OWN_CARD_DETECTION) | ||||
| 		return; | ||||
| 
 | ||||
| 	present = sdhci_readl(host, SDHCI_PRESENT_STATE) & | ||||
| 			      SDHCI_CARD_PRESENT; | ||||
| 	irqs = present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT; | ||||
|  | @ -180,7 +200,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask) | |||
| 	/* hw clears the bit when it's done */ | ||||
| 	while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) { | ||||
| 		if (timeout == 0) { | ||||
| 			printk(KERN_ERR "%s: Reset 0x%x never completed.\n", | ||||
| 			pr_err("%s: Reset 0x%x never completed.\n", | ||||
| 				mmc_hostname(host->mmc), (int)mask); | ||||
| 			sdhci_dumpregs(host); | ||||
| 			return; | ||||
|  | @ -251,11 +271,14 @@ static void sdhci_led_control(struct led_classdev *led, | |||
| 
 | ||||
| 	spin_lock_irqsave(&host->lock, flags); | ||||
| 
 | ||||
| 	if (host->runtime_suspended) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	if (brightness == LED_OFF) | ||||
| 		sdhci_deactivate_led(host); | ||||
| 	else | ||||
| 		sdhci_activate_led(host); | ||||
| 
 | ||||
| out: | ||||
| 	spin_unlock_irqrestore(&host->lock, flags); | ||||
| } | ||||
| #endif | ||||
|  | @ -654,7 +677,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) | |||
| 	} | ||||
| 
 | ||||
| 	if (count >= 0xF) { | ||||
| 		printk(KERN_WARNING "%s: Too large timeout requested for CMD%d!\n", | ||||
| 		pr_warning("%s: Too large timeout requested for CMD%d!\n", | ||||
| 		       mmc_hostname(host->mmc), cmd->opcode); | ||||
| 		count = 0xE; | ||||
| 	} | ||||
|  | @ -949,7 +972,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) | |||
| 
 | ||||
| 	while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) { | ||||
| 		if (timeout == 0) { | ||||
| 			printk(KERN_ERR "%s: Controller never released " | ||||
| 			pr_err("%s: Controller never released " | ||||
| 				"inhibit bit(s).\n", mmc_hostname(host->mmc)); | ||||
| 			sdhci_dumpregs(host); | ||||
| 			cmd->error = -EIO; | ||||
|  | @ -971,7 +994,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) | |||
| 	sdhci_set_transfer_mode(host, cmd); | ||||
| 
 | ||||
| 	if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) { | ||||
| 		printk(KERN_ERR "%s: Unsupported response type!\n", | ||||
| 		pr_err("%s: Unsupported response type!\n", | ||||
| 			mmc_hostname(host->mmc)); | ||||
| 		cmd->error = -EINVAL; | ||||
| 		tasklet_schedule(&host->finish_tasklet); | ||||
|  | @ -1121,7 +1144,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) | |||
| 	while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) | ||||
| 		& SDHCI_CLOCK_INT_STABLE)) { | ||||
| 		if (timeout == 0) { | ||||
| 			printk(KERN_ERR "%s: Internal clock never " | ||||
| 			pr_err("%s: Internal clock never " | ||||
| 				"stabilised.\n", mmc_hostname(host->mmc)); | ||||
| 			sdhci_dumpregs(host); | ||||
| 			return; | ||||
|  | @ -1209,6 +1232,8 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
| 
 | ||||
| 	host = mmc_priv(mmc); | ||||
| 
 | ||||
| 	sdhci_runtime_pm_get(host); | ||||
| 
 | ||||
| 	spin_lock_irqsave(&host->lock, flags); | ||||
| 
 | ||||
| 	WARN_ON(host->mrq != NULL); | ||||
|  | @ -1269,14 +1294,11 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
| 	spin_unlock_irqrestore(&host->lock, flags); | ||||
| } | ||||
| 
 | ||||
| static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | ||||
| static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) | ||||
| { | ||||
| 	struct sdhci_host *host; | ||||
| 	unsigned long flags; | ||||
| 	u8 ctrl; | ||||
| 
 | ||||
| 	host = mmc_priv(mmc); | ||||
| 
 | ||||
| 	spin_lock_irqsave(&host->lock, flags); | ||||
| 
 | ||||
| 	if (host->flags & SDHCI_DEVICE_DEAD) | ||||
|  | @ -1426,7 +1448,16 @@ out: | |||
| 	spin_unlock_irqrestore(&host->lock, flags); | ||||
| } | ||||
| 
 | ||||
| static int check_ro(struct sdhci_host *host) | ||||
| static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | ||||
| { | ||||
| 	struct sdhci_host *host = mmc_priv(mmc); | ||||
| 
 | ||||
| 	sdhci_runtime_pm_get(host); | ||||
| 	sdhci_do_set_ios(host, ios); | ||||
| 	sdhci_runtime_pm_put(host); | ||||
| } | ||||
| 
 | ||||
| static int sdhci_check_ro(struct sdhci_host *host) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	int is_readonly; | ||||
|  | @ -1450,19 +1481,16 @@ static int check_ro(struct sdhci_host *host) | |||
| 
 | ||||
| #define SAMPLE_COUNT	5 | ||||
| 
 | ||||
| static int sdhci_get_ro(struct mmc_host *mmc) | ||||
| static int sdhci_do_get_ro(struct sdhci_host *host) | ||||
| { | ||||
| 	struct sdhci_host *host; | ||||
| 	int i, ro_count; | ||||
| 
 | ||||
| 	host = mmc_priv(mmc); | ||||
| 
 | ||||
| 	if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT)) | ||||
| 		return check_ro(host); | ||||
| 		return sdhci_check_ro(host); | ||||
| 
 | ||||
| 	ro_count = 0; | ||||
| 	for (i = 0; i < SAMPLE_COUNT; i++) { | ||||
| 		if (check_ro(host)) { | ||||
| 		if (sdhci_check_ro(host)) { | ||||
| 			if (++ro_count > SAMPLE_COUNT / 2) | ||||
| 				return 1; | ||||
| 		} | ||||
|  | @ -1471,38 +1499,64 @@ static int sdhci_get_ro(struct mmc_host *mmc) | |||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) | ||||
| static void sdhci_hw_reset(struct mmc_host *mmc) | ||||
| { | ||||
| 	struct sdhci_host *host; | ||||
| 	unsigned long flags; | ||||
| 	struct sdhci_host *host = mmc_priv(mmc); | ||||
| 
 | ||||
| 	host = mmc_priv(mmc); | ||||
| 	if (host->ops && host->ops->hw_reset) | ||||
| 		host->ops->hw_reset(host); | ||||
| } | ||||
| 
 | ||||
| 	spin_lock_irqsave(&host->lock, flags); | ||||
| static int sdhci_get_ro(struct mmc_host *mmc) | ||||
| { | ||||
| 	struct sdhci_host *host = mmc_priv(mmc); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	sdhci_runtime_pm_get(host); | ||||
| 	ret = sdhci_do_get_ro(host); | ||||
| 	sdhci_runtime_pm_put(host); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable) | ||||
| { | ||||
| 	if (host->flags & SDHCI_DEVICE_DEAD) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	if (enable) | ||||
| 		host->flags |= SDHCI_SDIO_IRQ_ENABLED; | ||||
| 	else | ||||
| 		host->flags &= ~SDHCI_SDIO_IRQ_ENABLED; | ||||
| 
 | ||||
| 	/* SDIO IRQ will be enabled as appropriate in runtime resume */ | ||||
| 	if (host->runtime_suspended) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	if (enable) | ||||
| 		sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT); | ||||
| 	else | ||||
| 		sdhci_mask_irqs(host, SDHCI_INT_CARD_INT); | ||||
| out: | ||||
| 	mmiowb(); | ||||
| } | ||||
| 
 | ||||
| static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) | ||||
| { | ||||
| 	struct sdhci_host *host = mmc_priv(mmc); | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&host->lock, flags); | ||||
| 	sdhci_enable_sdio_irq_nolock(host, enable); | ||||
| 	spin_unlock_irqrestore(&host->lock, flags); | ||||
| } | ||||
| 
 | ||||
| static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, | ||||
| 	struct mmc_ios *ios) | ||||
| static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, | ||||
| 						struct mmc_ios *ios) | ||||
| { | ||||
| 	struct sdhci_host *host; | ||||
| 	u8 pwr; | ||||
| 	u16 clk, ctrl; | ||||
| 	u32 present_state; | ||||
| 
 | ||||
| 	host = mmc_priv(mmc); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Signal Voltage Switching is only applicable for Host Controllers | ||||
| 	 * v3.00 and above. | ||||
|  | @ -1528,7 +1582,7 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, | |||
| 		if (!(ctrl & SDHCI_CTRL_VDD_180)) | ||||
| 			return 0; | ||||
| 		else { | ||||
| 			printk(KERN_INFO DRIVER_NAME ": Switching to 3.3V " | ||||
| 			pr_info(DRIVER_NAME ": Switching to 3.3V " | ||||
| 				"signalling voltage failed\n"); | ||||
| 			return -EIO; | ||||
| 		} | ||||
|  | @ -1587,7 +1641,7 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, | |||
| 		pwr |= SDHCI_POWER_ON; | ||||
| 		sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); | ||||
| 
 | ||||
| 		printk(KERN_INFO DRIVER_NAME ": Switching to 1.8V signalling " | ||||
| 		pr_info(DRIVER_NAME ": Switching to 1.8V signalling " | ||||
| 			"voltage failed, retrying with S18R set to 0\n"); | ||||
| 		return -EAGAIN; | ||||
| 	} else | ||||
|  | @ -1595,6 +1649,20 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, | |||
| 		return 0; | ||||
| } | ||||
| 
 | ||||
| static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, | ||||
| 	struct mmc_ios *ios) | ||||
| { | ||||
| 	struct sdhci_host *host = mmc_priv(mmc); | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (host->version < SDHCI_SPEC_300) | ||||
| 		return 0; | ||||
| 	sdhci_runtime_pm_get(host); | ||||
| 	err = sdhci_do_start_signal_voltage_switch(host, ios); | ||||
| 	sdhci_runtime_pm_put(host); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static int sdhci_execute_tuning(struct mmc_host *mmc) | ||||
| { | ||||
| 	struct sdhci_host *host; | ||||
|  | @ -1606,6 +1674,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) | |||
| 
 | ||||
| 	host = mmc_priv(mmc); | ||||
| 
 | ||||
| 	sdhci_runtime_pm_get(host); | ||||
| 	disable_irq(host->irq); | ||||
| 	spin_lock(&host->lock); | ||||
| 
 | ||||
|  | @ -1623,6 +1692,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) | |||
| 	else { | ||||
| 		spin_unlock(&host->lock); | ||||
| 		enable_irq(host->irq); | ||||
| 		sdhci_runtime_pm_put(host); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -1648,7 +1718,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) | |||
| 	timeout = 150; | ||||
| 	do { | ||||
| 		struct mmc_command cmd = {0}; | ||||
| 		struct mmc_request mrq = {0}; | ||||
| 		struct mmc_request mrq = {NULL}; | ||||
| 
 | ||||
| 		if (!tuning_loop_counter && !timeout) | ||||
| 			break; | ||||
|  | @ -1694,7 +1764,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) | |||
| 		spin_lock(&host->lock); | ||||
| 
 | ||||
| 		if (!host->tuning_done) { | ||||
| 			printk(KERN_INFO DRIVER_NAME ": Timeout waiting for " | ||||
| 			pr_info(DRIVER_NAME ": Timeout waiting for " | ||||
| 				"Buffer Read Ready interrupt during tuning " | ||||
| 				"procedure, falling back to fixed sampling " | ||||
| 				"clock\n"); | ||||
|  | @ -1724,7 +1794,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) | |||
| 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); | ||||
| 	} else { | ||||
| 		if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) { | ||||
| 			printk(KERN_INFO DRIVER_NAME ": Tuning procedure" | ||||
| 			pr_info(DRIVER_NAME ": Tuning procedure" | ||||
| 				" failed, falling back to fixed sampling" | ||||
| 				" clock\n"); | ||||
| 			err = -EIO; | ||||
|  | @ -1766,18 +1836,16 @@ out: | |||
| 	sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier); | ||||
| 	spin_unlock(&host->lock); | ||||
| 	enable_irq(host->irq); | ||||
| 	sdhci_runtime_pm_put(host); | ||||
| 
 | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) | ||||
| static void sdhci_do_enable_preset_value(struct sdhci_host *host, bool enable) | ||||
| { | ||||
| 	struct sdhci_host *host; | ||||
| 	u16 ctrl; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	host = mmc_priv(mmc); | ||||
| 
 | ||||
| 	/* Host Controller v3.00 defines preset value registers */ | ||||
| 	if (host->version < SDHCI_SPEC_300) | ||||
| 		return; | ||||
|  | @ -1793,18 +1861,30 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) | |||
| 	if (enable && !(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { | ||||
| 		ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE; | ||||
| 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); | ||||
| 		host->flags |= SDHCI_PV_ENABLED; | ||||
| 	} else if (!enable && (ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { | ||||
| 		ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; | ||||
| 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); | ||||
| 		host->flags &= ~SDHCI_PV_ENABLED; | ||||
| 	} | ||||
| 
 | ||||
| 	spin_unlock_irqrestore(&host->lock, flags); | ||||
| } | ||||
| 
 | ||||
| static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) | ||||
| { | ||||
| 	struct sdhci_host *host = mmc_priv(mmc); | ||||
| 
 | ||||
| 	sdhci_runtime_pm_get(host); | ||||
| 	sdhci_do_enable_preset_value(host, enable); | ||||
| 	sdhci_runtime_pm_put(host); | ||||
| } | ||||
| 
 | ||||
| static const struct mmc_host_ops sdhci_ops = { | ||||
| 	.request	= sdhci_request, | ||||
| 	.set_ios	= sdhci_set_ios, | ||||
| 	.get_ro		= sdhci_get_ro, | ||||
| 	.hw_reset	= sdhci_hw_reset, | ||||
| 	.enable_sdio_irq = sdhci_enable_sdio_irq, | ||||
| 	.start_signal_voltage_switch	= sdhci_start_signal_voltage_switch, | ||||
| 	.execute_tuning			= sdhci_execute_tuning, | ||||
|  | @ -1826,19 +1906,19 @@ static void sdhci_tasklet_card(unsigned long param) | |||
| 
 | ||||
| 	spin_lock_irqsave(&host->lock, flags); | ||||
| 
 | ||||
| 	if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { | ||||
| 		if (host->mrq) { | ||||
| 			printk(KERN_ERR "%s: Card removed during transfer!\n", | ||||
| 				mmc_hostname(host->mmc)); | ||||
| 			printk(KERN_ERR "%s: Resetting controller.\n", | ||||
| 				mmc_hostname(host->mmc)); | ||||
| 	/* Check host->mrq first in case we are runtime suspended */ | ||||
| 	if (host->mrq && | ||||
| 	    !(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { | ||||
| 		pr_err("%s: Card removed during transfer!\n", | ||||
| 			mmc_hostname(host->mmc)); | ||||
| 		pr_err("%s: Resetting controller.\n", | ||||
| 			mmc_hostname(host->mmc)); | ||||
| 
 | ||||
| 			sdhci_reset(host, SDHCI_RESET_CMD); | ||||
| 			sdhci_reset(host, SDHCI_RESET_DATA); | ||||
| 		sdhci_reset(host, SDHCI_RESET_CMD); | ||||
| 		sdhci_reset(host, SDHCI_RESET_DATA); | ||||
| 
 | ||||
| 			host->mrq->cmd->error = -ENOMEDIUM; | ||||
| 			tasklet_schedule(&host->finish_tasklet); | ||||
| 		} | ||||
| 		host->mrq->cmd->error = -ENOMEDIUM; | ||||
| 		tasklet_schedule(&host->finish_tasklet); | ||||
| 	} | ||||
| 
 | ||||
| 	spin_unlock_irqrestore(&host->lock, flags); | ||||
|  | @ -1854,14 +1934,16 @@ static void sdhci_tasklet_finish(unsigned long param) | |||
| 
 | ||||
| 	host = (struct sdhci_host*)param; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&host->lock, flags); | ||||
| 
 | ||||
|         /*
 | ||||
|          * If this tasklet gets rescheduled while running, it will | ||||
|          * be run again afterwards but without any active request. | ||||
|          */ | ||||
| 	if (!host->mrq) | ||||
| 	if (!host->mrq) { | ||||
| 		spin_unlock_irqrestore(&host->lock, flags); | ||||
| 		return; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&host->lock, flags); | ||||
| 	} | ||||
| 
 | ||||
| 	del_timer(&host->timer); | ||||
| 
 | ||||
|  | @ -1905,6 +1987,7 @@ static void sdhci_tasklet_finish(unsigned long param) | |||
| 	spin_unlock_irqrestore(&host->lock, flags); | ||||
| 
 | ||||
| 	mmc_request_done(host->mmc, mrq); | ||||
| 	sdhci_runtime_pm_put(host); | ||||
| } | ||||
| 
 | ||||
| static void sdhci_timeout_timer(unsigned long data) | ||||
|  | @ -1917,7 +2000,7 @@ static void sdhci_timeout_timer(unsigned long data) | |||
| 	spin_lock_irqsave(&host->lock, flags); | ||||
| 
 | ||||
| 	if (host->mrq) { | ||||
| 		printk(KERN_ERR "%s: Timeout waiting for hardware " | ||||
| 		pr_err("%s: Timeout waiting for hardware " | ||||
| 			"interrupt.\n", mmc_hostname(host->mmc)); | ||||
| 		sdhci_dumpregs(host); | ||||
| 
 | ||||
|  | @ -1963,7 +2046,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) | |||
| 	BUG_ON(intmask == 0); | ||||
| 
 | ||||
| 	if (!host->cmd) { | ||||
| 		printk(KERN_ERR "%s: Got command interrupt 0x%08x even " | ||||
| 		pr_err("%s: Got command interrupt 0x%08x even " | ||||
| 			"though no command operation was in progress.\n", | ||||
| 			mmc_hostname(host->mmc), (unsigned)intmask); | ||||
| 		sdhci_dumpregs(host); | ||||
|  | @ -2063,7 +2146,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) | |||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		printk(KERN_ERR "%s: Got data interrupt 0x%08x even " | ||||
| 		pr_err("%s: Got data interrupt 0x%08x even " | ||||
| 			"though no data operation was in progress.\n", | ||||
| 			mmc_hostname(host->mmc), (unsigned)intmask); | ||||
| 		sdhci_dumpregs(host); | ||||
|  | @ -2080,7 +2163,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) | |||
| 			!= MMC_BUS_TEST_R) | ||||
| 		host->data->error = -EILSEQ; | ||||
| 	else if (intmask & SDHCI_INT_ADMA_ERROR) { | ||||
| 		printk(KERN_ERR "%s: ADMA error\n", mmc_hostname(host->mmc)); | ||||
| 		pr_err("%s: ADMA error\n", mmc_hostname(host->mmc)); | ||||
| 		sdhci_show_adma_error(host); | ||||
| 		host->data->error = -EIO; | ||||
| 	} | ||||
|  | @ -2136,12 +2219,19 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) | |||
| static irqreturn_t sdhci_irq(int irq, void *dev_id) | ||||
| { | ||||
| 	irqreturn_t result; | ||||
| 	struct sdhci_host* host = dev_id; | ||||
| 	struct sdhci_host *host = dev_id; | ||||
| 	u32 intmask; | ||||
| 	int cardint = 0; | ||||
| 
 | ||||
| 	spin_lock(&host->lock); | ||||
| 
 | ||||
| 	if (host->runtime_suspended) { | ||||
| 		spin_unlock(&host->lock); | ||||
| 		pr_warning("%s: got irq while runtime suspended\n", | ||||
| 		       mmc_hostname(host->mmc)); | ||||
| 		return IRQ_HANDLED; | ||||
| 	} | ||||
| 
 | ||||
| 	intmask = sdhci_readl(host, SDHCI_INT_STATUS); | ||||
| 
 | ||||
| 	if (!intmask || intmask == 0xffffffff) { | ||||
|  | @ -2194,7 +2284,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) | |||
| 	intmask &= ~SDHCI_INT_ERROR; | ||||
| 
 | ||||
| 	if (intmask & SDHCI_INT_BUS_POWER) { | ||||
| 		printk(KERN_ERR "%s: Card is consuming too much power!\n", | ||||
| 		pr_err("%s: Card is consuming too much power!\n", | ||||
| 			mmc_hostname(host->mmc)); | ||||
| 		sdhci_writel(host, SDHCI_INT_BUS_POWER, SDHCI_INT_STATUS); | ||||
| 	} | ||||
|  | @ -2207,7 +2297,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) | |||
| 	intmask &= ~SDHCI_INT_CARD_INT; | ||||
| 
 | ||||
| 	if (intmask) { | ||||
| 		printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n", | ||||
| 		pr_err("%s: Unexpected interrupt 0x%08x.\n", | ||||
| 			mmc_hostname(host->mmc), intmask); | ||||
| 		sdhci_dumpregs(host); | ||||
| 
 | ||||
|  | @ -2275,7 +2365,6 @@ int sdhci_resume_host(struct sdhci_host *host) | |||
| 			return ret; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { | ||||
| 		if (host->ops->enable_dma) | ||||
| 			host->ops->enable_dma(host); | ||||
|  | @ -2314,6 +2403,90 @@ EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups); | |||
| 
 | ||||
| #endif /* CONFIG_PM */ | ||||
| 
 | ||||
| #ifdef CONFIG_PM_RUNTIME | ||||
| 
 | ||||
| static int sdhci_runtime_pm_get(struct sdhci_host *host) | ||||
| { | ||||
| 	return pm_runtime_get_sync(host->mmc->parent); | ||||
| } | ||||
| 
 | ||||
| static int sdhci_runtime_pm_put(struct sdhci_host *host) | ||||
| { | ||||
| 	pm_runtime_mark_last_busy(host->mmc->parent); | ||||
| 	return pm_runtime_put_autosuspend(host->mmc->parent); | ||||
| } | ||||
| 
 | ||||
| int sdhci_runtime_suspend_host(struct sdhci_host *host) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	/* Disable tuning since we are suspending */ | ||||
| 	if (host->version >= SDHCI_SPEC_300 && | ||||
| 	    host->tuning_mode == SDHCI_TUNING_MODE_1) { | ||||
| 		del_timer_sync(&host->tuning_timer); | ||||
| 		host->flags &= ~SDHCI_NEEDS_RETUNING; | ||||
| 	} | ||||
| 
 | ||||
| 	spin_lock_irqsave(&host->lock, flags); | ||||
| 	sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); | ||||
| 	spin_unlock_irqrestore(&host->lock, flags); | ||||
| 
 | ||||
| 	synchronize_irq(host->irq); | ||||
| 
 | ||||
| 	spin_lock_irqsave(&host->lock, flags); | ||||
| 	host->runtime_suspended = true; | ||||
| 	spin_unlock_irqrestore(&host->lock, flags); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(sdhci_runtime_suspend_host); | ||||
| 
 | ||||
| int sdhci_runtime_resume_host(struct sdhci_host *host) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	int ret = 0, host_flags = host->flags; | ||||
| 
 | ||||
| 	if (host_flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { | ||||
| 		if (host->ops->enable_dma) | ||||
| 			host->ops->enable_dma(host); | ||||
| 	} | ||||
| 
 | ||||
| 	sdhci_init(host, 0); | ||||
| 
 | ||||
| 	/* Force clock and power re-program */ | ||||
| 	host->pwr = 0; | ||||
| 	host->clock = 0; | ||||
| 	sdhci_do_set_ios(host, &host->mmc->ios); | ||||
| 
 | ||||
| 	sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios); | ||||
| 	if (host_flags & SDHCI_PV_ENABLED) | ||||
| 		sdhci_do_enable_preset_value(host, true); | ||||
| 
 | ||||
| 	/* Set the re-tuning expiration flag */ | ||||
| 	if ((host->version >= SDHCI_SPEC_300) && host->tuning_count && | ||||
| 	    (host->tuning_mode == SDHCI_TUNING_MODE_1)) | ||||
| 		host->flags |= SDHCI_NEEDS_RETUNING; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&host->lock, flags); | ||||
| 
 | ||||
| 	host->runtime_suspended = false; | ||||
| 
 | ||||
| 	/* Enable SDIO IRQ */ | ||||
| 	if ((host->flags & SDHCI_SDIO_IRQ_ENABLED)) | ||||
| 		sdhci_enable_sdio_irq_nolock(host, true); | ||||
| 
 | ||||
| 	/* Enable Card Detection */ | ||||
| 	sdhci_enable_card_detection(host); | ||||
| 
 | ||||
| 	spin_unlock_irqrestore(&host->lock, flags); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host); | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| /*****************************************************************************\
 | ||||
|  *                                                                           * | ||||
|  * Device allocation/registration                                            * | ||||
|  | @ -2356,6 +2529,8 @@ int sdhci_add_host(struct sdhci_host *host) | |||
| 
 | ||||
| 	if (debug_quirks) | ||||
| 		host->quirks = debug_quirks; | ||||
| 	if (debug_quirks2) | ||||
| 		host->quirks2 = debug_quirks2; | ||||
| 
 | ||||
| 	sdhci_reset(host, SDHCI_RESET_ALL); | ||||
| 
 | ||||
|  | @ -2363,7 +2538,7 @@ int sdhci_add_host(struct sdhci_host *host) | |||
| 	host->version = (host->version & SDHCI_SPEC_VER_MASK) | ||||
| 				>> SDHCI_SPEC_VER_SHIFT; | ||||
| 	if (host->version > SDHCI_SPEC_300) { | ||||
| 		printk(KERN_ERR "%s: Unknown controller version (%d). " | ||||
| 		pr_err("%s: Unknown controller version (%d). " | ||||
| 			"You may experience problems.\n", mmc_hostname(mmc), | ||||
| 			host->version); | ||||
| 	} | ||||
|  | @ -2400,7 +2575,7 @@ int sdhci_add_host(struct sdhci_host *host) | |||
| 	if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { | ||||
| 		if (host->ops->enable_dma) { | ||||
| 			if (host->ops->enable_dma(host)) { | ||||
| 				printk(KERN_WARNING "%s: No suitable DMA " | ||||
| 				pr_warning("%s: No suitable DMA " | ||||
| 					"available. Falling back to PIO.\n", | ||||
| 					mmc_hostname(mmc)); | ||||
| 				host->flags &= | ||||
|  | @ -2420,7 +2595,7 @@ int sdhci_add_host(struct sdhci_host *host) | |||
| 		if (!host->adma_desc || !host->align_buffer) { | ||||
| 			kfree(host->adma_desc); | ||||
| 			kfree(host->align_buffer); | ||||
| 			printk(KERN_WARNING "%s: Unable to allocate ADMA " | ||||
| 			pr_warning("%s: Unable to allocate ADMA " | ||||
| 				"buffers. Falling back to standard DMA.\n", | ||||
| 				mmc_hostname(mmc)); | ||||
| 			host->flags &= ~SDHCI_USE_ADMA; | ||||
|  | @ -2448,8 +2623,7 @@ int sdhci_add_host(struct sdhci_host *host) | |||
| 	if (host->max_clk == 0 || host->quirks & | ||||
| 			SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) { | ||||
| 		if (!host->ops->get_max_clock) { | ||||
| 			printk(KERN_ERR | ||||
| 			       "%s: Hardware doesn't specify base clock " | ||||
| 			pr_err("%s: Hardware doesn't specify base clock " | ||||
| 			       "frequency.\n", mmc_hostname(mmc)); | ||||
| 			return -ENODEV; | ||||
| 		} | ||||
|  | @ -2495,8 +2669,7 @@ int sdhci_add_host(struct sdhci_host *host) | |||
| 			host->timeout_clk = host->ops->get_timeout_clock(host); | ||||
| 		} else if (!(host->quirks & | ||||
| 				SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) { | ||||
| 			printk(KERN_ERR | ||||
| 			       "%s: Hardware doesn't specify timeout clock " | ||||
| 			pr_err("%s: Hardware doesn't specify timeout clock " | ||||
| 			       "frequency.\n", mmc_hostname(mmc)); | ||||
| 			return -ENODEV; | ||||
| 		} | ||||
|  | @ -2566,6 +2739,15 @@ int sdhci_add_host(struct sdhci_host *host) | |||
| 	if (caps[1] & SDHCI_DRIVER_TYPE_D) | ||||
| 		mmc->caps |= MMC_CAP_DRIVER_TYPE_D; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If Power Off Notify capability is enabled by the host, | ||||
| 	 * set notify to short power off notify timeout value. | ||||
| 	 */ | ||||
| 	if (mmc->caps2 & MMC_CAP2_POWEROFF_NOTIFY) | ||||
| 		mmc->power_notify_type = MMC_HOST_PW_NOTIFY_SHORT; | ||||
| 	else | ||||
| 		mmc->power_notify_type = MMC_HOST_PW_NOTIFY_NONE; | ||||
| 
 | ||||
| 	/* Initial value for re-tuning timer count */ | ||||
| 	host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >> | ||||
| 			      SDHCI_RETUNING_TIMER_COUNT_SHIFT; | ||||
|  | @ -2655,7 +2837,7 @@ int sdhci_add_host(struct sdhci_host *host) | |||
| 		mmc->ocr_avail_mmc &= host->ocr_avail_mmc; | ||||
| 
 | ||||
| 	if (mmc->ocr_avail == 0) { | ||||
| 		printk(KERN_ERR "%s: Hardware doesn't report any " | ||||
| 		pr_err("%s: Hardware doesn't report any " | ||||
| 			"support voltages.\n", mmc_hostname(mmc)); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
|  | @ -2703,7 +2885,7 @@ int sdhci_add_host(struct sdhci_host *host) | |||
| 		mmc->max_blk_size = (caps[0] & SDHCI_MAX_BLOCK_MASK) >> | ||||
| 				SDHCI_MAX_BLOCK_SHIFT; | ||||
| 		if (mmc->max_blk_size >= 3) { | ||||
| 			printk(KERN_WARNING "%s: Invalid maximum block size, " | ||||
| 			pr_warning("%s: Invalid maximum block size, " | ||||
| 				"assuming 512 bytes\n", mmc_hostname(mmc)); | ||||
| 			mmc->max_blk_size = 0; | ||||
| 		} | ||||
|  | @ -2742,7 +2924,7 @@ int sdhci_add_host(struct sdhci_host *host) | |||
| 
 | ||||
| 	host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); | ||||
| 	if (IS_ERR(host->vmmc)) { | ||||
| 		printk(KERN_INFO "%s: no vmmc regulator found\n", mmc_hostname(mmc)); | ||||
| 		pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); | ||||
| 		host->vmmc = NULL; | ||||
| 	} else { | ||||
| 		regulator_enable(host->vmmc); | ||||
|  | @ -2771,7 +2953,7 @@ int sdhci_add_host(struct sdhci_host *host) | |||
| 
 | ||||
| 	mmc_add_host(mmc); | ||||
| 
 | ||||
| 	printk(KERN_INFO "%s: SDHCI controller on %s [%s] using %s\n", | ||||
| 	pr_info("%s: SDHCI controller on %s [%s] using %s\n", | ||||
| 		mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)), | ||||
| 		(host->flags & SDHCI_USE_ADMA) ? "ADMA" : | ||||
| 		(host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO"); | ||||
|  | @ -2804,7 +2986,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) | |||
| 		host->flags |= SDHCI_DEVICE_DEAD; | ||||
| 
 | ||||
| 		if (host->mrq) { | ||||
| 			printk(KERN_ERR "%s: Controller removed during " | ||||
| 			pr_err("%s: Controller removed during " | ||||
| 				" transfer!\n", mmc_hostname(host->mmc)); | ||||
| 
 | ||||
| 			host->mrq->cmd->error = -ENOMEDIUM; | ||||
|  | @ -2863,9 +3045,9 @@ EXPORT_SYMBOL_GPL(sdhci_free_host); | |||
| 
 | ||||
| static int __init sdhci_drv_init(void) | ||||
| { | ||||
| 	printk(KERN_INFO DRIVER_NAME | ||||
| 	pr_info(DRIVER_NAME | ||||
| 		": Secure Digital Host Controller Interface driver\n"); | ||||
| 	printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); | ||||
| 	pr_info(DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | @ -2878,9 +3060,11 @@ module_init(sdhci_drv_init); | |||
| module_exit(sdhci_drv_exit); | ||||
| 
 | ||||
| module_param(debug_quirks, uint, 0444); | ||||
| module_param(debug_quirks2, uint, 0444); | ||||
| 
 | ||||
| MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>"); | ||||
| MODULE_DESCRIPTION("Secure Digital Host Controller Interface core driver"); | ||||
| MODULE_LICENSE("GPL"); | ||||
| 
 | ||||
| MODULE_PARM_DESC(debug_quirks, "Force certain quirks."); | ||||
| MODULE_PARM_DESC(debug_quirks2, "Force certain other quirks."); | ||||
|  |  | |||
|  | @ -273,7 +273,7 @@ struct sdhci_ops { | |||
| 	void	(*platform_reset_enter)(struct sdhci_host *host, u8 mask); | ||||
| 	void	(*platform_reset_exit)(struct sdhci_host *host, u8 mask); | ||||
| 	int	(*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); | ||||
| 
 | ||||
| 	void	(*hw_reset)(struct sdhci_host *host); | ||||
| }; | ||||
| 
 | ||||
| #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS | ||||
|  | @ -379,4 +379,9 @@ extern int sdhci_resume_host(struct sdhci_host *host); | |||
| extern void sdhci_enable_irq_wakeups(struct sdhci_host *host); | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_PM_RUNTIME | ||||
| extern int sdhci_runtime_suspend_host(struct sdhci_host *host); | ||||
| extern int sdhci_runtime_resume_host(struct sdhci_host *host); | ||||
| #endif | ||||
| 
 | ||||
| #endif /* __SDHCI_HW_H */ | ||||
|  |  | |||
|  | @ -26,6 +26,7 @@ | |||
| */ | ||||
| #include <linux/delay.h> | ||||
| #include <linux/highmem.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/pci.h> | ||||
| #include <linux/ioport.h> | ||||
| #include <linux/scatterlist.h> | ||||
|  |  | |||
|  | @ -31,6 +31,7 @@ | |||
| #include <linux/platform_device.h> | ||||
| #include <linux/pm_runtime.h> | ||||
| #include <linux/spinlock.h> | ||||
| #include <linux/module.h> | ||||
| 
 | ||||
| #define DRIVER_NAME	"sh_mmcif" | ||||
| #define DRIVER_VERSION	"2010-04-28" | ||||
|  | @ -165,6 +166,8 @@ struct sh_mmcif_host { | |||
| 	struct mmc_host *mmc; | ||||
| 	struct mmc_data *data; | ||||
| 	struct platform_device *pd; | ||||
| 	struct sh_dmae_slave dma_slave_tx; | ||||
| 	struct sh_dmae_slave dma_slave_rx; | ||||
| 	struct clk *hclk; | ||||
| 	unsigned int clk; | ||||
| 	int bus_width; | ||||
|  | @ -323,25 +326,35 @@ static bool sh_mmcif_filter(struct dma_chan *chan, void *arg) | |||
| static void sh_mmcif_request_dma(struct sh_mmcif_host *host, | ||||
| 				 struct sh_mmcif_plat_data *pdata) | ||||
| { | ||||
| 	struct sh_dmae_slave *tx, *rx; | ||||
| 	host->dma_active = false; | ||||
| 
 | ||||
| 	/* We can only either use DMA for both Tx and Rx or not use it at all */ | ||||
| 	if (pdata->dma) { | ||||
| 		dev_warn(&host->pd->dev, | ||||
| 			 "Update your platform to use embedded DMA slave IDs\n"); | ||||
| 		tx = &pdata->dma->chan_priv_tx; | ||||
| 		rx = &pdata->dma->chan_priv_rx; | ||||
| 	} else { | ||||
| 		tx = &host->dma_slave_tx; | ||||
| 		tx->slave_id = pdata->slave_id_tx; | ||||
| 		rx = &host->dma_slave_rx; | ||||
| 		rx->slave_id = pdata->slave_id_rx; | ||||
| 	} | ||||
| 	if (tx->slave_id > 0 && rx->slave_id > 0) { | ||||
| 		dma_cap_mask_t mask; | ||||
| 
 | ||||
| 		dma_cap_zero(mask); | ||||
| 		dma_cap_set(DMA_SLAVE, mask); | ||||
| 
 | ||||
| 		host->chan_tx = dma_request_channel(mask, sh_mmcif_filter, | ||||
| 						    &pdata->dma->chan_priv_tx); | ||||
| 		host->chan_tx = dma_request_channel(mask, sh_mmcif_filter, tx); | ||||
| 		dev_dbg(&host->pd->dev, "%s: TX: got channel %p\n", __func__, | ||||
| 			host->chan_tx); | ||||
| 
 | ||||
| 		if (!host->chan_tx) | ||||
| 			return; | ||||
| 
 | ||||
| 		host->chan_rx = dma_request_channel(mask, sh_mmcif_filter, | ||||
| 						    &pdata->dma->chan_priv_rx); | ||||
| 		host->chan_rx = dma_request_channel(mask, sh_mmcif_filter, rx); | ||||
| 		dev_dbg(&host->pd->dev, "%s: RX: got channel %p\n", __func__, | ||||
| 			host->chan_rx); | ||||
| 
 | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ | |||
| #include <linux/kernel.h> | ||||
| #include <linux/clk.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/mmc/host.h> | ||||
| #include <linux/mmc/sh_mobile_sdhi.h> | ||||
|  | @ -96,7 +97,8 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) | |||
| 	struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; | ||||
| 	struct tmio_mmc_host *host; | ||||
| 	char clk_name[8]; | ||||
| 	int i, irq, ret; | ||||
| 	int irq, ret, i = 0; | ||||
| 	bool multiplexed_isr = true; | ||||
| 
 | ||||
| 	priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL); | ||||
| 	if (priv == NULL) { | ||||
|  | @ -153,27 +155,60 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) | |||
| 	if (ret < 0) | ||||
| 		goto eprobe; | ||||
| 
 | ||||
| 	for (i = 0; i < 3; i++) { | ||||
| 		irq = platform_get_irq(pdev, i); | ||||
| 		if (irq < 0) { | ||||
| 			if (i) { | ||||
| 				continue; | ||||
| 			} else { | ||||
| 				ret = irq; | ||||
| 				goto eirq; | ||||
| 			} | ||||
| 		} | ||||
| 		ret = request_irq(irq, tmio_mmc_irq, 0, | ||||
| 	/*
 | ||||
| 	 * Allow one or more specific (named) ISRs or | ||||
| 	 * one or more multiplexed (un-named) ISRs. | ||||
| 	 */ | ||||
| 
 | ||||
| 	irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_CARD_DETECT); | ||||
| 	if (irq >= 0) { | ||||
| 		multiplexed_isr = false; | ||||
| 		ret = request_irq(irq, tmio_mmc_card_detect_irq, 0, | ||||
| 				  dev_name(&pdev->dev), host); | ||||
| 		if (ret) { | ||||
| 			while (i--) { | ||||
| 				irq = platform_get_irq(pdev, i); | ||||
| 				if (irq >= 0) | ||||
| 					free_irq(irq, host); | ||||
| 			} | ||||
| 			goto eirq; | ||||
| 		} | ||||
| 		if (ret) | ||||
| 			goto eirq_card_detect; | ||||
| 	} | ||||
| 
 | ||||
| 	irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDIO); | ||||
| 	if (irq >= 0) { | ||||
| 		multiplexed_isr = false; | ||||
| 		ret = request_irq(irq, tmio_mmc_sdio_irq, 0, | ||||
| 				  dev_name(&pdev->dev), host); | ||||
| 		if (ret) | ||||
| 			goto eirq_sdio; | ||||
| 	} | ||||
| 
 | ||||
| 	irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDCARD); | ||||
| 	if (irq >= 0) { | ||||
| 		multiplexed_isr = false; | ||||
| 		ret = request_irq(irq, tmio_mmc_sdcard_irq, 0, | ||||
| 				  dev_name(&pdev->dev), host); | ||||
| 		if (ret) | ||||
| 			goto eirq_sdcard; | ||||
| 	} else if (!multiplexed_isr) { | ||||
| 		dev_err(&pdev->dev, | ||||
| 			"Principal SD-card IRQ is missing among named interrupts\n"); | ||||
| 		ret = irq; | ||||
| 		goto eirq_sdcard; | ||||
| 	} | ||||
| 
 | ||||
| 	if (multiplexed_isr) { | ||||
| 		while (1) { | ||||
| 			irq = platform_get_irq(pdev, i); | ||||
| 			if (irq < 0) | ||||
| 				break; | ||||
| 			i++; | ||||
| 			ret = request_irq(irq, tmio_mmc_irq, 0, | ||||
| 					  dev_name(&pdev->dev), host); | ||||
| 			if (ret) | ||||
| 				goto eirq_multiplexed; | ||||
| 		} | ||||
| 
 | ||||
| 		/* There must be at least one IRQ source */ | ||||
| 		if (!i) | ||||
| 			goto eirq_multiplexed; | ||||
| 	} | ||||
| 
 | ||||
| 	dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n", | ||||
| 		 mmc_hostname(host->mmc), (unsigned long) | ||||
| 		 (platform_get_resource(pdev,IORESOURCE_MEM, 0)->start), | ||||
|  | @ -181,7 +216,20 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) | |||
| 
 | ||||
| 	return ret; | ||||
| 
 | ||||
| eirq: | ||||
| eirq_multiplexed: | ||||
| 	while (i--) { | ||||
| 		irq = platform_get_irq(pdev, i); | ||||
| 		free_irq(irq, host); | ||||
| 	} | ||||
| eirq_sdcard: | ||||
| 	irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDIO); | ||||
| 	if (irq >= 0) | ||||
| 		free_irq(irq, host); | ||||
| eirq_sdio: | ||||
| 	irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_CARD_DETECT); | ||||
| 	if (irq >= 0) | ||||
| 		free_irq(irq, host); | ||||
| eirq_card_detect: | ||||
| 	tmio_mmc_host_remove(host); | ||||
| eprobe: | ||||
| 	clk_disable(priv->clk); | ||||
|  | @ -197,16 +245,17 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev) | |||
| 	struct tmio_mmc_host *host = mmc_priv(mmc); | ||||
| 	struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data); | ||||
| 	struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; | ||||
| 	int i, irq; | ||||
| 	int i = 0, irq; | ||||
| 
 | ||||
| 	p->pdata = NULL; | ||||
| 
 | ||||
| 	tmio_mmc_host_remove(host); | ||||
| 
 | ||||
| 	for (i = 0; i < 3; i++) { | ||||
| 		irq = platform_get_irq(pdev, i); | ||||
| 		if (irq >= 0) | ||||
| 			free_irq(irq, host); | ||||
| 	while (1) { | ||||
| 		irq = platform_get_irq(pdev, i++); | ||||
| 		if (irq < 0) | ||||
| 			break; | ||||
| 		free_irq(irq, host); | ||||
| 	} | ||||
| 
 | ||||
| 	clk_disable(priv->clk); | ||||
|  |  | |||
|  | @ -16,6 +16,7 @@ | |||
| #include <linux/mmc/host.h> | ||||
| #include <linux/highmem.h> | ||||
| #include <linux/scatterlist.h> | ||||
| #include <linux/module.h> | ||||
| #include <asm/io.h> | ||||
| 
 | ||||
| #define DRIVER_NAME "tifm_sd" | ||||
|  | @ -631,7 +632,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
| 	} | ||||
| 
 | ||||
| 	if (host->req) { | ||||
| 		printk(KERN_ERR "%s : unfinished request detected\n", | ||||
| 		pr_err("%s : unfinished request detected\n", | ||||
| 		       dev_name(&sock->dev)); | ||||
| 		mrq->cmd->error = -ETIMEDOUT; | ||||
| 		goto err_out; | ||||
|  | @ -671,7 +672,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
| 					    r_data->flags & MMC_DATA_WRITE | ||||
| 					    ? PCI_DMA_TODEVICE | ||||
| 					    : PCI_DMA_FROMDEVICE)) { | ||||
| 				printk(KERN_ERR "%s : scatterlist map failed\n", | ||||
| 				pr_err("%s : scatterlist map failed\n", | ||||
| 				       dev_name(&sock->dev)); | ||||
| 				mrq->cmd->error = -ENOMEM; | ||||
| 				goto err_out; | ||||
|  | @ -683,7 +684,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
| 						   ? PCI_DMA_TODEVICE | ||||
| 						   : PCI_DMA_FROMDEVICE); | ||||
| 			if (host->sg_len < 1) { | ||||
| 				printk(KERN_ERR "%s : scatterlist map failed\n", | ||||
| 				pr_err("%s : scatterlist map failed\n", | ||||
| 				       dev_name(&sock->dev)); | ||||
| 				tifm_unmap_sg(sock, &host->bounce_buf, 1, | ||||
| 					      r_data->flags & MMC_DATA_WRITE | ||||
|  | @ -747,7 +748,7 @@ static void tifm_sd_end_cmd(unsigned long data) | |||
| 	host->req = NULL; | ||||
| 
 | ||||
| 	if (!mrq) { | ||||
| 		printk(KERN_ERR " %s : no request to complete?\n", | ||||
| 		pr_err(" %s : no request to complete?\n", | ||||
| 		       dev_name(&sock->dev)); | ||||
| 		spin_unlock_irqrestore(&sock->lock, flags); | ||||
| 		return; | ||||
|  | @ -786,8 +787,7 @@ static void tifm_sd_abort(unsigned long data) | |||
| { | ||||
| 	struct tifm_sd *host = (struct tifm_sd*)data; | ||||
| 
 | ||||
| 	printk(KERN_ERR | ||||
| 	       "%s : card failed to respond for a long period of time " | ||||
| 	pr_err("%s : card failed to respond for a long period of time " | ||||
| 	       "(%x, %x)\n", | ||||
| 	       dev_name(&host->dev->dev), host->req->cmd->opcode, host->cmd_flags); | ||||
| 
 | ||||
|  | @ -905,7 +905,7 @@ static int tifm_sd_initialize_host(struct tifm_sd *host) | |||
| 	} | ||||
| 
 | ||||
| 	if (rc) { | ||||
| 		printk(KERN_ERR "%s : controller failed to reset\n", | ||||
| 		pr_err("%s : controller failed to reset\n", | ||||
| 		       dev_name(&sock->dev)); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
|  | @ -931,8 +931,7 @@ static int tifm_sd_initialize_host(struct tifm_sd *host) | |||
| 	} | ||||
| 
 | ||||
| 	if (rc) { | ||||
| 		printk(KERN_ERR | ||||
| 		       "%s : card not ready - probe failed on initialization\n", | ||||
| 		pr_err("%s : card not ready - probe failed on initialization\n", | ||||
| 		       dev_name(&sock->dev)); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
|  | @ -953,7 +952,7 @@ static int tifm_sd_probe(struct tifm_dev *sock) | |||
| 
 | ||||
| 	if (!(TIFM_SOCK_STATE_OCCUPIED | ||||
| 	      & readl(sock->addr + SOCK_PRESENT_STATE))) { | ||||
| 		printk(KERN_WARNING "%s : card gone, unexpectedly\n", | ||||
| 		pr_warning("%s : card gone, unexpectedly\n", | ||||
| 		       dev_name(&sock->dev)); | ||||
| 		return rc; | ||||
| 	} | ||||
|  |  | |||
|  | @ -88,8 +88,8 @@ static int __devinit tmio_mmc_probe(struct platform_device *pdev) | |||
| 	if (ret) | ||||
| 		goto cell_disable; | ||||
| 
 | ||||
| 	ret = request_irq(irq, tmio_mmc_irq, IRQF_DISABLED | | ||||
| 			  IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), host); | ||||
| 	ret = request_irq(irq, tmio_mmc_irq, IRQF_TRIGGER_FALLING, | ||||
| 				dev_name(&pdev->dev), host); | ||||
| 	if (ret) | ||||
| 		goto host_remove; | ||||
| 
 | ||||
|  |  | |||
|  | @ -79,6 +79,10 @@ struct tmio_mmc_host { | |||
| 	struct delayed_work	delayed_reset_work; | ||||
| 	struct work_struct	done; | ||||
| 
 | ||||
| 	/* Cache IRQ mask */ | ||||
| 	u32			sdcard_irq_mask; | ||||
| 	u32			sdio_irq_mask; | ||||
| 
 | ||||
| 	spinlock_t		lock;		/* protect host private data */ | ||||
| 	unsigned long		last_req_ts; | ||||
| 	struct mutex		ios_lock;	/* protect set_ios() context */ | ||||
|  | @ -93,6 +97,9 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host); | |||
| void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i); | ||||
| void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i); | ||||
| irqreturn_t tmio_mmc_irq(int irq, void *devid); | ||||
| irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid); | ||||
| irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid); | ||||
| irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid); | ||||
| 
 | ||||
| static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg, | ||||
| 					 unsigned long *flags) | ||||
|  |  | |||
|  | @ -48,14 +48,14 @@ | |||
| 
 | ||||
| void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i) | ||||
| { | ||||
| 	u32 mask = sd_ctrl_read32(host, CTL_IRQ_MASK) & ~(i & TMIO_MASK_IRQ); | ||||
| 	sd_ctrl_write32(host, CTL_IRQ_MASK, mask); | ||||
| 	host->sdcard_irq_mask &= ~(i & TMIO_MASK_IRQ); | ||||
| 	sd_ctrl_write32(host, CTL_IRQ_MASK, host->sdcard_irq_mask); | ||||
| } | ||||
| 
 | ||||
| void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i) | ||||
| { | ||||
| 	u32 mask = sd_ctrl_read32(host, CTL_IRQ_MASK) | (i & TMIO_MASK_IRQ); | ||||
| 	sd_ctrl_write32(host, CTL_IRQ_MASK, mask); | ||||
| 	host->sdcard_irq_mask |= (i & TMIO_MASK_IRQ); | ||||
| 	sd_ctrl_write32(host, CTL_IRQ_MASK, host->sdcard_irq_mask); | ||||
| } | ||||
| 
 | ||||
| static void tmio_mmc_ack_mmc_irqs(struct tmio_mmc_host *host, u32 i) | ||||
|  | @ -92,7 +92,7 @@ static int tmio_mmc_next_sg(struct tmio_mmc_host *host) | |||
| static void pr_debug_status(u32 status) | ||||
| { | ||||
| 	int i = 0; | ||||
| 	printk(KERN_DEBUG "status: %08x = ", status); | ||||
| 	pr_debug("status: %08x = ", status); | ||||
| 	STATUS_TO_TEXT(CARD_REMOVE, status, i); | ||||
| 	STATUS_TO_TEXT(CARD_INSERT, status, i); | ||||
| 	STATUS_TO_TEXT(SIGSTATE, status, i); | ||||
|  | @ -127,11 +127,13 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) | |||
| 
 | ||||
| 	if (enable) { | ||||
| 		host->sdio_irq_enabled = 1; | ||||
| 		host->sdio_irq_mask = TMIO_SDIO_MASK_ALL & | ||||
| 					~TMIO_SDIO_STAT_IOIRQ; | ||||
| 		sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001); | ||||
| 		sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, | ||||
| 			(TMIO_SDIO_MASK_ALL & ~TMIO_SDIO_STAT_IOIRQ)); | ||||
| 		sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask); | ||||
| 	} else { | ||||
| 		sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, TMIO_SDIO_MASK_ALL); | ||||
| 		host->sdio_irq_mask = TMIO_SDIO_MASK_ALL; | ||||
| 		sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask); | ||||
| 		sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0000); | ||||
| 		host->sdio_irq_enabled = 0; | ||||
| 	} | ||||
|  | @ -543,45 +545,20 @@ out: | |||
| 	spin_unlock(&host->lock); | ||||
| } | ||||
| 
 | ||||
| irqreturn_t tmio_mmc_irq(int irq, void *devid) | ||||
| static void tmio_mmc_card_irq_status(struct tmio_mmc_host *host, | ||||
| 				       int *ireg, int *status) | ||||
| { | ||||
| 	*status = sd_ctrl_read32(host, CTL_STATUS); | ||||
| 	*ireg = *status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask; | ||||
| 
 | ||||
| 	pr_debug_status(*status); | ||||
| 	pr_debug_status(*ireg); | ||||
| } | ||||
| 
 | ||||
| static bool __tmio_mmc_card_detect_irq(struct tmio_mmc_host *host, | ||||
| 				      int ireg, int status) | ||||
| { | ||||
| 	struct tmio_mmc_host *host = devid; | ||||
| 	struct mmc_host *mmc = host->mmc; | ||||
| 	struct tmio_mmc_data *pdata = host->pdata; | ||||
| 	unsigned int ireg, irq_mask, status; | ||||
| 	unsigned int sdio_ireg, sdio_irq_mask, sdio_status; | ||||
| 
 | ||||
| 	pr_debug("MMC IRQ begin\n"); | ||||
| 
 | ||||
| 	status = sd_ctrl_read32(host, CTL_STATUS); | ||||
| 	irq_mask = sd_ctrl_read32(host, CTL_IRQ_MASK); | ||||
| 	ireg = status & TMIO_MASK_IRQ & ~irq_mask; | ||||
| 
 | ||||
| 	sdio_ireg = 0; | ||||
| 	if (!ireg && pdata->flags & TMIO_MMC_SDIO_IRQ) { | ||||
| 		sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS); | ||||
| 		sdio_irq_mask = sd_ctrl_read16(host, CTL_SDIO_IRQ_MASK); | ||||
| 		sdio_ireg = sdio_status & TMIO_SDIO_MASK_ALL & ~sdio_irq_mask; | ||||
| 
 | ||||
| 		sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status & ~TMIO_SDIO_MASK_ALL); | ||||
| 
 | ||||
| 		if (sdio_ireg && !host->sdio_irq_enabled) { | ||||
| 			pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n", | ||||
| 				   sdio_status, sdio_irq_mask, sdio_ireg); | ||||
| 			tmio_mmc_enable_sdio_irq(mmc, 0); | ||||
| 			goto out; | ||||
| 		} | ||||
| 
 | ||||
| 		if (mmc->caps & MMC_CAP_SDIO_IRQ && | ||||
| 			sdio_ireg & TMIO_SDIO_STAT_IOIRQ) | ||||
| 			mmc_signal_sdio_irq(mmc); | ||||
| 
 | ||||
| 		if (sdio_ireg) | ||||
| 			goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	pr_debug_status(status); | ||||
| 	pr_debug_status(ireg); | ||||
| 
 | ||||
| 	/* Card insert / remove attempts */ | ||||
| 	if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) { | ||||
|  | @ -591,43 +568,102 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid) | |||
| 		     ((ireg & TMIO_STAT_CARD_INSERT) && !mmc->card)) && | ||||
| 		    !work_pending(&mmc->detect.work)) | ||||
| 			mmc_detect_change(host->mmc, msecs_to_jiffies(100)); | ||||
| 		goto out; | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	/* CRC and other errors */ | ||||
| /*	if (ireg & TMIO_STAT_ERR_IRQ)
 | ||||
|  *		handled |= tmio_error_irq(host, irq, stat); | ||||
|  */ | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid) | ||||
| { | ||||
| 	unsigned int ireg, status; | ||||
| 	struct tmio_mmc_host *host = devid; | ||||
| 
 | ||||
| 	tmio_mmc_card_irq_status(host, &ireg, &status); | ||||
| 	__tmio_mmc_card_detect_irq(host, ireg, status); | ||||
| 
 | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
| EXPORT_SYMBOL(tmio_mmc_card_detect_irq); | ||||
| 
 | ||||
| static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host, | ||||
| 				 int ireg, int status) | ||||
| { | ||||
| 	/* Command completion */ | ||||
| 	if (ireg & (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT)) { | ||||
| 		tmio_mmc_ack_mmc_irqs(host, | ||||
| 			     TMIO_STAT_CMDRESPEND | | ||||
| 			     TMIO_STAT_CMDTIMEOUT); | ||||
| 		tmio_mmc_cmd_irq(host, status); | ||||
| 		goto out; | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Data transfer */ | ||||
| 	if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) { | ||||
| 		tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ); | ||||
| 		tmio_mmc_pio_irq(host); | ||||
| 		goto out; | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Data transfer completion */ | ||||
| 	if (ireg & TMIO_STAT_DATAEND) { | ||||
| 		tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_DATAEND); | ||||
| 		tmio_mmc_data_irq(host); | ||||
| 		goto out; | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	pr_warning("tmio_mmc: Spurious irq, disabling! " | ||||
| 		"0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg); | ||||
| 	pr_debug_status(status); | ||||
| 	tmio_mmc_disable_mmc_irqs(host, status & ~irq_mask); | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid) | ||||
| { | ||||
| 	unsigned int ireg, status; | ||||
| 	struct tmio_mmc_host *host = devid; | ||||
| 
 | ||||
| 	tmio_mmc_card_irq_status(host, &ireg, &status); | ||||
| 	__tmio_mmc_sdcard_irq(host, ireg, status); | ||||
| 
 | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
| EXPORT_SYMBOL(tmio_mmc_sdcard_irq); | ||||
| 
 | ||||
| irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid) | ||||
| { | ||||
| 	struct tmio_mmc_host *host = devid; | ||||
| 	struct mmc_host *mmc = host->mmc; | ||||
| 	struct tmio_mmc_data *pdata = host->pdata; | ||||
| 	unsigned int ireg, status; | ||||
| 
 | ||||
| 	if (!(pdata->flags & TMIO_MMC_SDIO_IRQ)) | ||||
| 		return IRQ_HANDLED; | ||||
| 
 | ||||
| 	status = sd_ctrl_read16(host, CTL_SDIO_STATUS); | ||||
| 	ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdcard_irq_mask; | ||||
| 
 | ||||
| 	sd_ctrl_write16(host, CTL_SDIO_STATUS, status & ~TMIO_SDIO_MASK_ALL); | ||||
| 
 | ||||
| 	if (mmc->caps & MMC_CAP_SDIO_IRQ && ireg & TMIO_SDIO_STAT_IOIRQ) | ||||
| 		mmc_signal_sdio_irq(mmc); | ||||
| 
 | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
| EXPORT_SYMBOL(tmio_mmc_sdio_irq); | ||||
| 
 | ||||
| irqreturn_t tmio_mmc_irq(int irq, void *devid) | ||||
| { | ||||
| 	struct tmio_mmc_host *host = devid; | ||||
| 	unsigned int ireg, status; | ||||
| 
 | ||||
| 	pr_debug("MMC IRQ begin\n"); | ||||
| 
 | ||||
| 	tmio_mmc_card_irq_status(host, &ireg, &status); | ||||
| 	if (__tmio_mmc_card_detect_irq(host, ireg, status)) | ||||
| 		return IRQ_HANDLED; | ||||
| 	if (__tmio_mmc_sdcard_irq(host, ireg, status)) | ||||
| 		return IRQ_HANDLED; | ||||
| 
 | ||||
| 	tmio_mmc_sdio_irq(irq, devid); | ||||
| 
 | ||||
| out: | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
| EXPORT_SYMBOL(tmio_mmc_irq); | ||||
|  | @ -882,6 +918,7 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, | |||
| 	tmio_mmc_clk_stop(_host); | ||||
| 	tmio_mmc_reset(_host); | ||||
| 
 | ||||
| 	_host->sdcard_irq_mask = sd_ctrl_read32(_host, CTL_IRQ_MASK); | ||||
| 	tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL); | ||||
| 	if (pdata->flags & TMIO_MMC_SDIO_IRQ) | ||||
| 		tmio_mmc_enable_sdio_irq(mmc, 0); | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ | |||
|  */ | ||||
| 
 | ||||
| #include <linux/pci.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/dma-mapping.h> | ||||
| #include <linux/highmem.h> | ||||
| #include <linux/delay.h> | ||||
|  | @ -1191,7 +1192,7 @@ static void __devexit via_sd_remove(struct pci_dev *pcidev) | |||
| 	mmiowb(); | ||||
| 
 | ||||
| 	if (sdhost->mrq) { | ||||
| 		printk(KERN_ERR "%s: Controller removed during " | ||||
| 		pr_err("%s: Controller removed during " | ||||
| 			"transfer\n", mmc_hostname(sdhost->mmc)); | ||||
| 
 | ||||
| 		/* make sure all DMA is stopped */ | ||||
|  |  | |||
|  | @ -194,7 +194,7 @@ static void wbsd_reset(struct wbsd_host *host) | |||
| { | ||||
| 	u8 setup; | ||||
| 
 | ||||
| 	printk(KERN_ERR "%s: Resetting chip\n", mmc_hostname(host->mmc)); | ||||
| 	pr_err("%s: Resetting chip\n", mmc_hostname(host->mmc)); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Soft reset of chip (SD/MMC part). | ||||
|  | @ -721,7 +721,7 @@ static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data) | |||
| 		 * Any leftover data? | ||||
| 		 */ | ||||
| 		if (count) { | ||||
| 			printk(KERN_ERR "%s: Incomplete DMA transfer. " | ||||
| 			pr_err("%s: Incomplete DMA transfer. " | ||||
| 				"%d bytes left.\n", | ||||
| 				mmc_hostname(host->mmc), count); | ||||
| 
 | ||||
|  | @ -803,7 +803,7 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
| 
 | ||||
| 		default: | ||||
| #ifdef CONFIG_MMC_DEBUG | ||||
| 			printk(KERN_WARNING "%s: Data command %d is not " | ||||
| 			pr_warning("%s: Data command %d is not " | ||||
| 				"supported by this controller.\n", | ||||
| 				mmc_hostname(host->mmc), cmd->opcode); | ||||
| #endif | ||||
|  | @ -1029,7 +1029,7 @@ static void wbsd_tasklet_card(unsigned long param) | |||
| 		host->flags &= ~WBSD_FCARD_PRESENT; | ||||
| 
 | ||||
| 		if (host->mrq) { | ||||
| 			printk(KERN_ERR "%s: Card removed during transfer!\n", | ||||
| 			pr_err("%s: Card removed during transfer!\n", | ||||
| 				mmc_hostname(host->mmc)); | ||||
| 			wbsd_reset(host); | ||||
| 
 | ||||
|  | @ -1429,7 +1429,7 @@ free: | |||
| 	free_dma(dma); | ||||
| 
 | ||||
| err: | ||||
| 	printk(KERN_WARNING DRIVER_NAME ": Unable to allocate DMA %d. " | ||||
| 	pr_warning(DRIVER_NAME ": Unable to allocate DMA %d. " | ||||
| 		"Falling back on FIFO.\n", dma); | ||||
| } | ||||
| 
 | ||||
|  | @ -1664,7 +1664,7 @@ static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma, | |||
| 	ret = wbsd_scan(host); | ||||
| 	if (ret) { | ||||
| 		if (pnp && (ret == -ENODEV)) { | ||||
| 			printk(KERN_WARNING DRIVER_NAME | ||||
| 			pr_warning(DRIVER_NAME | ||||
| 				": Unable to confirm device presence. You may " | ||||
| 				"experience lock-ups.\n"); | ||||
| 		} else { | ||||
|  | @ -1688,7 +1688,7 @@ static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma, | |||
| 	 */ | ||||
| 	if (pnp) { | ||||
| 		if ((host->config != 0) && !wbsd_chip_validate(host)) { | ||||
| 			printk(KERN_WARNING DRIVER_NAME | ||||
| 			pr_warning(DRIVER_NAME | ||||
| 				": PnP active but chip not configured! " | ||||
| 				"You probably have a buggy BIOS. " | ||||
| 				"Configuring chip manually.\n"); | ||||
|  | @ -1720,7 +1720,7 @@ static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma, | |||
| 
 | ||||
| 	mmc_add_host(mmc); | ||||
| 
 | ||||
| 	printk(KERN_INFO "%s: W83L51xD", mmc_hostname(mmc)); | ||||
| 	pr_info("%s: W83L51xD", mmc_hostname(mmc)); | ||||
| 	if (host->chip_id != 0) | ||||
| 		printk(" id %x", (int)host->chip_id); | ||||
| 	printk(" at 0x%x irq %d", (int)host->base, (int)host->irq); | ||||
|  | @ -1909,7 +1909,7 @@ static int wbsd_pnp_resume(struct pnp_dev *pnp_dev) | |||
| 	 */ | ||||
| 	if (host->config != 0) { | ||||
| 		if (!wbsd_chip_validate(host)) { | ||||
| 			printk(KERN_WARNING DRIVER_NAME | ||||
| 			pr_warning(DRIVER_NAME | ||||
| 				": PnP active but chip not configured! " | ||||
| 				"You probably have a buggy BIOS. " | ||||
| 				"Configuring chip manually.\n"); | ||||
|  | @ -1973,9 +1973,9 @@ static int __init wbsd_drv_init(void) | |||
| { | ||||
| 	int result; | ||||
| 
 | ||||
| 	printk(KERN_INFO DRIVER_NAME | ||||
| 	pr_info(DRIVER_NAME | ||||
| 		": Winbond W83L51xD SD/MMC card interface driver\n"); | ||||
| 	printk(KERN_INFO DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); | ||||
| 	pr_info(DRIVER_NAME ": Copyright(c) Pierre Ossman\n"); | ||||
| 
 | ||||
| #ifdef CONFIG_PNP | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| #ifndef __LINUX_ATMEL_MCI_H | ||||
| #define __LINUX_ATMEL_MCI_H | ||||
| 
 | ||||
| #define ATMEL_MCI_MAX_NR_SLOTS	2 | ||||
| #define ATMCI_MAX_NR_SLOTS	2 | ||||
| 
 | ||||
| /**
 | ||||
|  * struct mci_slot_pdata - board-specific per-slot configuration | ||||
|  | @ -33,7 +33,7 @@ struct mci_slot_pdata { | |||
|  */ | ||||
| struct mci_platform_data { | ||||
| 	struct mci_dma_data	*dma_slave; | ||||
| 	struct mci_slot_pdata	slot[ATMEL_MCI_MAX_NR_SLOTS]; | ||||
| 	struct mci_slot_pdata	slot[ATMCI_MAX_NR_SLOTS]; | ||||
| }; | ||||
| 
 | ||||
| #endif /* __LINUX_ATMEL_MCI_H */ | ||||
|  |  | |||
|  | @ -33,4 +33,6 @@ | |||
| 
 | ||||
| #define ATMEL_PDC_PTSR		0x124	/* Transfer Status Register */ | ||||
| 
 | ||||
| #define ATMEL_PDC_SCND_BUF_OFF	0x10	/* Offset between first and second buffer registers */ | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -50,8 +50,12 @@ struct mmc_ext_csd { | |||
| 	u8			rel_sectors; | ||||
| 	u8			rel_param; | ||||
| 	u8			part_config; | ||||
| 	u8			cache_ctrl; | ||||
| 	u8			rst_n_function; | ||||
| 	unsigned int		part_time;		/* Units: ms */ | ||||
| 	unsigned int		sa_timeout;		/* Units: 100ns */ | ||||
| 	unsigned int		generic_cmd6_time;	/* Units: 10ms */ | ||||
| 	unsigned int            power_off_longtime;     /* Units: ms */ | ||||
| 	unsigned int		hs_max_dtr; | ||||
| 	unsigned int		sectors; | ||||
| 	unsigned int		card_type; | ||||
|  | @ -63,11 +67,15 @@ struct mmc_ext_csd { | |||
| 	bool			enhanced_area_en;	/* enable bit */ | ||||
| 	unsigned long long	enhanced_area_offset;	/* Units: Byte */ | ||||
| 	unsigned int		enhanced_area_size;	/* Units: KB */ | ||||
| 	unsigned int		boot_size;		/* in bytes */ | ||||
| 	unsigned int		cache_size;		/* Units: KB */ | ||||
| 	bool			hpi_en;			/* HPI enablebit */ | ||||
| 	bool			hpi;			/* HPI support bit */ | ||||
| 	unsigned int		hpi_cmd;		/* cmd used as HPI */ | ||||
| 	u8			raw_partition_support;	/* 160 */ | ||||
| 	u8			raw_erased_mem_count;	/* 181 */ | ||||
| 	u8			raw_ext_csd_structure;	/* 194 */ | ||||
| 	u8			raw_card_type;		/* 196 */ | ||||
| 	u8			out_of_int_time;	/* 198 */ | ||||
| 	u8			raw_s_a_timeout;		/* 217 */ | ||||
| 	u8			raw_hc_erase_gap_size;	/* 221 */ | ||||
| 	u8			raw_erase_timeout_mult;	/* 223 */ | ||||
|  | @ -77,6 +85,9 @@ struct mmc_ext_csd { | |||
| 	u8			raw_sec_feature_support;/* 231 */ | ||||
| 	u8			raw_trim_mult;		/* 232 */ | ||||
| 	u8			raw_sectors[4];		/* 212 - 4 bytes */ | ||||
| 
 | ||||
| 	unsigned int            feature_support; | ||||
| #define MMC_DISCARD_FEATURE	BIT(0)                  /* CMD38 feature */ | ||||
| }; | ||||
| 
 | ||||
| struct sd_scr { | ||||
|  | @ -157,6 +168,24 @@ struct sdio_func_tuple; | |||
| 
 | ||||
| #define SDIO_MAX_FUNCS		7 | ||||
| 
 | ||||
| /* The number of MMC physical partitions.  These consist of:
 | ||||
|  * boot partitions (2), general purpose partitions (4) in MMC v4.4. | ||||
|  */ | ||||
| #define MMC_NUM_BOOT_PARTITION	2 | ||||
| #define MMC_NUM_GP_PARTITION	4 | ||||
| #define MMC_NUM_PHY_PARTITION	6 | ||||
| #define MAX_MMC_PART_NAME_LEN	20 | ||||
| 
 | ||||
| /*
 | ||||
|  * MMC Physical partitions | ||||
|  */ | ||||
| struct mmc_part { | ||||
| 	unsigned int	size;	/* partition size (in bytes) */ | ||||
| 	unsigned int	part_cfg;	/* partition type */ | ||||
| 	char	name[MAX_MMC_PART_NAME_LEN]; | ||||
| 	bool	force_ro;	/* to make boot parts RO by default */ | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * MMC device | ||||
|  */ | ||||
|  | @ -188,6 +217,13 @@ struct mmc_card { | |||
| #define MMC_QUIRK_DISABLE_CD	(1<<5)		/* disconnect CD/DAT[3] resistor */ | ||||
| #define MMC_QUIRK_INAND_CMD38	(1<<6)		/* iNAND devices have broken CMD38 */ | ||||
| #define MMC_QUIRK_BLK_NO_CMD23	(1<<7)		/* Avoid CMD23 for regular multiblock */ | ||||
| #define MMC_QUIRK_BROKEN_BYTE_MODE_512 (1<<8)	/* Avoid sending 512 bytes in */ | ||||
| 						/* byte mode */ | ||||
| 	unsigned int    poweroff_notify_state;	/* eMMC4.5 notify feature */ | ||||
| #define MMC_NO_POWER_NOTIFICATION	0 | ||||
| #define MMC_POWERED_ON			1 | ||||
| #define MMC_POWEROFF_SHORT		2 | ||||
| #define MMC_POWEROFF_LONG		3 | ||||
| 
 | ||||
| 	unsigned int		erase_size;	/* erase size in sectors */ | ||||
|  	unsigned int		erase_shift;	/* if erase unit is power 2 */ | ||||
|  | @ -216,8 +252,23 @@ struct mmc_card { | |||
| 	unsigned int		sd_bus_speed;	/* Bus Speed Mode set for the card */ | ||||
| 
 | ||||
| 	struct dentry		*debugfs_root; | ||||
| 	struct mmc_part	part[MMC_NUM_PHY_PARTITION]; /* physical partitions */ | ||||
| 	unsigned int    nr_parts; | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * This function fill contents in mmc_part. | ||||
|  */ | ||||
| static inline void mmc_part_add(struct mmc_card *card, unsigned int size, | ||||
| 			unsigned int part_cfg, char *name, int idx, bool ro) | ||||
| { | ||||
| 	card->part[card->nr_parts].size = size; | ||||
| 	card->part[card->nr_parts].part_cfg = part_cfg; | ||||
| 	sprintf(card->part[card->nr_parts].name, name, idx); | ||||
| 	card->part[card->nr_parts].force_ro = ro; | ||||
| 	card->nr_parts++; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  *  The world is not perfect and supplies us with broken mmc/sdio devices. | ||||
|  *  For at least some of these bugs we need a work-around. | ||||
|  | @ -377,6 +428,11 @@ static inline int mmc_card_nonstd_func_interface(const struct mmc_card *c) | |||
| 	return c->quirks & MMC_QUIRK_NONSTD_FUNC_IF; | ||||
| } | ||||
| 
 | ||||
| static inline int mmc_card_broken_byte_mode_512(const struct mmc_card *c) | ||||
| { | ||||
| 	return c->quirks & MMC_QUIRK_BROKEN_BYTE_MODE_512; | ||||
| } | ||||
| 
 | ||||
| #define mmc_card_name(c)	((c)->cid.prod_name) | ||||
| #define mmc_card_id(c)		(dev_name(&(c)->dev)) | ||||
| 
 | ||||
|  |  | |||
|  | @ -136,6 +136,7 @@ struct mmc_async_req; | |||
| 
 | ||||
| extern struct mmc_async_req *mmc_start_req(struct mmc_host *, | ||||
| 					   struct mmc_async_req *, int *); | ||||
| extern int mmc_interrupt_hpi(struct mmc_card *); | ||||
| extern void mmc_wait_for_req(struct mmc_host *, struct mmc_request *); | ||||
| extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int); | ||||
| extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *); | ||||
|  | @ -146,6 +147,7 @@ extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int); | |||
| #define MMC_ERASE_ARG		0x00000000 | ||||
| #define MMC_SECURE_ERASE_ARG	0x80000000 | ||||
| #define MMC_TRIM_ARG		0x00000001 | ||||
| #define MMC_DISCARD_ARG		0x00000003 | ||||
| #define MMC_SECURE_TRIM1_ARG	0x80000001 | ||||
| #define MMC_SECURE_TRIM2_ARG	0x80008000 | ||||
| 
 | ||||
|  | @ -156,12 +158,17 @@ extern int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr, | |||
| 		     unsigned int arg); | ||||
| extern int mmc_can_erase(struct mmc_card *card); | ||||
| extern int mmc_can_trim(struct mmc_card *card); | ||||
| extern int mmc_can_discard(struct mmc_card *card); | ||||
| extern int mmc_can_sanitize(struct mmc_card *card); | ||||
| extern int mmc_can_secure_erase_trim(struct mmc_card *card); | ||||
| extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from, | ||||
| 				   unsigned int nr); | ||||
| extern unsigned int mmc_calc_max_discard(struct mmc_card *card); | ||||
| 
 | ||||
| extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen); | ||||
| extern int mmc_hw_reset(struct mmc_host *host); | ||||
| extern int mmc_hw_reset_check(struct mmc_host *host); | ||||
| extern int mmc_can_reset(struct mmc_card *card); | ||||
| 
 | ||||
| extern void mmc_set_data_timeout(struct mmc_data *, const struct mmc_card *); | ||||
| extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int); | ||||
|  | @ -171,6 +178,8 @@ extern void mmc_release_host(struct mmc_host *host); | |||
| extern void mmc_do_release_host(struct mmc_host *host); | ||||
| extern int mmc_try_claim_host(struct mmc_host *host); | ||||
| 
 | ||||
| extern int mmc_flush_cache(struct mmc_card *); | ||||
| 
 | ||||
| /**
 | ||||
|  *	mmc_claim_host - exclusively claim a host | ||||
|  *	@host: mmc host to claim | ||||
|  |  | |||
|  | @ -72,6 +72,8 @@ struct mmc_data; | |||
|  *	rate and timeout calculations. | ||||
|  * @current_speed: Configured rate of the controller. | ||||
|  * @num_slots: Number of slots available. | ||||
|  * @verid: Denote Version ID. | ||||
|  * @data_offset: Set the offset of DATA register according to VERID. | ||||
|  * @pdev: Platform device associated with the MMC controller. | ||||
|  * @pdata: Platform data associated with the MMC controller. | ||||
|  * @slot: Slots sharing this MMC controller. | ||||
|  | @ -147,6 +149,8 @@ struct dw_mci { | |||
| 	u32			current_speed; | ||||
| 	u32			num_slots; | ||||
| 	u32			fifoth_val; | ||||
| 	u16			verid; | ||||
| 	u16			data_offset; | ||||
| 	struct platform_device	*pdev; | ||||
| 	struct dw_mci_board	*pdata; | ||||
| 	struct dw_mci_slot	*slot[MAX_MCI_SLOTS]; | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ | |||
| 
 | ||||
| #include <linux/leds.h> | ||||
| #include <linux/sched.h> | ||||
| #include <linux/fault-inject.h> | ||||
| 
 | ||||
| #include <linux/mmc/core.h> | ||||
| #include <linux/mmc/pm.h> | ||||
|  | @ -108,6 +109,9 @@ struct mmc_host_ops { | |||
| 	 * It is optional for the host to implement pre_req and post_req in | ||||
| 	 * order to support double buffering of requests (prepare one | ||||
| 	 * request while another request is active). | ||||
| 	 * pre_req() must always be followed by a post_req(). | ||||
| 	 * To undo a call made to pre_req(), call post_req() with | ||||
| 	 * a nonzero err condition. | ||||
| 	 */ | ||||
| 	void	(*post_req)(struct mmc_host *host, struct mmc_request *req, | ||||
| 			    int err); | ||||
|  | @ -147,6 +151,7 @@ struct mmc_host_ops { | |||
| 	int	(*execute_tuning)(struct mmc_host *host); | ||||
| 	void	(*enable_preset_value)(struct mmc_host *host, bool enable); | ||||
| 	int	(*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv); | ||||
| 	void	(*hw_reset)(struct mmc_host *host); | ||||
| }; | ||||
| 
 | ||||
| struct mmc_card; | ||||
|  | @ -229,8 +234,20 @@ struct mmc_host { | |||
| #define MMC_CAP_MAX_CURRENT_600	(1 << 28)	/* Host max current limit is 600mA */ | ||||
| #define MMC_CAP_MAX_CURRENT_800	(1 << 29)	/* Host max current limit is 800mA */ | ||||
| #define MMC_CAP_CMD23		(1 << 30)	/* CMD23 supported. */ | ||||
| #define MMC_CAP_HW_RESET	(1 << 31)	/* Hardware reset */ | ||||
| 
 | ||||
| 	unsigned int		caps2;		/* More host capabilities */ | ||||
| 
 | ||||
| #define MMC_CAP2_BOOTPART_NOACC	(1 << 0)	/* Boot partition no access */ | ||||
| #define MMC_CAP2_CACHE_CTRL	(1 << 1)	/* Allow cache control */ | ||||
| #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2)	/* Notify poweroff supported */ | ||||
| #define MMC_CAP2_NO_MULTI_READ	(1 << 3)	/* Multiblock reads don't work */ | ||||
| 
 | ||||
| 	mmc_pm_flag_t		pm_caps;	/* supported pm features */ | ||||
| 	unsigned int        power_notify_type; | ||||
| #define MMC_HOST_PW_NOTIFY_NONE		0 | ||||
| #define MMC_HOST_PW_NOTIFY_SHORT	1 | ||||
| #define MMC_HOST_PW_NOTIFY_LONG		2 | ||||
| 
 | ||||
| #ifdef CONFIG_MMC_CLKGATE | ||||
| 	int			clk_requests;	/* internal reference counter */ | ||||
|  | @ -302,6 +319,10 @@ struct mmc_host { | |||
| 
 | ||||
| 	struct mmc_async_req	*areq;		/* active async req */ | ||||
| 
 | ||||
| #ifdef CONFIG_FAIL_MMC_REQUEST | ||||
| 	struct fault_attr	fail_mmc_request; | ||||
| #endif | ||||
| 
 | ||||
| 	unsigned long		private[0] ____cacheline_aligned; | ||||
| }; | ||||
| 
 | ||||
|  | @ -330,6 +351,8 @@ extern int mmc_power_restore_host(struct mmc_host *host); | |||
| extern void mmc_detect_change(struct mmc_host *, unsigned long delay); | ||||
| extern void mmc_request_done(struct mmc_host *, struct mmc_request *); | ||||
| 
 | ||||
| extern int mmc_cache_ctrl(struct mmc_host *, u8); | ||||
| 
 | ||||
| static inline void mmc_signal_sdio_irq(struct mmc_host *host) | ||||
| { | ||||
| 	host->ops->enable_sdio_irq(host, 0); | ||||
|  | @ -394,4 +417,10 @@ static inline int mmc_host_cmd23(struct mmc_host *host) | |||
| { | ||||
| 	return host->caps & MMC_CAP_CMD23; | ||||
| } | ||||
| 
 | ||||
| static inline int mmc_boot_partition_access(struct mmc_host *host) | ||||
| { | ||||
| 	return !(host->caps2 & MMC_CAP2_BOOTPART_NOACC); | ||||
| } | ||||
| 
 | ||||
| #endif /* LINUX_MMC_HOST_H */ | ||||
|  |  | |||
|  | @ -270,18 +270,31 @@ struct _mmc_csd { | |||
|  * EXT_CSD fields | ||||
|  */ | ||||
| 
 | ||||
| #define EXT_CSD_FLUSH_CACHE		32      /* W */ | ||||
| #define EXT_CSD_CACHE_CTRL		33      /* R/W */ | ||||
| #define EXT_CSD_POWER_OFF_NOTIFICATION	34	/* R/W */ | ||||
| #define EXT_CSD_GP_SIZE_MULT		143	/* R/W */ | ||||
| #define EXT_CSD_PARTITION_ATTRIBUTE	156	/* R/W */ | ||||
| #define EXT_CSD_PARTITION_SUPPORT	160	/* RO */ | ||||
| #define EXT_CSD_HPI_MGMT		161	/* R/W */ | ||||
| #define EXT_CSD_RST_N_FUNCTION		162	/* R/W */ | ||||
| #define EXT_CSD_SANITIZE_START		165     /* W */ | ||||
| #define EXT_CSD_WR_REL_PARAM		166	/* RO */ | ||||
| #define EXT_CSD_ERASE_GROUP_DEF		175	/* R/W */ | ||||
| #define EXT_CSD_PART_CONFIG		179	/* R/W */ | ||||
| #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */ | ||||
| #define EXT_CSD_BUS_WIDTH		183	/* R/W */ | ||||
| #define EXT_CSD_HS_TIMING		185	/* R/W */ | ||||
| #define EXT_CSD_POWER_CLASS		187	/* R/W */ | ||||
| #define EXT_CSD_REV			192	/* RO */ | ||||
| #define EXT_CSD_STRUCTURE		194	/* RO */ | ||||
| #define EXT_CSD_CARD_TYPE		196	/* RO */ | ||||
| #define EXT_CSD_OUT_OF_INTERRUPT_TIME	198	/* RO */ | ||||
| #define EXT_CSD_PART_SWITCH_TIME        199     /* RO */ | ||||
| #define EXT_CSD_PWR_CL_52_195		200	/* RO */ | ||||
| #define EXT_CSD_PWR_CL_26_195		201	/* RO */ | ||||
| #define EXT_CSD_PWR_CL_52_360		202	/* RO */ | ||||
| #define EXT_CSD_PWR_CL_26_360		203	/* RO */ | ||||
| #define EXT_CSD_SEC_CNT			212	/* RO, 4 bytes */ | ||||
| #define EXT_CSD_S_A_TIMEOUT		217	/* RO */ | ||||
| #define EXT_CSD_REL_WR_SEC_C		222	/* RO */ | ||||
|  | @ -293,6 +306,14 @@ struct _mmc_csd { | |||
| #define EXT_CSD_SEC_ERASE_MULT		230	/* RO */ | ||||
| #define EXT_CSD_SEC_FEATURE_SUPPORT	231	/* RO */ | ||||
| #define EXT_CSD_TRIM_MULT		232	/* RO */ | ||||
| #define EXT_CSD_PWR_CL_200_195		236	/* RO */ | ||||
| #define EXT_CSD_PWR_CL_200_360		237	/* RO */ | ||||
| #define EXT_CSD_PWR_CL_DDR_52_195	238	/* RO */ | ||||
| #define EXT_CSD_PWR_CL_DDR_52_360	239	/* RO */ | ||||
| #define EXT_CSD_POWER_OFF_LONG_TIME	247	/* RO */ | ||||
| #define EXT_CSD_GENERIC_CMD6_TIME	248	/* RO */ | ||||
| #define EXT_CSD_CACHE_SIZE		249	/* RO, 4 bytes */ | ||||
| #define EXT_CSD_HPI_FEATURES		503	/* RO */ | ||||
| 
 | ||||
| /*
 | ||||
|  * EXT_CSD field definitions | ||||
|  | @ -302,7 +323,9 @@ struct _mmc_csd { | |||
| 
 | ||||
| #define EXT_CSD_PART_CONFIG_ACC_MASK	(0x7) | ||||
| #define EXT_CSD_PART_CONFIG_ACC_BOOT0	(0x1) | ||||
| #define EXT_CSD_PART_CONFIG_ACC_BOOT1	(0x2) | ||||
| #define EXT_CSD_PART_CONFIG_ACC_GP0	(0x4) | ||||
| 
 | ||||
| #define EXT_CSD_PART_SUPPORT_PART_EN	(0x1) | ||||
| 
 | ||||
| #define EXT_CSD_CMD_SET_NORMAL		(1<<0) | ||||
| #define EXT_CSD_CMD_SET_SECURE		(1<<1) | ||||
|  | @ -327,7 +350,20 @@ struct _mmc_csd { | |||
| #define EXT_CSD_SEC_ER_EN	BIT(0) | ||||
| #define EXT_CSD_SEC_BD_BLK_EN	BIT(2) | ||||
| #define EXT_CSD_SEC_GB_CL_EN	BIT(4) | ||||
| #define EXT_CSD_SEC_SANITIZE	BIT(6)  /* v4.5 only */ | ||||
| 
 | ||||
| #define EXT_CSD_RST_N_EN_MASK	0x3 | ||||
| #define EXT_CSD_RST_N_ENABLED	1	/* RST_n is enabled on card */ | ||||
| 
 | ||||
| #define EXT_CSD_NO_POWER_NOTIFICATION	0 | ||||
| #define EXT_CSD_POWER_ON		1 | ||||
| #define EXT_CSD_POWER_OFF_SHORT		2 | ||||
| #define EXT_CSD_POWER_OFF_LONG		3 | ||||
| 
 | ||||
| #define EXT_CSD_PWR_CL_8BIT_MASK	0xF0	/* 8 bit PWR CLS */ | ||||
| #define EXT_CSD_PWR_CL_4BIT_MASK	0x0F	/* 8 bit PWR CLS */ | ||||
| #define EXT_CSD_PWR_CL_8BIT_SHIFT	4 | ||||
| #define EXT_CSD_PWR_CL_4BIT_SHIFT	0 | ||||
| /*
 | ||||
|  * MMC_SWITCH access modes | ||||
|  */ | ||||
|  |  | |||
|  | @ -88,6 +88,10 @@ struct sdhci_host { | |||
| /* The read-only detection via SDHCI_PRESENT_STATE register is unstable */ | ||||
| #define SDHCI_QUIRK_UNSTABLE_RO_DETECT			(1<<31) | ||||
| 
 | ||||
| 	unsigned int quirks2;	/* More deviations from spec. */ | ||||
| 
 | ||||
| #define SDHCI_QUIRK2_OWN_CARD_DETECTION			(1<<0) | ||||
| 
 | ||||
| 	int irq;		/* Device IRQ */ | ||||
| 	void __iomem *ioaddr;	/* Mapped address */ | ||||
| 
 | ||||
|  | @ -115,6 +119,8 @@ struct sdhci_host { | |||
| #define SDHCI_NEEDS_RETUNING	(1<<5)	/* Host needs retuning */ | ||||
| #define SDHCI_AUTO_CMD12	(1<<6)	/* Auto CMD12 support */ | ||||
| #define SDHCI_AUTO_CMD23	(1<<7)	/* Auto CMD23 support */ | ||||
| #define SDHCI_PV_ENABLED	(1<<8)	/* Preset value enabled */ | ||||
| #define SDHCI_SDIO_IRQ_ENABLED	(1<<9)	/* SDIO irq enabled */ | ||||
| 
 | ||||
| 	unsigned int version;	/* SDHCI spec. version */ | ||||
| 
 | ||||
|  | @ -125,6 +131,8 @@ struct sdhci_host { | |||
| 	unsigned int clock;	/* Current clock (MHz) */ | ||||
| 	u8 pwr;			/* Current voltage */ | ||||
| 
 | ||||
| 	bool runtime_suspended;	/* Host is runtime suspended */ | ||||
| 
 | ||||
| 	struct mmc_request *mrq;	/* Current request */ | ||||
| 	struct mmc_command *cmd;	/* Current command */ | ||||
| 	struct mmc_data *data;	/* Current data request */ | ||||
|  |  | |||
|  | @ -72,11 +72,13 @@ | |||
| #define  SDIO_CCCR_REV_1_00	0	/* CCCR/FBR Version 1.00 */ | ||||
| #define  SDIO_CCCR_REV_1_10	1	/* CCCR/FBR Version 1.10 */ | ||||
| #define  SDIO_CCCR_REV_1_20	2	/* CCCR/FBR Version 1.20 */ | ||||
| #define  SDIO_CCCR_REV_3_00	3	/* CCCR/FBR Version 3.00 */ | ||||
| 
 | ||||
| #define  SDIO_SDIO_REV_1_00	0	/* SDIO Spec Version 1.00 */ | ||||
| #define  SDIO_SDIO_REV_1_10	1	/* SDIO Spec Version 1.10 */ | ||||
| #define  SDIO_SDIO_REV_1_20	2	/* SDIO Spec Version 1.20 */ | ||||
| #define  SDIO_SDIO_REV_2_00	3	/* SDIO Spec Version 2.00 */ | ||||
| #define  SDIO_SDIO_REV_3_00	4	/* SDIO Spec Version 3.00 */ | ||||
| 
 | ||||
| #define SDIO_CCCR_SD		0x01 | ||||
| 
 | ||||
|  |  | |||
|  | @ -41,7 +41,9 @@ struct sh_mmcif_plat_data { | |||
| 	void (*set_pwr)(struct platform_device *pdev, int state); | ||||
| 	void (*down_pwr)(struct platform_device *pdev); | ||||
| 	int (*get_cd)(struct platform_device *pdef); | ||||
| 	struct sh_mmcif_dma	*dma; | ||||
| 	struct sh_mmcif_dma	*dma;		/* Deprecated. Instead */ | ||||
| 	unsigned int		slave_id_tx;	/* use embedded slave_id_[tr]x */ | ||||
| 	unsigned int		slave_id_rx; | ||||
| 	u8			sup_pclk;	/* 1 :SH7757, 0: SH7724/SH7372 */ | ||||
| 	unsigned long		caps; | ||||
| 	u32			ocr; | ||||
|  |  | |||
|  | @ -6,6 +6,10 @@ | |||
| struct platform_device; | ||||
| struct tmio_mmc_data; | ||||
| 
 | ||||
| #define SH_MOBILE_SDHI_IRQ_CARD_DETECT	"card_detect" | ||||
| #define SH_MOBILE_SDHI_IRQ_SDCARD	"sdcard" | ||||
| #define SH_MOBILE_SDHI_IRQ_SDIO		"sdio" | ||||
| 
 | ||||
| struct sh_mobile_sdhi_info { | ||||
| 	int dma_slave_tx; | ||||
| 	int dma_slave_rx; | ||||
|  |  | |||
|  | @ -1070,6 +1070,17 @@ config FAIL_IO_TIMEOUT | |||
| 	  Only works with drivers that use the generic timeout handling, | ||||
| 	  for others it wont do anything. | ||||
| 
 | ||||
| config FAIL_MMC_REQUEST | ||||
| 	bool "Fault-injection capability for MMC IO" | ||||
| 	select DEBUG_FS | ||||
| 	depends on FAULT_INJECTION && MMC | ||||
| 	help | ||||
| 	  Provide fault-injection capability for MMC IO. | ||||
| 	  This will make the mmc core return data errors. This is | ||||
| 	  useful to test the error handling in the mmc block device | ||||
| 	  and to test how the mmc host driver handles retries from | ||||
| 	  the block device. | ||||
| 
 | ||||
| config FAULT_INJECTION_DEBUG_FS | ||||
| 	bool "Debugfs entries for fault-injection capabilities" | ||||
| 	depends on FAULT_INJECTION && SYSFS && DEBUG_FS | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ | |||
|  * setup_fault_attr() is a helper function for various __setup handlers, so it | ||||
|  * returns 0 on error, because that is what __setup handlers do. | ||||
|  */ | ||||
| int __init setup_fault_attr(struct fault_attr *attr, char *str) | ||||
| int setup_fault_attr(struct fault_attr *attr, char *str) | ||||
| { | ||||
| 	unsigned long probability; | ||||
| 	unsigned long interval; | ||||
|  | @ -36,6 +36,7 @@ int __init setup_fault_attr(struct fault_attr *attr, char *str) | |||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(setup_fault_attr); | ||||
| 
 | ||||
| static void fail_dump(struct fault_attr *attr) | ||||
| { | ||||
|  | @ -130,6 +131,7 @@ bool should_fail(struct fault_attr *attr, ssize_t size) | |||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(should_fail); | ||||
| 
 | ||||
| #ifdef CONFIG_FAULT_INJECTION_DEBUG_FS | ||||
| 
 | ||||
|  | @ -243,5 +245,6 @@ fail: | |||
| 
 | ||||
| 	return ERR_PTR(-ENOMEM); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(fault_create_debugfs_attr); | ||||
| 
 | ||||
| #endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Linus Torvalds
				Linus Torvalds