diff options
Diffstat (limited to 'drivers/mmc')
| -rw-r--r-- | drivers/mmc/card/mmc_test.c | 9 | ||||
| -rw-r--r-- | drivers/mmc/core/core.c | 6 | ||||
| -rw-r--r-- | drivers/mmc/core/host.c | 4 | ||||
| -rw-r--r-- | drivers/mmc/core/mmc.c | 7 | ||||
| -rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 14 | ||||
| -rw-r--r-- | drivers/mmc/host/pxamci.c | 66 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-of-at91.c | 1 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-pxav3.c | 6 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci.c | 2 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci.h | 5 | ||||
| -rw-r--r-- | drivers/mmc/host/sunxi-mmc.c | 53 | 
11 files changed, 92 insertions, 81 deletions
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index b78cf5d403a3..7fc9174d4619 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -2263,15 +2263,12 @@ static int mmc_test_profile_sglen_r_nonblock_perf(struct mmc_test_card *test)  /*   * eMMC hardware reset.   */ -static int mmc_test_hw_reset(struct mmc_test_card *test) +static int mmc_test_reset(struct mmc_test_card *test)  {  	struct mmc_card *card = test->card;  	struct mmc_host *host = card->host;  	int err; -	if (!mmc_card_mmc(card) || !mmc_can_reset(card)) -		return RESULT_UNSUP_CARD; -  	err = mmc_hw_reset(host);  	if (!err)  		return RESULT_OK; @@ -2605,8 +2602,8 @@ static const struct mmc_test_case mmc_test_cases[] = {  	},  	{ -		.name = "eMMC hardware reset", -		.run = mmc_test_hw_reset, +		.name = "Reset test", +		.run = mmc_test_reset,  	},  }; diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 0520064dc33b..a3eb20bdcd97 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -134,9 +134,11 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)  	int err = cmd->error;  	/* Flag re-tuning needed on CRC errors */ -	if (err == -EILSEQ || (mrq->sbc && mrq->sbc->error == -EILSEQ) || +	if ((cmd->opcode != MMC_SEND_TUNING_BLOCK && +	    cmd->opcode != MMC_SEND_TUNING_BLOCK_HS200) && +	    (err == -EILSEQ || (mrq->sbc && mrq->sbc->error == -EILSEQ) ||  	    (mrq->data && mrq->data->error == -EILSEQ) || -	    (mrq->stop && mrq->stop->error == -EILSEQ)) +	    (mrq->stop && mrq->stop->error == -EILSEQ)))  		mmc_retune_needed(host);  	if (err && cmd->retries && mmc_host_is_spi(host)) { diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index abd933b7029b..5466f25f0281 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -457,7 +457,7 @@ int mmc_of_parse(struct mmc_host *host)  					   0, &cd_gpio_invert);  		if (!ret)  			dev_info(host->parent, "Got CD GPIO\n"); -		else if (ret != -ENOENT) +		else if (ret != -ENOENT && ret != -ENOSYS)  			return ret;  		/* @@ -481,7 +481,7 @@ int mmc_of_parse(struct mmc_host *host)  	ret = mmc_gpiod_request_ro(host, "wp", 0, false, 0, &ro_gpio_invert);  	if (!ret)  		dev_info(host->parent, "Got WP GPIO\n"); -	else if (ret != -ENOENT) +	else if (ret != -ENOENT && ret != -ENOSYS)  		return ret;  	if (of_property_read_bool(np, "disable-wp")) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index e726903170a8..f6cd995dbe92 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1924,7 +1924,6 @@ EXPORT_SYMBOL(mmc_can_reset);  static int mmc_reset(struct mmc_host *host)  {  	struct mmc_card *card = host->card; -	u32 status;  	if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)  		return -EOPNOTSUPP; @@ -1937,12 +1936,6 @@ static int mmc_reset(struct mmc_host *host)  	host->ops->hw_reset(host); -	/* If the reset has happened, then a status command will fail */ -	if (!mmc_send_status(card, &status)) { -		mmc_host_clk_release(host); -		return -ENOSYS; -	} -  	/* Set initial state and call mmc_set_ios */  	mmc_set_initial_state(host);  	mmc_host_clk_release(host); diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 781e4db31767..7fb0753abe30 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -182,6 +182,7 @@ struct omap_hsmmc_host {  	struct	clk		*fclk;  	struct	clk		*dbclk;  	struct	regulator	*pbias; +	bool			pbias_enabled;  	void	__iomem		*base;  	int			vqmmc_enabled;  	resource_size_t		mapbase; @@ -328,20 +329,22 @@ static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on,  			return ret;  		} -		if (!regulator_is_enabled(host->pbias)) { +		if (host->pbias_enabled == 0) {  			ret = regulator_enable(host->pbias);  			if (ret) {  				dev_err(host->dev, "pbias reg enable fail\n");  				return ret;  			} +			host->pbias_enabled = 1;  		}  	} else { -		if (regulator_is_enabled(host->pbias)) { +		if (host->pbias_enabled == 1) {  			ret = regulator_disable(host->pbias);  			if (ret) {  				dev_err(host->dev, "pbias reg disable fail\n");  				return ret;  			} +			host->pbias_enabled = 0;  		}  	} @@ -475,7 +478,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)  	mmc->supply.vmmc = devm_regulator_get_optional(host->dev, "vmmc");  	if (IS_ERR(mmc->supply.vmmc)) {  		ret = PTR_ERR(mmc->supply.vmmc); -		if (ret != -ENODEV) +		if ((ret != -ENODEV) && host->dev->of_node)  			return ret;  		dev_dbg(host->dev, "unable to get vmmc regulator %ld\n",  			PTR_ERR(mmc->supply.vmmc)); @@ -490,7 +493,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)  	mmc->supply.vqmmc = devm_regulator_get_optional(host->dev, "vmmc_aux");  	if (IS_ERR(mmc->supply.vqmmc)) {  		ret = PTR_ERR(mmc->supply.vqmmc); -		if (ret != -ENODEV) +		if ((ret != -ENODEV) && host->dev->of_node)  			return ret;  		dev_dbg(host->dev, "unable to get vmmc_aux regulator %ld\n",  			PTR_ERR(mmc->supply.vqmmc)); @@ -500,7 +503,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)  	host->pbias = devm_regulator_get_optional(host->dev, "pbias");  	if (IS_ERR(host->pbias)) {  		ret = PTR_ERR(host->pbias); -		if (ret != -ENODEV) +		if ((ret != -ENODEV) && host->dev->of_node)  			return ret;  		dev_dbg(host->dev, "unable to get pbias regulator %ld\n",  			PTR_ERR(host->pbias)); @@ -2053,6 +2056,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)  	host->base	= base + pdata->reg_offset;  	host->power_mode = MMC_POWER_OFF;  	host->next_data.cookie = 1; +	host->pbias_enabled = 0;  	host->vqmmc_enabled = 0;  	ret = omap_hsmmc_gpio_init(mmc, host, pdata); diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 1420f29628c7..8cadd74e8407 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -28,6 +28,7 @@  #include <linux/clk.h>  #include <linux/err.h>  #include <linux/mmc/host.h> +#include <linux/mmc/slot-gpio.h>  #include <linux/io.h>  #include <linux/regulator/consumer.h>  #include <linux/gpio.h> @@ -454,12 +455,8 @@ static int pxamci_get_ro(struct mmc_host *mmc)  {  	struct pxamci_host *host = mmc_priv(mmc); -	if (host->pdata && gpio_is_valid(host->pdata->gpio_card_ro)) { -		if (host->pdata->gpio_card_ro_invert) -			return !gpio_get_value(host->pdata->gpio_card_ro); -		else -			return gpio_get_value(host->pdata->gpio_card_ro); -	} +	if (host->pdata && gpio_is_valid(host->pdata->gpio_card_ro)) +		return mmc_gpio_get_ro(mmc);  	if (host->pdata && host->pdata->get_ro)  		return !!host->pdata->get_ro(mmc_dev(mmc));  	/* @@ -551,6 +548,7 @@ static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable)  static const struct mmc_host_ops pxamci_ops = {  	.request		= pxamci_request, +	.get_cd			= mmc_gpio_get_cd,  	.get_ro			= pxamci_get_ro,  	.set_ios		= pxamci_set_ios,  	.enable_sdio_irq	= pxamci_enable_sdio_irq, @@ -790,37 +788,31 @@ static int pxamci_probe(struct platform_device *pdev)  		gpio_power = host->pdata->gpio_power;  	}  	if (gpio_is_valid(gpio_power)) { -		ret = gpio_request(gpio_power, "mmc card power"); +		ret = devm_gpio_request(&pdev->dev, gpio_power, +					"mmc card power");  		if (ret) { -			dev_err(&pdev->dev, "Failed requesting gpio_power %d\n", gpio_power); +			dev_err(&pdev->dev, "Failed requesting gpio_power %d\n", +				gpio_power);  			goto out;  		}  		gpio_direction_output(gpio_power,  				      host->pdata->gpio_power_invert);  	} -	if (gpio_is_valid(gpio_ro)) { -		ret = gpio_request(gpio_ro, "mmc card read only"); -		if (ret) { -			dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n", gpio_ro); -			goto err_gpio_ro; -		} -		gpio_direction_input(gpio_ro); +	if (gpio_is_valid(gpio_ro)) +		ret = mmc_gpio_request_ro(mmc, gpio_ro); +	if (ret) { +		dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n", gpio_ro); +		goto out; +	} else { +		mmc->caps |= host->pdata->gpio_card_ro_invert ? +			MMC_CAP2_RO_ACTIVE_HIGH : 0;  	} -	if (gpio_is_valid(gpio_cd)) { -		ret = gpio_request(gpio_cd, "mmc card detect"); -		if (ret) { -			dev_err(&pdev->dev, "Failed requesting gpio_cd %d\n", gpio_cd); -			goto err_gpio_cd; -		} -		gpio_direction_input(gpio_cd); -		ret = request_irq(gpio_to_irq(gpio_cd), pxamci_detect_irq, -				  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, -				  "mmc card detect", mmc); -		if (ret) { -			dev_err(&pdev->dev, "failed to request card detect IRQ\n"); -			goto err_request_irq; -		} +	if (gpio_is_valid(gpio_cd)) +		ret = mmc_gpio_request_cd(mmc, gpio_cd, 0); +	if (ret) { +		dev_err(&pdev->dev, "Failed requesting gpio_cd %d\n", gpio_cd); +		goto out;  	}  	if (host->pdata && host->pdata->init) @@ -835,13 +827,7 @@ static int pxamci_probe(struct platform_device *pdev)  	return 0; -err_request_irq: -	gpio_free(gpio_cd); -err_gpio_cd: -	gpio_free(gpio_ro); -err_gpio_ro: -	gpio_free(gpio_power); - out: +out:  	if (host) {  		if (host->dma_chan_rx)  			dma_release_channel(host->dma_chan_rx); @@ -873,14 +859,6 @@ static int pxamci_remove(struct platform_device *pdev)  			gpio_ro = host->pdata->gpio_card_ro;  			gpio_power = host->pdata->gpio_power;  		} -		if (gpio_is_valid(gpio_cd)) { -			free_irq(gpio_to_irq(gpio_cd), mmc); -			gpio_free(gpio_cd); -		} -		if (gpio_is_valid(gpio_ro)) -			gpio_free(gpio_ro); -		if (gpio_is_valid(gpio_power)) -			gpio_free(gpio_power);  		if (host->vcc)  			regulator_put(host->vcc); diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index d1556643a41d..a0f05de5409f 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -43,6 +43,7 @@ static const struct sdhci_ops sdhci_at91_sama5d2_ops = {  static const struct sdhci_pltfm_data soc_data_sama5d2 = {  	.ops = &sdhci_at91_sama5d2_ops, +	.quirks2 = SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST,  };  static const struct of_device_id sdhci_at91_dt_match[] = { diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index 946d37f94a31..f5edf9d3a18a 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -135,6 +135,7 @@ static int armada_38x_quirks(struct platform_device *pdev,  	struct sdhci_pxa *pxa = pltfm_host->priv;  	struct resource *res; +	host->quirks &= ~SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;  	host->quirks |= SDHCI_QUIRK_MISSING_CAPS;  	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,  					   "conf-sdio3"); @@ -290,6 +291,9 @@ static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)  		    uhs == MMC_TIMING_UHS_DDR50) {  			reg_val &= ~SDIO3_CONF_CLK_INV;  			reg_val |= SDIO3_CONF_SD_FB_CLK; +		} else if (uhs == MMC_TIMING_MMC_HS) { +			reg_val &= ~SDIO3_CONF_CLK_INV; +			reg_val &= ~SDIO3_CONF_SD_FB_CLK;  		} else {  			reg_val |= SDIO3_CONF_CLK_INV;  			reg_val &= ~SDIO3_CONF_SD_FB_CLK; @@ -398,7 +402,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)  	if (of_device_is_compatible(np, "marvell,armada-380-sdhci")) {  		ret = armada_38x_quirks(pdev, host);  		if (ret < 0) -			goto err_clk_get; +			goto err_mbus_win;  		ret = mv_conf_mbus_windows(pdev, mv_mbus_dram_info());  		if (ret < 0)  			goto err_mbus_win; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 64b7fdbd1a9c..fbc7efdddcb5 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1160,6 +1160,8 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)  	host->mmc->actual_clock = 0;  	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); +	if (host->quirks2 & SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST) +		mdelay(1);  	if (clock == 0)  		return; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 7c02ff46c8ac..9d4aa31b683a 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -412,6 +412,11 @@ struct sdhci_host {  #define SDHCI_QUIRK2_ACMD23_BROKEN			(1<<14)  /* Broken Clock divider zero in controller */  #define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN		(1<<15) +/* + * When internal clock is disabled, a delay is needed before modifying the + * SD clock frequency or enabling back the internal clock. + */ +#define SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST	(1<<16)  	int irq;		/* Device IRQ */  	void __iomem *ioaddr;	/* Mapped address */ diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index a7b7a6771598..b981b8552e43 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -210,6 +210,16 @@  #define SDXC_IDMAC_DES0_CES	BIT(30) /* card error summary */  #define SDXC_IDMAC_DES0_OWN	BIT(31) /* 1-idma owns it, 0-host owns it */ +#define SDXC_CLK_400K		0 +#define SDXC_CLK_25M		1 +#define SDXC_CLK_50M		2 +#define SDXC_CLK_50M_DDR	3 + +struct sunxi_mmc_clk_delay { +	u32 output; +	u32 sample; +}; +  struct sunxi_idma_des {  	u32	config;  	u32	buf_size; @@ -229,6 +239,7 @@ struct sunxi_mmc_host {  	struct clk	*clk_mmc;  	struct clk	*clk_sample;  	struct clk	*clk_output; +	const struct sunxi_mmc_clk_delay *clk_delays;  	/* irq */  	spinlock_t	lock; @@ -654,25 +665,19 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,  	/* determine delays */  	if (rate <= 400000) { -		oclk_dly = 180; -		sclk_dly = 42; +		oclk_dly = host->clk_delays[SDXC_CLK_400K].output; +		sclk_dly = host->clk_delays[SDXC_CLK_400K].sample;  	} else if (rate <= 25000000) { -		oclk_dly = 180; -		sclk_dly = 75; +		oclk_dly = host->clk_delays[SDXC_CLK_25M].output; +		sclk_dly = host->clk_delays[SDXC_CLK_25M].sample;  	} else if (rate <= 50000000) {  		if (ios->timing == MMC_TIMING_UHS_DDR50) { -			oclk_dly = 60; -			sclk_dly = 120; +			oclk_dly = host->clk_delays[SDXC_CLK_50M_DDR].output; +			sclk_dly = host->clk_delays[SDXC_CLK_50M_DDR].sample;  		} else { -			oclk_dly = 90; -			sclk_dly = 150; +			oclk_dly = host->clk_delays[SDXC_CLK_50M].output; +			sclk_dly = host->clk_delays[SDXC_CLK_50M].sample;  		} -	} else if (rate <= 100000000) { -		oclk_dly = 6; -		sclk_dly = 24; -	} else if (rate <= 200000000) { -		oclk_dly = 3; -		sclk_dly = 12;  	} else {  		return -EINVAL;  	} @@ -871,6 +876,7 @@ static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)  static const struct of_device_id sunxi_mmc_of_match[] = {  	{ .compatible = "allwinner,sun4i-a10-mmc", },  	{ .compatible = "allwinner,sun5i-a13-mmc", }, +	{ .compatible = "allwinner,sun9i-a80-mmc", },  	{ /* sentinel */ }  };  MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match); @@ -884,6 +890,20 @@ static struct mmc_host_ops sunxi_mmc_ops = {  	.hw_reset	 = sunxi_mmc_hw_reset,  }; +static const struct sunxi_mmc_clk_delay sunxi_mmc_clk_delays[] = { +	[SDXC_CLK_400K]		= { .output = 180, .sample = 180 }, +	[SDXC_CLK_25M]		= { .output = 180, .sample =  75 }, +	[SDXC_CLK_50M]		= { .output =  90, .sample = 120 }, +	[SDXC_CLK_50M_DDR]	= { .output =  60, .sample = 120 }, +}; + +static const struct sunxi_mmc_clk_delay sun9i_mmc_clk_delays[] = { +	[SDXC_CLK_400K]		= { .output = 180, .sample = 180 }, +	[SDXC_CLK_25M]		= { .output = 180, .sample =  75 }, +	[SDXC_CLK_50M]		= { .output = 150, .sample = 120 }, +	[SDXC_CLK_50M_DDR]	= { .output =  90, .sample = 120 }, +}; +  static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,  				      struct platform_device *pdev)  { @@ -895,6 +915,11 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,  	else  		host->idma_des_size_bits = 16; +	if (of_device_is_compatible(np, "allwinner,sun9i-a80-mmc")) +		host->clk_delays = sun9i_mmc_clk_delays; +	else +		host->clk_delays = sunxi_mmc_clk_delays; +  	ret = mmc_regulator_get_supply(host->mmc);  	if (ret) {  		if (ret != -EPROBE_DEFER)  | 
