diff options
Diffstat (limited to 'drivers/mmc')
48 files changed, 1562 insertions, 2378 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index c69afb5e264e..2c25271f8c41 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -2230,7 +2230,7 @@ static int mmc_blk_alloc_part(struct mmc_card *card,  	part_md->part_type = part_type;  	list_add(&part_md->part, &md->part); -	string_get_size((u64)get_capacity(part_md->disk) << 9, STRING_UNITS_2, +	string_get_size((u64)get_capacity(part_md->disk), 512, STRING_UNITS_2,  			cap_str, sizeof(cap_str));  	pr_info("%s: %s %s partition %u %s\n",  	       part_md->disk->disk_name, mmc_card_id(card), @@ -2418,9 +2418,8 @@ static const struct mmc_fixup blk_fixups[] =  	END_FIXUP  }; -static int mmc_blk_probe(struct device *dev) +static int mmc_blk_probe(struct mmc_card *card)  { -	struct mmc_card *card = mmc_dev_to_card(dev);  	struct mmc_blk_data *md, *part_md;  	char cap_str[10]; @@ -2436,7 +2435,7 @@ static int mmc_blk_probe(struct device *dev)  	if (IS_ERR(md))  		return PTR_ERR(md); -	string_get_size((u64)get_capacity(md->disk) << 9, STRING_UNITS_2, +	string_get_size((u64)get_capacity(md->disk), 512, STRING_UNITS_2,  			cap_str, sizeof(cap_str));  	pr_info("%s: %s %s %s %s\n",  		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), @@ -2445,7 +2444,7 @@ static int mmc_blk_probe(struct device *dev)  	if (mmc_blk_alloc_parts(card, md))  		goto out; -	dev_set_drvdata(dev, md); +	dev_set_drvdata(&card->dev, md);  	if (mmc_add_disk(md))  		goto out; @@ -2475,10 +2474,9 @@ static int mmc_blk_probe(struct device *dev)  	return 0;  } -static int mmc_blk_remove(struct device *dev) +static void mmc_blk_remove(struct mmc_card *card)  { -	struct mmc_card *card = mmc_dev_to_card(dev); -	struct mmc_blk_data *md = dev_get_drvdata(dev); +	struct mmc_blk_data *md = dev_get_drvdata(&card->dev);  	mmc_blk_remove_parts(card, md);  	pm_runtime_get_sync(&card->dev); @@ -2489,15 +2487,13 @@ static int mmc_blk_remove(struct device *dev)  		pm_runtime_disable(&card->dev);  	pm_runtime_put_noidle(&card->dev);  	mmc_blk_remove_req(md); -	dev_set_drvdata(dev, NULL); - -	return 0; +	dev_set_drvdata(&card->dev, NULL);  } -static int _mmc_blk_suspend(struct device *dev) +static int _mmc_blk_suspend(struct mmc_card *card)  {  	struct mmc_blk_data *part_md; -	struct mmc_blk_data *md = dev_get_drvdata(dev); +	struct mmc_blk_data *md = dev_get_drvdata(&card->dev);  	if (md) {  		mmc_queue_suspend(&md->queue); @@ -2508,15 +2504,17 @@ static int _mmc_blk_suspend(struct device *dev)  	return 0;  } -static void mmc_blk_shutdown(struct device *dev) +static void mmc_blk_shutdown(struct mmc_card *card)  { -	_mmc_blk_suspend(dev); +	_mmc_blk_suspend(card);  }  #ifdef CONFIG_PM_SLEEP  static int mmc_blk_suspend(struct device *dev)  { -	return _mmc_blk_suspend(dev); +	struct mmc_card *card = mmc_dev_to_card(dev); + +	return _mmc_blk_suspend(card);  }  static int mmc_blk_resume(struct device *dev) @@ -2541,9 +2539,11 @@ static int mmc_blk_resume(struct device *dev)  static SIMPLE_DEV_PM_OPS(mmc_blk_pm_ops, mmc_blk_suspend, mmc_blk_resume); -static struct device_driver mmc_driver = { -	.name		= "mmcblk", -	.pm		= &mmc_blk_pm_ops, +static struct mmc_driver mmc_driver = { +	.drv		= { +		.name	= "mmcblk", +		.pm	= &mmc_blk_pm_ops, +	},  	.probe		= mmc_blk_probe,  	.remove		= mmc_blk_remove,  	.shutdown	= mmc_blk_shutdown, diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 7dac4695163b..53b741398b93 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -14,7 +14,6 @@  #include <linux/mmc/host.h>  #include <linux/mmc/mmc.h>  #include <linux/slab.h> -#include <linux/device.h>  #include <linux/scatterlist.h>  #include <linux/swap.h>		/* For nr_free_buffer_pages() */ @@ -2996,9 +2995,8 @@ err:  	return ret;  } -static int mmc_test_probe(struct device *dev) +static int mmc_test_probe(struct mmc_card *card)  { -	struct mmc_card *card = mmc_dev_to_card(dev);  	int ret;  	if (!mmc_card_mmc(card) && !mmc_card_sd(card)) @@ -3013,22 +3011,20 @@ static int mmc_test_probe(struct device *dev)  	return 0;  } -static int mmc_test_remove(struct device *dev) +static void mmc_test_remove(struct mmc_card *card)  { -	struct mmc_card *card = mmc_dev_to_card(dev); -  	mmc_test_free_result(card);  	mmc_test_free_dbgfs_file(card); - -	return 0;  } -static void mmc_test_shutdown(struct device *dev) +static void mmc_test_shutdown(struct mmc_card *card)  {  } -static struct device_driver mmc_driver = { -	.name	= "mmc_test", +static struct mmc_driver mmc_driver = { +	.drv		= { +		.name	= "mmc_test", +	},  	.probe		= mmc_test_probe,  	.remove		= mmc_test_remove,  	.shutdown	= mmc_test_shutdown, diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index c5ef10065a4a..972ff844cf5a 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -26,6 +26,8 @@  #include "sdio_cis.h"  #include "bus.h" +#define to_mmc_driver(d)	container_of(d, struct mmc_driver, drv) +  static ssize_t type_show(struct device *dev,  	struct device_attribute *attr, char *buf)  { @@ -105,14 +107,33 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)  	return retval;  } +static int mmc_bus_probe(struct device *dev) +{ +	struct mmc_driver *drv = to_mmc_driver(dev->driver); +	struct mmc_card *card = mmc_dev_to_card(dev); + +	return drv->probe(card); +} + +static int mmc_bus_remove(struct device *dev) +{ +	struct mmc_driver *drv = to_mmc_driver(dev->driver); +	struct mmc_card *card = mmc_dev_to_card(dev); + +	drv->remove(card); + +	return 0; +} +  static void mmc_bus_shutdown(struct device *dev)  { +	struct mmc_driver *drv = to_mmc_driver(dev->driver);  	struct mmc_card *card = mmc_dev_to_card(dev);  	struct mmc_host *host = card->host;  	int ret; -	if (dev->driver && dev->driver->shutdown) -		dev->driver->shutdown(dev); +	if (dev->driver && drv->shutdown) +		drv->shutdown(card);  	if (host->bus_ops->shutdown) {  		ret = host->bus_ops->shutdown(host); @@ -181,6 +202,8 @@ static struct bus_type mmc_bus_type = {  	.dev_groups	= mmc_dev_groups,  	.match		= mmc_bus_match,  	.uevent		= mmc_bus_uevent, +	.probe		= mmc_bus_probe, +	.remove		= mmc_bus_remove,  	.shutdown	= mmc_bus_shutdown,  	.pm		= &mmc_bus_pm_ops,  }; @@ -199,22 +222,24 @@ void mmc_unregister_bus(void)   *	mmc_register_driver - register a media driver   *	@drv: MMC media driver   */ -int mmc_register_driver(struct device_driver *drv) +int mmc_register_driver(struct mmc_driver *drv)  { -	drv->bus = &mmc_bus_type; -	return driver_register(drv); +	drv->drv.bus = &mmc_bus_type; +	return driver_register(&drv->drv);  } +  EXPORT_SYMBOL(mmc_register_driver);  /**   *	mmc_unregister_driver - unregister a media driver   *	@drv: MMC media driver   */ -void mmc_unregister_driver(struct device_driver *drv) +void mmc_unregister_driver(struct mmc_driver *drv)  { -	drv->bus = &mmc_bus_type; -	driver_unregister(drv); +	drv->drv.bus = &mmc_bus_type; +	driver_unregister(&drv->drv);  } +  EXPORT_SYMBOL(mmc_unregister_driver);  static void mmc_release_card(struct device *dev) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 23f10f72e5f3..c296bc098fe2 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -897,6 +897,7 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)  	DECLARE_WAITQUEUE(wait, current);  	unsigned long flags;  	int stop; +	bool pm = false;  	might_sleep(); @@ -916,15 +917,18 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)  		host->claimed = 1;  		host->claimer = current;  		host->claim_cnt += 1; +		if (host->claim_cnt == 1) +			pm = true;  	} else  		wake_up(&host->wq);  	spin_unlock_irqrestore(&host->lock, flags);  	remove_wait_queue(&host->wq, &wait); -	if (host->ops->enable && !stop && host->claim_cnt == 1) -		host->ops->enable(host); + +	if (pm) +		pm_runtime_get_sync(mmc_dev(host)); +  	return stop;  } -  EXPORT_SYMBOL(__mmc_claim_host);  /** @@ -940,9 +944,6 @@ void mmc_release_host(struct mmc_host *host)  	WARN_ON(!host->claimed); -	if (host->ops->disable && host->claim_cnt == 1) -		host->ops->disable(host); -  	spin_lock_irqsave(&host->lock, flags);  	if (--host->claim_cnt) {  		/* Release for nested claim */ @@ -952,6 +953,8 @@ void mmc_release_host(struct mmc_host *host)  		host->claimer = NULL;  		spin_unlock_irqrestore(&host->lock, flags);  		wake_up(&host->wq); +		pm_runtime_mark_last_busy(mmc_dev(host)); +		pm_runtime_put_autosuspend(mmc_dev(host));  	}  }  EXPORT_SYMBOL(mmc_release_host); diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 1d41e8541f38..f36c76f8b232 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -11,6 +11,7 @@   */  #include <linux/err.h> +#include <linux/of.h>  #include <linux/slab.h>  #include <linux/stat.h>  #include <linux/pm_runtime.h> @@ -336,6 +337,8 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)  {  	int err = 0, idx;  	unsigned int part_size; +	struct device_node *np; +	bool broken_hpi = false;  	/* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */  	card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE]; @@ -349,6 +352,11 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)  		}  	} +	np = mmc_of_find_child_device(card->host, 0); +	if (np && of_device_is_compatible(np, "mmc-card")) +		broken_hpi = of_property_read_bool(np, "broken-hpi"); +	of_node_put(np); +  	/*  	 * The EXT_CSD format is meant to be forward compatible. As long  	 * as CSD_STRUCTURE does not change, all values for EXT_CSD_REV @@ -494,7 +502,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)  		}  		/* check whether the eMMC card supports HPI */ -		if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) { +		if (!broken_hpi && (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; @@ -1750,7 +1758,7 @@ static int mmc_runtime_suspend(struct mmc_host *host)  	err = _mmc_suspend(host, true);  	if (err) -		pr_err("%s: error %d doing aggessive suspend\n", +		pr_err("%s: error %d doing aggressive suspend\n",  			mmc_hostname(host), err);  	return err; @@ -1768,7 +1776,7 @@ static int mmc_runtime_resume(struct mmc_host *host)  	err = _mmc_resume(host);  	if (err) -		pr_err("%s: error %d doing aggessive resume\n", +		pr_err("%s: error %d doing aggressive resume\n",  			mmc_hostname(host), err);  	return 0; diff --git a/drivers/mmc/core/pwrseq.c b/drivers/mmc/core/pwrseq.c index 862356123d78..4c1d1757dbf9 100644 --- a/drivers/mmc/core/pwrseq.c +++ b/drivers/mmc/core/pwrseq.c @@ -19,7 +19,7 @@  struct mmc_pwrseq_match {  	const char *compatible; -	int (*alloc)(struct mmc_host *host, struct device *dev); +	struct mmc_pwrseq *(*alloc)(struct mmc_host *host, struct device *dev);  };  static struct mmc_pwrseq_match pwrseq_match[] = { @@ -52,6 +52,7 @@ int mmc_pwrseq_alloc(struct mmc_host *host)  	struct platform_device *pdev;  	struct device_node *np;  	struct mmc_pwrseq_match *match; +	struct mmc_pwrseq *pwrseq;  	int ret = 0;  	np = of_parse_phandle(host->parent->of_node, "mmc-pwrseq", 0); @@ -70,9 +71,14 @@ int mmc_pwrseq_alloc(struct mmc_host *host)  		goto err;  	} -	ret = match->alloc(host, &pdev->dev); -	if (!ret) -		dev_info(host->parent, "allocated mmc-pwrseq\n"); +	pwrseq = match->alloc(host, &pdev->dev); +	if (IS_ERR(pwrseq)) { +		ret = PTR_ERR(pwrseq); +		goto err; +	} + +	host->pwrseq = pwrseq; +	dev_info(host->parent, "allocated mmc-pwrseq\n");  err:  	of_node_put(np); @@ -109,4 +115,6 @@ void mmc_pwrseq_free(struct mmc_host *host)  	if (pwrseq && pwrseq->ops && pwrseq->ops->free)  		pwrseq->ops->free(host); + +	host->pwrseq = NULL;  } diff --git a/drivers/mmc/core/pwrseq.h b/drivers/mmc/core/pwrseq.h index aba3409e8d6e..096da48c6a7e 100644 --- a/drivers/mmc/core/pwrseq.h +++ b/drivers/mmc/core/pwrseq.h @@ -27,8 +27,10 @@ void mmc_pwrseq_post_power_on(struct mmc_host *host);  void mmc_pwrseq_power_off(struct mmc_host *host);  void mmc_pwrseq_free(struct mmc_host *host); -int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev); -int mmc_pwrseq_emmc_alloc(struct mmc_host *host, struct device *dev); +struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host, +					   struct device *dev); +struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host, +					 struct device *dev);  #else diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c index a2d545904fbf..9d6d2fb21796 100644 --- a/drivers/mmc/core/pwrseq_emmc.c +++ b/drivers/mmc/core/pwrseq_emmc.c @@ -49,7 +49,6 @@ static void mmc_pwrseq_emmc_free(struct mmc_host *host)  	unregister_restart_handler(&pwrseq->reset_nb);  	gpiod_put(pwrseq->reset_gpio);  	kfree(pwrseq); -	host->pwrseq = NULL;  }  static struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = { @@ -67,14 +66,15 @@ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,  	return NOTIFY_DONE;  } -int mmc_pwrseq_emmc_alloc(struct mmc_host *host, struct device *dev) +struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host, +					 struct device *dev)  {  	struct mmc_pwrseq_emmc *pwrseq;  	int ret = 0;  	pwrseq = kzalloc(sizeof(struct mmc_pwrseq_emmc), GFP_KERNEL);  	if (!pwrseq) -		return -ENOMEM; +		return ERR_PTR(-ENOMEM);  	pwrseq->reset_gpio = gpiod_get_index(dev, "reset", 0, GPIOD_OUT_LOW);  	if (IS_ERR(pwrseq->reset_gpio)) { @@ -92,10 +92,9 @@ int mmc_pwrseq_emmc_alloc(struct mmc_host *host, struct device *dev)  	register_restart_handler(&pwrseq->reset_nb);  	pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops; -	host->pwrseq = &pwrseq->pwrseq; -	return 0; +	return &pwrseq->pwrseq;  free:  	kfree(pwrseq); -	return ret; +	return ERR_PTR(ret);  } diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c index e9f1d8d84613..0b14b83a53d6 100644 --- a/drivers/mmc/core/pwrseq_simple.c +++ b/drivers/mmc/core/pwrseq_simple.c @@ -85,7 +85,6 @@ static void mmc_pwrseq_simple_free(struct mmc_host *host)  		clk_put(pwrseq->ext_clk);  	kfree(pwrseq); -	host->pwrseq = NULL;  }  static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = { @@ -95,7 +94,8 @@ static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {  	.free = mmc_pwrseq_simple_free,  }; -int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev) +struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host, +					   struct device *dev)  {  	struct mmc_pwrseq_simple *pwrseq;  	int i, nr_gpios, ret = 0; @@ -107,7 +107,7 @@ int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev)  	pwrseq = kzalloc(sizeof(struct mmc_pwrseq_simple) + nr_gpios *  			 sizeof(struct gpio_desc *), GFP_KERNEL);  	if (!pwrseq) -		return -ENOMEM; +		return ERR_PTR(-ENOMEM);  	pwrseq->ext_clk = clk_get(dev, "ext_clock");  	if (IS_ERR(pwrseq->ext_clk) && @@ -124,7 +124,7 @@ int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev)  		    PTR_ERR(pwrseq->reset_gpios[i]) != -ENOSYS) {  			ret = PTR_ERR(pwrseq->reset_gpios[i]); -			while (--i) +			while (i--)  				gpiod_put(pwrseq->reset_gpios[i]);  			goto clk_put; @@ -133,13 +133,12 @@ int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev)  	pwrseq->nr_gpios = nr_gpios;  	pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops; -	host->pwrseq = &pwrseq->pwrseq; -	return 0; +	return &pwrseq->pwrseq;  clk_put:  	if (!IS_ERR(pwrseq->ext_clk))  		clk_put(pwrseq->ext_clk);  free:  	kfree(pwrseq); -	return ret; +	return ERR_PTR(ret);  } diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index ad4d43eae99d..31a9ef256d06 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1157,7 +1157,7 @@ static int mmc_sd_runtime_suspend(struct mmc_host *host)  	err = _mmc_sd_suspend(host);  	if (err) -		pr_err("%s: error %d doing aggessive suspend\n", +		pr_err("%s: error %d doing aggressive suspend\n",  			mmc_hostname(host), err);  	return err; @@ -1175,7 +1175,7 @@ static int mmc_sd_runtime_resume(struct mmc_host *host)  	err = _mmc_sd_resume(host);  	if (err) -		pr_err("%s: error %d doing aggessive resume\n", +		pr_err("%s: error %d doing aggressive resume\n",  			mmc_hostname(host), err);  	return 0; diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index ce6cc47206b0..5bc6c7dbbd60 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -293,19 +293,22 @@ static int sdio_enable_4bit_bus(struct mmc_card *card)  	int err;  	if (card->type == MMC_TYPE_SDIO) -		return sdio_enable_wide(card); - -	if ((card->host->caps & MMC_CAP_4_BIT_DATA) && -		(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) { +		err = sdio_enable_wide(card); +	else if ((card->host->caps & MMC_CAP_4_BIT_DATA) && +		 (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {  		err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);  		if (err)  			return err; +		err = sdio_enable_wide(card); +		if (err <= 0) +			mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1);  	} else  		return 0; -	err = sdio_enable_wide(card); -	if (err <= 0) -		mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1); +	if (err > 0) { +		mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); +		err = 0; +	}  	return err;  } @@ -547,13 +550,8 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card)  	/*  	 * Switch to wider bus (if supported).  	 */ -	if (card->host->caps & MMC_CAP_4_BIT_DATA) { +	if (card->host->caps & MMC_CAP_4_BIT_DATA)  		err = sdio_enable_4bit_bus(card); -		if (err > 0) { -			mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); -			err = 0; -		} -	}  	/* Set the driver strength for the card */  	sdio_select_driver_type(card); @@ -803,9 +801,7 @@ try_again:  		 * Switch to wider bus (if supported).  		 */  		err = sdio_enable_4bit_bus(card); -		if (err > 0) -			mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); -		else if (err) +		if (err)  			goto remove;  	}  finish: @@ -983,10 +979,6 @@ static int mmc_sdio_resume(struct mmc_host *host)  	} else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {  		/* We may have switched to 1-bit mode during suspend */  		err = sdio_enable_4bit_bus(host->card); -		if (err > 0) { -			mmc_set_bus_width(host, MMC_BUS_WIDTH_4); -			err = 0; -		}  	}  	if (!err && host->sdio_irqs) { diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 61ac63a3776a..b1f837e749fe 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -132,7 +132,7 @@ config MMC_SDHCI_OF_ARASAN  config MMC_SDHCI_OF_ESDHC  	tristate "SDHCI OF support for the Freescale eSDHC controller"  	depends on MMC_SDHCI_PLTFM -	depends on PPC_OF +	depends on PPC  	select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER  	help  	  This selects the Freescale eSDHC controller support. @@ -144,7 +144,7 @@ config MMC_SDHCI_OF_ESDHC  config MMC_SDHCI_OF_HLWD  	tristate "SDHCI OF support for the Nintendo Wii SDHCI controllers"  	depends on MMC_SDHCI_PLTFM -	depends on PPC_OF +	depends on PPC  	select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER  	help  	  This selects the Secure Digital Host Controller Interface (SDHCI) @@ -230,7 +230,7 @@ config MMC_SDHCI_PXAV3  	tristate "Marvell MMP2 SD Host Controller support (PXAV3)"  	depends on CLKDEV_LOOKUP  	depends on MMC_SDHCI_PLTFM -	depends on ARCH_MMP || COMPILE_TEST +	depends on ARCH_BERLIN || ARCH_MMP || ARCH_MVEBU || COMPILE_TEST  	default CPU_MMP2  	help  	  This selects the Marvell(R) PXAV3 SD Host Controller. @@ -255,6 +255,7 @@ config MMC_SDHCI_PXAV2  config MMC_SDHCI_SPEAR  	tristate "SDHCI support on ST SPEAr platform"  	depends on MMC_SDHCI && PLAT_SPEAR +	depends on OF  	help  	  This selects the Secure Digital Host Controller Interface (SDHCI)  	  often referrered to as the HSMMC block in some of the ST SPEAR range @@ -307,6 +308,20 @@ config MMC_SDHCI_F_SDH30  	  If unsure, say N. +config MMC_SDHCI_IPROC +	tristate "SDHCI platform support for the iProc SD/MMC Controller" +	depends on ARCH_BCM_IPROC || COMPILE_TEST +	depends on MMC_SDHCI_PLTFM +	default ARCH_BCM_IPROC +	select MMC_SDHCI_IO_ACCESSORS +	help +	  This selects the iProc SD/MMC controller. + +	  If you have an IPROC platform with SD or MMC devices, +	  say Y or M here. + +	  If unsure, say N. +  config MMC_MOXART  	tristate "MOXART SD/MMC Host Controller support"  	depends on ARCH_MOXART && MMC @@ -393,14 +408,6 @@ config MMC_SDHCI_MSM  	  If unsure, say N. -config MMC_MSM -	tristate "Qualcomm SDCC Controller Support" -	depends on MMC && (ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50) -	help -	  This provides support for the SD/MMC cell found in the -	  MSM and QSD SOCs from Qualcomm. The controller also has -	  support for SDIO devices. -  config MMC_MXC  	tristate "Freescale i.MX21/27/31 or MPC512x Multimedia Card support"  	depends on ARCH_MXC || PPC_MPC512x diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 6a7cfe0de332..e3ab5b968651 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -24,7 +24,6 @@ obj-$(CONFIG_MMC_OMAP)		+= omap.o  obj-$(CONFIG_MMC_OMAP_HS)	+= omap_hsmmc.o  obj-$(CONFIG_MMC_ATMELMCI)	+= atmel-mci.o  obj-$(CONFIG_MMC_TIFM_SD)	+= tifm_sd.o -obj-$(CONFIG_MMC_MSM)		+= msm_sdcc.o  obj-$(CONFIG_MMC_MVSDIO)	+= mvsdio.o  obj-$(CONFIG_MMC_DAVINCI)       += davinci_mmc.o  obj-$(CONFIG_MMC_GOLDFISH)	+= android-goldfish.o @@ -71,6 +70,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_ESDHC)	+= sdhci-of-esdhc.o  obj-$(CONFIG_MMC_SDHCI_OF_HLWD)		+= sdhci-of-hlwd.o  obj-$(CONFIG_MMC_SDHCI_BCM_KONA)	+= sdhci-bcm-kona.o  obj-$(CONFIG_MMC_SDHCI_BCM2835)		+= sdhci-bcm2835.o +obj-$(CONFIG_MMC_SDHCI_IPROC)		+= sdhci-iproc.o  obj-$(CONFIG_MMC_SDHCI_MSM)		+= sdhci-msm.o  obj-$(CONFIG_MMC_SDHCI_ST)		+= sdhci-st.o diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h index c97001e15227..0aa44e679df4 100644 --- a/drivers/mmc/host/atmel-mci-regs.h +++ b/drivers/mmc/host/atmel-mci-regs.h @@ -135,10 +135,17 @@  #define ATMCI_REGS_SIZE		0x100  /* Register access macros */ -#define atmci_readl(port,reg)				\ +#ifdef CONFIG_AVR32 +#define atmci_readl(port, reg)			\  	__raw_readl((port)->regs + reg) -#define atmci_writel(port,reg,value)			\ +#define atmci_writel(port, reg, value)			\  	__raw_writel((value), (port)->regs + reg) +#else +#define atmci_readl(port, reg)			\ +	readl_relaxed((port)->regs + reg) +#define atmci_writel(port, reg, value)			\ +	writel_relaxed((value), (port)->regs + reg) +#endif  /* On AVR chips the Peripheral DMA Controller is not connected to MCI. */  #ifdef CONFIG_AVR32 diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index fe32948c6114..e761eb1b1441 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -40,7 +40,12 @@ struct dw_mci_exynos_priv_data {  	u8				ciu_div;  	u32				sdr_timing;  	u32				ddr_timing; +	u32				hs400_timing; +	u32				tuned_sample;  	u32				cur_speed; +	u32				dqs_delay; +	u32				saved_dqs_en; +	u32				saved_strobe_ctrl;  };  static struct dw_mci_exynos_compatible { @@ -71,6 +76,21 @@ static struct dw_mci_exynos_compatible {  	},  }; +static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host) +{ +	struct dw_mci_exynos_priv_data *priv = host->priv; + +	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412) +		return EXYNOS4412_FIXED_CIU_CLK_DIV; +	else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210) +		return EXYNOS4210_FIXED_CIU_CLK_DIV; +	else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || +			priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) +		return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1; +	else +		return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1; +} +  static int dw_mci_exynos_priv_init(struct dw_mci *host)  {  	struct dw_mci_exynos_priv_data *priv = host->priv; @@ -85,6 +105,16 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)  			   SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);  	} +	if (priv->ctrl_type >= DW_MCI_TYPE_EXYNOS5420) { +		priv->saved_strobe_ctrl = mci_readl(host, HS400_DLINE_CTRL); +		priv->saved_dqs_en = mci_readl(host, HS400_DQS_EN); +		priv->saved_dqs_en |= AXI_NON_BLOCKING_WR; +		mci_writel(host, HS400_DQS_EN, priv->saved_dqs_en); +		if (!priv->dqs_delay) +			priv->dqs_delay = +				DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl); +	} +  	return 0;  } @@ -97,6 +127,26 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)  	return 0;  } +static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing) +{ +	struct dw_mci_exynos_priv_data *priv = host->priv; +	u32 clksel; + +	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || +		priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) +		clksel = mci_readl(host, CLKSEL64); +	else +		clksel = mci_readl(host, CLKSEL); + +	clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing; + +	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || +		priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) +		mci_writel(host, CLKSEL64, clksel); +	else +		mci_writel(host, CLKSEL, clksel); +} +  #ifdef CONFIG_PM_SLEEP  static int dw_mci_exynos_suspend(struct device *dev)  { @@ -172,30 +222,38 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)  	}  } -static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) +static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)  {  	struct dw_mci_exynos_priv_data *priv = host->priv; -	unsigned int wanted = ios->clock; -	unsigned long actual; -	u8 div = priv->ciu_div + 1; +	u32 dqs, strobe; -	if (ios->timing == MMC_TIMING_MMC_DDR52) { -		if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || -			priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) -			mci_writel(host, CLKSEL64, priv->ddr_timing); -		else -			mci_writel(host, CLKSEL, priv->ddr_timing); -		/* Should be double rate for DDR mode */ -		if (ios->bus_width == MMC_BUS_WIDTH_8) -			wanted <<= 1; +	/* +	 * Not supported to configure register +	 * related to HS400 +	 */ +	if (priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420) +		return; + +	dqs = priv->saved_dqs_en; +	strobe = priv->saved_strobe_ctrl; + +	if (timing == MMC_TIMING_MMC_HS400) { +		dqs |= DATA_STROBE_EN; +		strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay);  	} else { -		if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || -			priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) -			mci_writel(host, CLKSEL64, priv->sdr_timing); -		else -			mci_writel(host, CLKSEL, priv->sdr_timing); +		dqs &= ~DATA_STROBE_EN;  	} +	mci_writel(host, HS400_DQS_EN, dqs); +	mci_writel(host, HS400_DLINE_CTRL, strobe); +} + +static void dw_mci_exynos_adjust_clock(struct dw_mci *host, unsigned int wanted) +{ +	struct dw_mci_exynos_priv_data *priv = host->priv; +	unsigned long actual; +	u8 div; +	int ret;  	/*  	 * Don't care if wanted clock is zero or  	 * ciu clock is unavailable @@ -207,17 +265,52 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)  	if (wanted < EXYNOS_CCLKIN_MIN)  		wanted = EXYNOS_CCLKIN_MIN; -	if (wanted != priv->cur_speed) { -		int ret = clk_set_rate(host->ciu_clk, wanted * div); -		if (ret) -			dev_warn(host->dev, -				"failed to set clk-rate %u error: %d\n", -				 wanted * div, ret); -		actual = clk_get_rate(host->ciu_clk); -		host->bus_hz = actual / div; -		priv->cur_speed = wanted; -		host->current_speed = 0; +	if (wanted == priv->cur_speed) +		return; + +	div = dw_mci_exynos_get_ciu_div(host); +	ret = clk_set_rate(host->ciu_clk, wanted * div); +	if (ret) +		dev_warn(host->dev, +			"failed to set clk-rate %u error: %d\n", +			wanted * div, ret); +	actual = clk_get_rate(host->ciu_clk); +	host->bus_hz = actual / div; +	priv->cur_speed = wanted; +	host->current_speed = 0; +} + +static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) +{ +	struct dw_mci_exynos_priv_data *priv = host->priv; +	unsigned int wanted = ios->clock; +	u32 timing = ios->timing, clksel; + +	switch (timing) { +	case MMC_TIMING_MMC_HS400: +		/* Update tuned sample timing */ +		clksel = SDMMC_CLKSEL_UP_SAMPLE( +				priv->hs400_timing, priv->tuned_sample); +		wanted <<= 1; +		break; +	case MMC_TIMING_MMC_DDR52: +		clksel = priv->ddr_timing; +		/* Should be double rate for DDR mode */ +		if (ios->bus_width == MMC_BUS_WIDTH_8) +			wanted <<= 1; +		break; +	default: +		clksel = priv->sdr_timing;  	} + +	/* Set clock timing for the requested speed mode*/ +	dw_mci_exynos_set_clksel_timing(host, clksel); + +	/* Configure setting for HS400 */ +	dw_mci_exynos_config_hs400(host, timing); + +	/* Configure clock rate */ +	dw_mci_exynos_adjust_clock(host, wanted);  }  static int dw_mci_exynos_parse_dt(struct dw_mci *host) @@ -260,6 +353,16 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)  		return ret;  	priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div); + +	ret = of_property_read_u32_array(np, +			"samsung,dw-mshc-hs400-timing", timing, 2); +	if (!ret && of_property_read_u32(np, +				"samsung,read-strobe-delay", &priv->dqs_delay)) +		dev_dbg(host->dev, +			"read-strobe-delay is not found, assuming usage of default value\n"); + +	priv->hs400_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], +						HS400_FIXED_CIU_CLK_DIV);  	host->priv = priv;  	return 0;  } @@ -285,7 +388,7 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)  		clksel = mci_readl(host, CLKSEL64);  	else  		clksel = mci_readl(host, CLKSEL); -	clksel = (clksel & ~0x7) | SDMMC_CLKSEL_CCLK_SAMPLE(sample); +	clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);  	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||  		priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)  		mci_writel(host, CLKSEL64, clksel); @@ -304,13 +407,16 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)  		clksel = mci_readl(host, CLKSEL64);  	else  		clksel = mci_readl(host, CLKSEL); +  	sample = (clksel + 1) & 0x7; -	clksel = (clksel & ~0x7) | sample; +	clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample); +  	if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||  		priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)  		mci_writel(host, CLKSEL64, clksel);  	else  		mci_writel(host, CLKSEL, clksel); +  	return sample;  } @@ -343,6 +449,7 @@ out:  static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)  {  	struct dw_mci *host = slot->host; +	struct dw_mci_exynos_priv_data *priv = host->priv;  	struct mmc_host *mmc = slot->mmc;  	u8 start_smpl, smpl, candiates = 0;  	s8 found = -1; @@ -360,14 +467,27 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)  	} while (start_smpl != smpl);  	found = dw_mci_exynos_get_best_clksmpl(candiates); -	if (found >= 0) +	if (found >= 0) {  		dw_mci_exynos_set_clksmpl(host, found); -	else +		priv->tuned_sample = found; +	} else {  		ret = -EIO; +	}  	return ret;  } +static int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host, +					struct mmc_ios *ios) +{ +	struct dw_mci_exynos_priv_data *priv = host->priv; + +	dw_mci_exynos_set_clksel_timing(host, priv->hs400_timing); +	dw_mci_exynos_adjust_clock(host, (ios->clock) << 1); + +	return 0; +} +  /* Common capabilities of Exynos4/Exynos5 SoC */  static unsigned long exynos_dwmmc_caps[4] = {  	MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23, @@ -384,6 +504,7 @@ static const struct dw_mci_drv_data exynos_drv_data = {  	.set_ios		= dw_mci_exynos_set_ios,  	.parse_dt		= dw_mci_exynos_parse_dt,  	.execute_tuning		= dw_mci_exynos_execute_tuning, +	.prepare_hs400_tuning	= dw_mci_exynos_prepare_hs400_tuning,  };  static const struct of_device_id dw_mci_exynos_match[] = { diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h index 7872ce586b55..595c934e6166 100644 --- a/drivers/mmc/host/dw_mmc-exynos.h +++ b/drivers/mmc/host/dw_mmc-exynos.h @@ -12,20 +12,36 @@  #ifndef _DW_MMC_EXYNOS_H_  #define _DW_MMC_EXYNOS_H_ -/* Extended Register's Offset */  #define SDMMC_CLKSEL			0x09C  #define SDMMC_CLKSEL64			0x0A8 +/* Extended Register's Offset */ +#define SDMMC_HS400_DQS_EN		0x180 +#define SDMMC_HS400_ASYNC_FIFO_CTRL	0x184 +#define SDMMC_HS400_DLINE_CTRL		0x188 +  /* CLKSEL register defines */  #define SDMMC_CLKSEL_CCLK_SAMPLE(x)	(((x) & 7) << 0)  #define SDMMC_CLKSEL_CCLK_DRIVE(x)	(((x) & 7) << 16)  #define SDMMC_CLKSEL_CCLK_DIVIDER(x)	(((x) & 7) << 24)  #define SDMMC_CLKSEL_GET_DRV_WD3(x)	(((x) >> 16) & 0x7) +#define SDMMC_CLKSEL_GET_DIV(x)		(((x) >> 24) & 0x7) +#define SDMMC_CLKSEL_UP_SAMPLE(x, y)	(((x) & ~SDMMC_CLKSEL_CCLK_SAMPLE(7)) |\ +					 SDMMC_CLKSEL_CCLK_SAMPLE(y))  #define SDMMC_CLKSEL_TIMING(x, y, z)	(SDMMC_CLKSEL_CCLK_SAMPLE(x) |	\  					 SDMMC_CLKSEL_CCLK_DRIVE(y) |	\  					 SDMMC_CLKSEL_CCLK_DIVIDER(z)) +#define SDMMC_CLKSEL_TIMING_MASK	SDMMC_CLKSEL_TIMING(0x7, 0x7, 0x7)  #define SDMMC_CLKSEL_WAKEUP_INT		BIT(11) +/* RCLK_EN register defines */ +#define DATA_STROBE_EN			BIT(0) +#define AXI_NON_BLOCKING_WR	BIT(7) + +/* DLINE_CTRL register defines */ +#define DQS_CTRL_RD_DELAY(x, y)		(((x) & ~0x3FF) | ((y) & 0x3FF)) +#define DQS_CTRL_GET_RD_DELAY(x)	((x) & 0x3FF) +  /* Protector Register */  #define SDMMC_EMMCP_BASE	0x1000  #define SDMMC_MPSECURITY	(SDMMC_EMMCP_BASE + 0x0010) @@ -49,6 +65,7 @@  /* Fixed clock divider */  #define EXYNOS4210_FIXED_CIU_CLK_DIV	2  #define EXYNOS4412_FIXED_CIU_CLK_DIV	4 +#define HS400_FIXED_CIU_CLK_DIV		1  /* Minimal required clock frequency for cclkin, unit: HZ */  #define EXYNOS_CCLKIN_MIN	50000000 diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index e2a726a503ee..dbf166f94f1b 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -76,12 +76,20 @@ static int dw_mci_rockchip_init(struct dw_mci *host)  	return 0;  } +/* Common capabilities of RK3288 SoC */ +static unsigned long dw_mci_rk3288_dwmmc_caps[4] = { +	MMC_CAP_RUNTIME_RESUME, /* emmc */ +	MMC_CAP_RUNTIME_RESUME, /* sdmmc */ +	MMC_CAP_RUNTIME_RESUME, /* sdio0 */ +	MMC_CAP_RUNTIME_RESUME, /* sdio1 */ +};  static const struct dw_mci_drv_data rk2928_drv_data = {  	.prepare_command        = dw_mci_rockchip_prepare_command,  	.init			= dw_mci_rockchip_init,  };  static const struct dw_mci_drv_data rk3288_drv_data = { +	.caps			= dw_mci_rk3288_dwmmc_caps,  	.prepare_command        = dw_mci_rockchip_prepare_command,  	.set_ios		= dw_mci_rk3288_set_ios,  	.setup_clock    = dw_mci_rk3288_setup_clock, diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 4d2e3c2e1830..38b29265cc7c 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -69,7 +69,8 @@ struct idmac_desc_64addr {  	u32		des2;	/*Buffer sizes */  #define IDMAC_64ADDR_SET_BUFFER1_SIZE(d, s) \ -	((d)->des2 = ((d)->des2 & 0x03ffe000) | ((s) & 0x1fff)) +	((d)->des2 = ((d)->des2 & cpu_to_le32(0x03ffe000)) | \ +	 ((cpu_to_le32(s)) & cpu_to_le32(0x1fff)))  	u32		des3;	/* Reserved */ @@ -81,7 +82,7 @@ struct idmac_desc_64addr {  };  struct idmac_desc { -	u32		des0;	/* Control Descriptor */ +	__le32		des0;	/* Control Descriptor */  #define IDMAC_DES0_DIC	BIT(1)  #define IDMAC_DES0_LD	BIT(2)  #define IDMAC_DES0_FD	BIT(3) @@ -90,18 +91,19 @@ struct idmac_desc {  #define IDMAC_DES0_CES	BIT(30)  #define IDMAC_DES0_OWN	BIT(31) -	u32		des1;	/* Buffer sizes */ +	__le32		des1;	/* Buffer sizes */  #define IDMAC_SET_BUFFER1_SIZE(d, s) \  	((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff)) -	u32		des2;	/* buffer 1 physical address */ +	__le32		des2;	/* buffer 1 physical address */ -	u32		des3;	/* buffer 2 physical address */ +	__le32		des3;	/* buffer 2 physical address */  };  #endif /* CONFIG_MMC_DW_IDMAC */  static bool dw_mci_reset(struct dw_mci *host);  static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset); +static int dw_mci_card_busy(struct mmc_host *mmc);  #if defined(CONFIG_DEBUG_FS)  static int dw_mci_req_show(struct seq_file *s, void *v) @@ -335,6 +337,31 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)  	return cmdr;  } +static void dw_mci_wait_while_busy(struct dw_mci *host, u32 cmd_flags) +{ +	unsigned long timeout = jiffies + msecs_to_jiffies(500); + +	/* +	 * Databook says that before issuing a new data transfer command +	 * we need to check to see if the card is busy.  Data transfer commands +	 * all have SDMMC_CMD_PRV_DAT_WAIT set, so we'll key off that. +	 * +	 * ...also allow sending for SDMMC_CMD_VOLT_SWITCH where busy is +	 * expected. +	 */ +	if ((cmd_flags & SDMMC_CMD_PRV_DAT_WAIT) && +	    !(cmd_flags & SDMMC_CMD_VOLT_SWITCH)) { +		while (mci_readl(host, STATUS) & SDMMC_STATUS_BUSY) { +			if (time_after(jiffies, timeout)) { +				/* Command will fail; we'll pass error then */ +				dev_err(host->dev, "Busy; trying anyway\n"); +				break; +			} +			udelay(10); +		} +	} +} +  static void dw_mci_start_command(struct dw_mci *host,  				 struct mmc_command *cmd, u32 cmd_flags)  { @@ -345,6 +372,7 @@ static void dw_mci_start_command(struct dw_mci *host,  	mci_writel(host, CMDARG, cmd->arg);  	wmb(); +	dw_mci_wait_while_busy(host, cmd_flags);  	mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);  } @@ -477,23 +505,23 @@ static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,  			 * Set the OWN bit and disable interrupts for this  			 * descriptor  			 */ -			desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | -						IDMAC_DES0_CH; +			desc->des0 = cpu_to_le32(IDMAC_DES0_OWN | +					IDMAC_DES0_DIC | IDMAC_DES0_CH);  			/* Buffer length */  			IDMAC_SET_BUFFER1_SIZE(desc, length);  			/* Physical address to DMA to/from */ -			desc->des2 = mem_addr; +			desc->des2 = cpu_to_le32(mem_addr);  		}  		/* Set first descriptor */  		desc = host->sg_cpu; -		desc->des0 |= IDMAC_DES0_FD; +		desc->des0 |= cpu_to_le32(IDMAC_DES0_FD);  		/* Set last descriptor */  		desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc); -		desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC); -		desc->des0 |= IDMAC_DES0_LD; +		desc->des0 &= cpu_to_le32(~(IDMAC_DES0_CH | IDMAC_DES0_DIC)); +		desc->des0 |= cpu_to_le32(IDMAC_DES0_LD);  	}  	wmb(); @@ -562,12 +590,12 @@ static int dw_mci_idmac_init(struct dw_mci *host)  		/* Forward link the descriptor list */  		for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++) -			p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * -								(i + 1)); +			p->des3 = cpu_to_le32(host->sg_dma + +					(sizeof(struct idmac_desc) * (i + 1)));  		/* Set the last descriptor as the end-of-ring descriptor */ -		p->des3 = host->sg_dma; -		p->des0 = IDMAC_DES0_ER; +		p->des3 = cpu_to_le32(host->sg_dma); +		p->des0 = cpu_to_le32(IDMAC_DES0_ER);  	}  	dw_mci_idmac_reset(host); @@ -737,6 +765,7 @@ static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data)  		return;  	if (host->timing != MMC_TIMING_MMC_HS200 && +	    host->timing != MMC_TIMING_MMC_HS400 &&  	    host->timing != MMC_TIMING_UHS_SDR104)  		goto disable; @@ -876,6 +905,7 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)  	mci_writel(host, CMDARG, arg);  	wmb(); +	dw_mci_wait_while_busy(host, cmd);  	mci_writel(host, CMD, SDMMC_CMD_START | cmd);  	while (time_before(jiffies, timeout)) { @@ -992,6 +1022,26 @@ static void __dw_mci_start_request(struct dw_mci *host,  	dw_mci_start_command(host, cmd, cmdflags); +	if (cmd->opcode == SD_SWITCH_VOLTAGE) { +		unsigned long irqflags; + +		/* +		 * Databook says to fail after 2ms w/ no response, but evidence +		 * shows that sometimes the cmd11 interrupt takes over 130ms. +		 * We'll set to 500ms, plus an extra jiffy just in case jiffies +		 * is just about to roll over. +		 * +		 * We do this whole thing under spinlock and only if the +		 * command hasn't already completed (indicating the the irq +		 * already ran so we don't want the timeout). +		 */ +		spin_lock_irqsave(&host->irq_lock, irqflags); +		if (!test_bit(EVENT_CMD_COMPLETE, &host->pending_events)) +			mod_timer(&host->cmd11_timer, +				jiffies + msecs_to_jiffies(500) + 1); +		spin_unlock_irqrestore(&host->irq_lock, irqflags); +	} +  	if (mrq->stop)  		host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop);  	else @@ -1084,7 +1134,8 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  	regs = mci_readl(slot->host, UHS_REG);  	/* DDR mode set */ -	if (ios->timing == MMC_TIMING_MMC_DDR52) +	if (ios->timing == MMC_TIMING_MMC_DDR52 || +	    ios->timing == MMC_TIMING_MMC_HS400)  		regs |= ((0x1 << slot->id) << 16);  	else  		regs &= ~((0x1 << slot->id) << 16); @@ -1101,12 +1152,6 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  	if (drv_data && drv_data->set_ios)  		drv_data->set_ios(slot->host, ios); -	/* Slot specific timing and width adjustment */ -	dw_mci_setup_bus(slot, false); - -	if (slot->host->state == STATE_WAITING_CMD11_DONE && ios->clock != 0) -		slot->host->state = STATE_IDLE; -  	switch (ios->power_mode) {  	case MMC_POWER_UP:  		if (!IS_ERR(mmc->supply.vmmc)) { @@ -1125,23 +1170,39 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  		mci_writel(slot->host, PWREN, regs);  		break;  	case MMC_POWER_ON: -		if (!IS_ERR(mmc->supply.vqmmc) && !slot->host->vqmmc_enabled) { -			ret = regulator_enable(mmc->supply.vqmmc); -			if (ret < 0) -				dev_err(slot->host->dev, -					"failed to enable vqmmc regulator\n"); -			else +		if (!slot->host->vqmmc_enabled) { +			if (!IS_ERR(mmc->supply.vqmmc)) { +				ret = regulator_enable(mmc->supply.vqmmc); +				if (ret < 0) +					dev_err(slot->host->dev, +						"failed to enable vqmmc\n"); +				else +					slot->host->vqmmc_enabled = true; + +			} else { +				/* Keep track so we don't reset again */  				slot->host->vqmmc_enabled = true; +			} + +			/* Reset our state machine after powering on */ +			dw_mci_ctrl_reset(slot->host, +					  SDMMC_CTRL_ALL_RESET_FLAGS);  		} + +		/* Adjust clock / bus width after power is up */ +		dw_mci_setup_bus(slot, false); +  		break;  	case MMC_POWER_OFF: +		/* Turn clock off before power goes down */ +		dw_mci_setup_bus(slot, false); +  		if (!IS_ERR(mmc->supply.vmmc))  			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); -		if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled) { +		if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled)  			regulator_disable(mmc->supply.vqmmc); -			slot->host->vqmmc_enabled = false; -		} +		slot->host->vqmmc_enabled = false;  		regs = mci_readl(slot->host, PWREN);  		regs &= ~(1 << slot->id); @@ -1150,6 +1211,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  	default:  		break;  	} + +	if (slot->host->state == STATE_WAITING_CMD11_DONE && ios->clock != 0) +		slot->host->state = STATE_IDLE;  }  static int dw_mci_card_busy(struct mmc_host *mmc) @@ -1323,6 +1387,18 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)  	return err;  } +static int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios) +{ +	struct dw_mci_slot *slot = mmc_priv(mmc); +	struct dw_mci *host = slot->host; +	const struct dw_mci_drv_data *drv_data = host->drv_data; + +	if (drv_data && drv_data->prepare_hs400_tuning) +		return drv_data->prepare_hs400_tuning(host, ios); + +	return 0; +} +  static const struct mmc_host_ops dw_mci_ops = {  	.request		= dw_mci_request,  	.pre_req		= dw_mci_pre_req, @@ -1335,6 +1411,7 @@ static const struct mmc_host_ops dw_mci_ops = {  	.card_busy		= dw_mci_card_busy,  	.start_signal_voltage_switch = dw_mci_switch_voltage,  	.init_card		= dw_mci_init_card, +	.prepare_hs400_tuning	= dw_mci_prepare_hs400_tuning,  };  static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq) @@ -1520,7 +1597,10 @@ static void dw_mci_tasklet_func(unsigned long priv)  			if (test_and_clear_bit(EVENT_DATA_ERROR,  					       &host->pending_events)) {  				dw_mci_stop_dma(host); -				send_stop_abort(host, data); +				if (data->stop || +				    !(host->data_status & (SDMMC_INT_DRTO | +							   SDMMC_INT_EBE))) +					send_stop_abort(host, data);  				state = STATE_DATA_ERROR;  				break;  			} @@ -1547,7 +1627,10 @@ static void dw_mci_tasklet_func(unsigned long priv)  			if (test_and_clear_bit(EVENT_DATA_ERROR,  					       &host->pending_events)) {  				dw_mci_stop_dma(host); -				send_stop_abort(host, data); +				if (data->stop || +				    !(host->data_status & (SDMMC_INT_DRTO | +							   SDMMC_INT_EBE))) +					send_stop_abort(host, data);  				state = STATE_DATA_ERROR;  				break;  			} @@ -1685,8 +1768,7 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)  		buf += len;  		cnt -= len;  		if (host->part_buf_count == 2) { -			mci_writew(host, DATA(host->data_offset), -					host->part_buf16); +			mci_fifo_writew(host->fifo_reg, host->part_buf16);  			host->part_buf_count = 0;  		}  	} @@ -1703,15 +1785,14 @@ 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(host->data_offset), -						aligned_buf[i]); +				mci_fifo_writew(host->fifo_reg, aligned_buf[i]);  		}  	} else  #endif  	{  		u16 *pdata = buf;  		for (; cnt >= 2; cnt -= 2) -			mci_writew(host, DATA(host->data_offset), *pdata++); +			mci_fifo_writew(host->fifo_reg, *pdata++);  		buf = pdata;  	}  	/* put anything remaining in the part_buf */ @@ -1720,8 +1801,7 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)  		 /* Push data if we have reached the expected data length */  		if ((data->bytes_xfered + init_cnt) ==  		    (data->blksz * data->blocks)) -			mci_writew(host, DATA(host->data_offset), -				   host->part_buf16); +			mci_fifo_writew(host->fifo_reg, host->part_buf16);  	}  } @@ -1736,8 +1816,7 @@ 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(host->data_offset)); +				aligned_buf[i] = mci_fifo_readw(host->fifo_reg);  			/* memcpy from aligned buffer into output buffer */  			memcpy(buf, aligned_buf, len);  			buf += len; @@ -1748,11 +1827,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(host->data_offset)); +			*pdata++ = mci_fifo_readw(host->fifo_reg);  		buf = pdata;  	}  	if (cnt) { -		host->part_buf16 = mci_readw(host, DATA(host->data_offset)); +		host->part_buf16 = mci_fifo_readw(host->fifo_reg);  		dw_mci_pull_final_bytes(host, buf, cnt);  	}  } @@ -1768,8 +1847,7 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)  		buf += len;  		cnt -= len;  		if (host->part_buf_count == 4) { -			mci_writel(host, DATA(host->data_offset), -					host->part_buf32); +			mci_fifo_writel(host->fifo_reg,	host->part_buf32);  			host->part_buf_count = 0;  		}  	} @@ -1786,15 +1864,14 @@ 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(host->data_offset), -						aligned_buf[i]); +				mci_fifo_writel(host->fifo_reg,	aligned_buf[i]);  		}  	} else  #endif  	{  		u32 *pdata = buf;  		for (; cnt >= 4; cnt -= 4) -			mci_writel(host, DATA(host->data_offset), *pdata++); +			mci_fifo_writel(host->fifo_reg, *pdata++);  		buf = pdata;  	}  	/* put anything remaining in the part_buf */ @@ -1803,8 +1880,7 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)  		 /* Push data if we have reached the expected data length */  		if ((data->bytes_xfered + init_cnt) ==  		    (data->blksz * data->blocks)) -			mci_writel(host, DATA(host->data_offset), -				   host->part_buf32); +			mci_fifo_writel(host->fifo_reg, host->part_buf32);  	}  } @@ -1819,8 +1895,7 @@ 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(host->data_offset)); +				aligned_buf[i] = mci_fifo_readl(host->fifo_reg);  			/* memcpy from aligned buffer into output buffer */  			memcpy(buf, aligned_buf, len);  			buf += len; @@ -1831,11 +1906,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(host->data_offset)); +			*pdata++ = mci_fifo_readl(host->fifo_reg);  		buf = pdata;  	}  	if (cnt) { -		host->part_buf32 = mci_readl(host, DATA(host->data_offset)); +		host->part_buf32 = mci_fifo_readl(host->fifo_reg);  		dw_mci_pull_final_bytes(host, buf, cnt);  	}  } @@ -1852,8 +1927,7 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)  		cnt -= len;  		if (host->part_buf_count == 8) { -			mci_writeq(host, DATA(host->data_offset), -					host->part_buf); +			mci_fifo_writeq(host->fifo_reg,	host->part_buf);  			host->part_buf_count = 0;  		}  	} @@ -1870,15 +1944,14 @@ 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(host->data_offset), -						aligned_buf[i]); +				mci_fifo_writeq(host->fifo_reg,	aligned_buf[i]);  		}  	} else  #endif  	{  		u64 *pdata = buf;  		for (; cnt >= 8; cnt -= 8) -			mci_writeq(host, DATA(host->data_offset), *pdata++); +			mci_fifo_writeq(host->fifo_reg, *pdata++);  		buf = pdata;  	}  	/* put anything remaining in the part_buf */ @@ -1887,8 +1960,7 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)  		/* Push data if we have reached the expected data length */  		if ((data->bytes_xfered + init_cnt) ==  		    (data->blksz * data->blocks)) -			mci_writeq(host, DATA(host->data_offset), -				   host->part_buf); +			mci_fifo_writeq(host->fifo_reg, host->part_buf);  	}  } @@ -1903,8 +1975,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(host->data_offset)); +				aligned_buf[i] = mci_fifo_readq(host->fifo_reg); +  			/* memcpy from aligned buffer into output buffer */  			memcpy(buf, aligned_buf, len);  			buf += len; @@ -1915,11 +1987,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(host->data_offset)); +			*pdata++ = mci_fifo_readq(host->fifo_reg);  		buf = pdata;  	}  	if (cnt) { -		host->part_buf = mci_readq(host, DATA(host->data_offset)); +		host->part_buf = mci_fifo_readq(host->fifo_reg);  		dw_mci_pull_final_bytes(host, buf, cnt);  	}  } @@ -2097,9 +2169,20 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)  		/* Check volt switch first, since it can look like an error */  		if ((host->state == STATE_SENDING_CMD11) &&  		    (pending & SDMMC_INT_VOLT_SWITCH)) { +			unsigned long irqflags; +  			mci_writel(host, RINTSTS, SDMMC_INT_VOLT_SWITCH);  			pending &= ~SDMMC_INT_VOLT_SWITCH; + +			/* +			 * Hold the lock; we know cmd11_timer can't be kicked +			 * off after the lock is released, so safe to delete. +			 */ +			spin_lock_irqsave(&host->irq_lock, irqflags);  			dw_mci_cmd_interrupt(host, pending); +			spin_unlock_irqrestore(&host->irq_lock, irqflags); + +			del_timer(&host->cmd11_timer);  		}  		if (pending & DW_MCI_CMD_ERROR_FLAGS) { @@ -2156,6 +2239,10 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)  		/* Handle SDIO Interrupts */  		for (i = 0; i < host->num_slots; i++) {  			struct dw_mci_slot *slot = host->slot[i]; + +			if (!slot) +				continue; +  			if (pending & SDMMC_INT_SDIO(slot->sdio_id)) {  				mci_writel(host, RINTSTS,  					   SDMMC_INT_SDIO(slot->sdio_id)); @@ -2506,6 +2593,20 @@ ciu_out:  	return ret;  } +static void dw_mci_cmd11_timer(unsigned long arg) +{ +	struct dw_mci *host = (struct dw_mci *)arg; + +	if (host->state != STATE_SENDING_CMD11) { +		dev_warn(host->dev, "Unexpected CMD11 timeout\n"); +		return; +	} + +	host->cmd_status = SDMMC_INT_RTO; +	set_bit(EVENT_CMD_COMPLETE, &host->pending_events); +	tasklet_schedule(&host->tasklet); +} +  #ifdef CONFIG_OF  static struct dw_mci_of_quirks {  	char *quirk; @@ -2574,6 +2675,34 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)  }  #endif /* CONFIG_OF */ +static void dw_mci_enable_cd(struct dw_mci *host) +{ +	struct dw_mci_board *brd = host->pdata; +	unsigned long irqflags; +	u32 temp; +	int i; + +	/* No need for CD if broken card detection */ +	if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) +		return; + +	/* No need for CD if all slots have a non-error GPIO */ +	for (i = 0; i < host->num_slots; i++) { +		struct dw_mci_slot *slot = host->slot[i]; + +		if (IS_ERR_VALUE(mmc_gpio_get_cd(slot->mmc))) +			break; +	} +	if (i == host->num_slots) +		return; + +	spin_lock_irqsave(&host->irq_lock, irqflags); +	temp = mci_readl(host, INTMASK); +	temp  |= SDMMC_INT_CD; +	mci_writel(host, INTMASK, temp); +	spin_unlock_irqrestore(&host->irq_lock, irqflags); +} +  int dw_mci_probe(struct dw_mci *host)  {  	const struct dw_mci_drv_data *drv_data = host->drv_data; @@ -2652,6 +2781,9 @@ int dw_mci_probe(struct dw_mci *host)  		}  	} +	setup_timer(&host->cmd11_timer, +		    dw_mci_cmd11_timer, (unsigned long)host); +  	host->quirks = host->pdata->quirks;  	spin_lock_init(&host->lock); @@ -2731,9 +2863,9 @@ int dw_mci_probe(struct dw_mci *host)  	dev_info(host->dev, "Version ID is %04x\n", host->verid);  	if (host->verid < DW_MMC_240A) -		host->data_offset = DATA_OFFSET; +		host->fifo_reg = host->regs + DATA_OFFSET;  	else -		host->data_offset = DATA_240A_OFFSET; +		host->fifo_reg = host->regs + DATA_240A_OFFSET;  	tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);  	ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt, @@ -2747,13 +2879,13 @@ int dw_mci_probe(struct dw_mci *host)  		host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1;  	/* -	 * Enable interrupts for command done, data over, data empty, card det, +	 * Enable interrupts for command done, data over, data empty,  	 * receive ready and error such as transmit, receive timeout, crc error  	 */  	mci_writel(host, RINTSTS, 0xFFFFFFFF);  	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |  		   SDMMC_INT_TXDR | SDMMC_INT_RXDR | -		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); +		   DW_MCI_ERROR_FLAGS);  	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */  	dev_info(host->dev, "DW MMC controller at irq %d, " @@ -2778,6 +2910,9 @@ int dw_mci_probe(struct dw_mci *host)  		goto err_dmaunmap;  	} +	/* Now that slots are all setup, we can enable card detect */ +	dw_mci_enable_cd(host); +  	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)  		dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n"); @@ -2864,7 +2999,7 @@ int dw_mci_resume(struct dw_mci *host)  	mci_writel(host, RINTSTS, 0xFFFFFFFF);  	mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |  		   SDMMC_INT_TXDR | SDMMC_INT_RXDR | -		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD); +		   DW_MCI_ERROR_FLAGS);  	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);  	for (i = 0; i < host->num_slots; i++) { @@ -2876,6 +3011,10 @@ int dw_mci_resume(struct dw_mci *host)  			dw_mci_setup_bus(slot, true);  		}  	} + +	/* Now that slots are all setup, we can enable card detect */ +	dw_mci_enable_cd(host); +  	return 0;  }  EXPORT_SYMBOL(dw_mci_resume); diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 18c4afe683b8..f45ab91de339 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -169,24 +169,34 @@  #define SDMMC_CTRL_ALL_RESET_FLAGS \  	(SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) +/* FIFO register access macros. These should not change the data endian-ness + * as they are written to memory to be dealt with by the upper layers */ +#define mci_fifo_readw(__reg)	__raw_readw(__reg) +#define mci_fifo_readl(__reg)	__raw_readl(__reg) +#define mci_fifo_readq(__reg)	__raw_readq(__reg) + +#define mci_fifo_writew(__value, __reg)	__raw_writew(__reg, __value) +#define mci_fifo_writel(__value, __reg)	__raw_writel(__reg, __value) +#define mci_fifo_writeq(__value, __reg)	__raw_writeq(__reg, __value) +  /* Register access macros */  #define mci_readl(dev, reg)			\ -	__raw_readl((dev)->regs + SDMMC_##reg) +	readl_relaxed((dev)->regs + SDMMC_##reg)  #define mci_writel(dev, reg, value)			\ -	__raw_writel((value), (dev)->regs + SDMMC_##reg) +	writel_relaxed((value), (dev)->regs + SDMMC_##reg)  /* 16-bit FIFO access macros */  #define mci_readw(dev, reg)			\ -	__raw_readw((dev)->regs + SDMMC_##reg) +	readw_relaxed((dev)->regs + SDMMC_##reg)  #define mci_writew(dev, reg, value)			\ -	__raw_writew((value), (dev)->regs + SDMMC_##reg) +	writew_relaxed((value), (dev)->regs + SDMMC_##reg)  /* 64-bit FIFO access macros */  #ifdef readq  #define mci_readq(dev, reg)			\ -	__raw_readq((dev)->regs + SDMMC_##reg) +	readq_relaxed((dev)->regs + SDMMC_##reg)  #define mci_writeq(dev, reg, value)			\ -	__raw_writeq((value), (dev)->regs + SDMMC_##reg) +	writeq_relaxed((value), (dev)->regs + SDMMC_##reg)  #else  /*   * Dummy readq implementation for architectures that don't define it. @@ -200,6 +210,10 @@  	(*(volatile u64 __force *)((dev)->regs + SDMMC_##reg))  #define mci_writeq(dev, reg, value)			\  	(*(volatile u64 __force *)((dev)->regs + SDMMC_##reg) = (value)) + +#define __raw_writeq(__value, __reg) \ +	(*(volatile u64 __force *)(__reg) = (__value)) +#define __raw_readq(__reg) (*(volatile u64 __force *)(__reg))  #endif  extern int dw_mci_probe(struct dw_mci *host); @@ -271,5 +285,7 @@ struct dw_mci_drv_data {  	void		(*set_ios)(struct dw_mci *host, struct mmc_ios *ios);  	int		(*parse_dt)(struct dw_mci *host);  	int		(*execute_tuning)(struct dw_mci_slot *slot); +	int		(*prepare_hs400_tuning)(struct dw_mci *host, +						struct mmc_ios *ios);  };  #endif /* _DW_MMC_H_ */ diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index e4a07546f8b6..ae19d83bb9de 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -1507,7 +1507,7 @@ static int mmc_spi_remove(struct spi_device *spi)  	return 0;  } -static struct of_device_id mmc_spi_of_match_table[] = { +static const struct of_device_id mmc_spi_of_match_table[] = {  	{ .compatible = "mmc-spi-slot", },  	{},  }; diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 7fe16194ebc8..fb266745f824 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1613,7 +1613,10 @@ static int mmci_probe(struct amba_device *dev,  	dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max);  	/* Get regulators and the supported OCR mask */ -	mmc_regulator_get_supply(mmc); +	ret = mmc_regulator_get_supply(mmc); +	if (ret == -EPROBE_DEFER) +		goto clk_disable; +  	if (!mmc->ocr_avail)  		mmc->ocr_avail = plat->ocr_mask;  	else if (plat->ocr_mask) diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c deleted file mode 100644 index 90c60fd4ff6e..000000000000 --- a/drivers/mmc/host/msm_sdcc.c +++ /dev/null @@ -1,1474 +0,0 @@ -/* - *  linux/drivers/mmc/host/msm_sdcc.c - Qualcomm MSM 7X00A SDCC Driver - * - *  Copyright (C) 2007 Google Inc, - *  Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved. - *  Copyright (C) 2009, Code Aurora Forum. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Based on mmci.c - * - * Author: San Mehat ([email protected]) - * - */ - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/ioport.h> -#include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/highmem.h> -#include <linux/log2.h> -#include <linux/mmc/host.h> -#include <linux/mmc/card.h> -#include <linux/mmc/sdio.h> -#include <linux/clk.h> -#include <linux/scatterlist.h> -#include <linux/platform_device.h> -#include <linux/dma-mapping.h> -#include <linux/debugfs.h> -#include <linux/io.h> -#include <linux/memory.h> -#include <linux/gfp.h> -#include <linux/gpio.h> - -#include <asm/cacheflush.h> -#include <asm/div64.h> -#include <asm/sizes.h> - -#include <linux/platform_data/mmc-msm_sdcc.h> -#include <mach/dma.h> -#include <mach/clk.h> - -#include "msm_sdcc.h" - -#define DRIVER_NAME "msm-sdcc" - -#define BUSCLK_PWRSAVE 1 -#define BUSCLK_TIMEOUT (HZ) -static unsigned int msmsdcc_fmin = 144000; -static unsigned int msmsdcc_fmax = 50000000; -static unsigned int msmsdcc_4bit = 1; -static unsigned int msmsdcc_pwrsave = 1; -static unsigned int msmsdcc_piopoll = 1; -static unsigned int msmsdcc_sdioirq; - -#define PIO_SPINMAX 30 -#define CMD_SPINMAX 20 - - -static inline void -msmsdcc_disable_clocks(struct msmsdcc_host *host, int deferr) -{ -	WARN_ON(!host->clks_on); - -	BUG_ON(host->curr.mrq); - -	if (deferr) { -		mod_timer(&host->busclk_timer, jiffies + BUSCLK_TIMEOUT); -	} else { -		del_timer_sync(&host->busclk_timer); -		/* Need to check clks_on again in case the busclk -		 * timer fired -		 */ -		if (host->clks_on) { -			clk_disable(host->clk); -			clk_disable(host->pclk); -			host->clks_on = 0; -		} -	} -} - -static inline int -msmsdcc_enable_clocks(struct msmsdcc_host *host) -{ -	int rc; - -	del_timer_sync(&host->busclk_timer); - -	if (!host->clks_on) { -		rc = clk_enable(host->pclk); -		if (rc) -			return rc; -		rc = clk_enable(host->clk); -		if (rc) { -			clk_disable(host->pclk); -			return rc; -		} -		udelay(1 + ((3 * USEC_PER_SEC) / -		       (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); -		host->clks_on = 1; -	} -	return 0; -} - -static inline unsigned int -msmsdcc_readl(struct msmsdcc_host *host, unsigned int reg) -{ -	return readl(host->base + reg); -} - -static inline void -msmsdcc_writel(struct msmsdcc_host *host, u32 data, unsigned int reg) -{ -	writel(data, host->base + reg); -	/* 3 clk delay required! */ -	udelay(1 + ((3 * USEC_PER_SEC) / -	       (host->clk_rate ? host->clk_rate : msmsdcc_fmin))); -} - -static void -msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, -		      u32 c); - -static void msmsdcc_reset_and_restore(struct msmsdcc_host *host) -{ -	u32	mci_clk = 0; -	u32	mci_mask0 = 0; -	int	ret = 0; - -	/* Save the controller state */ -	mci_clk = readl(host->base + MMCICLOCK); -	mci_mask0 = readl(host->base + MMCIMASK0); - -	/* Reset the controller */ -	ret = clk_reset(host->clk, CLK_RESET_ASSERT); -	if (ret) -		pr_err("%s: Clock assert failed at %u Hz with err %d\n", -				mmc_hostname(host->mmc), host->clk_rate, ret); - -	ret = clk_reset(host->clk, CLK_RESET_DEASSERT); -	if (ret) -		pr_err("%s: Clock deassert failed at %u Hz with err %d\n", -				mmc_hostname(host->mmc), host->clk_rate, ret); - -	pr_info("%s: Controller has been re-initialiazed\n", -			mmc_hostname(host->mmc)); - -	/* Restore the contoller state */ -	writel(host->pwr, host->base + MMCIPOWER); -	writel(mci_clk, host->base + MMCICLOCK); -	writel(mci_mask0, host->base + MMCIMASK0); -	ret = clk_set_rate(host->clk, host->clk_rate); -	if (ret) -		pr_err("%s: Failed to set clk rate %u Hz (%d)\n", -				mmc_hostname(host->mmc), host->clk_rate, ret); -} - -static void -msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) -{ -	BUG_ON(host->curr.data); - -	host->curr.mrq = NULL; -	host->curr.cmd = NULL; - -	if (mrq->data) -		mrq->data->bytes_xfered = host->curr.data_xfered; -	if (mrq->cmd->error == -ETIMEDOUT) -		mdelay(5); - -#if BUSCLK_PWRSAVE -	msmsdcc_disable_clocks(host, 1); -#endif -	/* -	 * Need to drop the host lock here; mmc_request_done may call -	 * back into the driver... -	 */ -	spin_unlock(&host->lock); -	mmc_request_done(host->mmc, mrq); -	spin_lock(&host->lock); -} - -static void -msmsdcc_stop_data(struct msmsdcc_host *host) -{ -	host->curr.data = NULL; -	host->curr.got_dataend = 0; -} - -uint32_t msmsdcc_fifo_addr(struct msmsdcc_host *host) -{ -	return host->memres->start + MMCIFIFO; -} - -static inline void -msmsdcc_start_command_exec(struct msmsdcc_host *host, u32 arg, u32 c) { -       msmsdcc_writel(host, arg, MMCIARGUMENT); -       msmsdcc_writel(host, c, MMCICOMMAND); -} - -static void -msmsdcc_dma_exec_func(struct msm_dmov_cmd *cmd) -{ -	struct msmsdcc_host *host = (struct msmsdcc_host *)cmd->data; - -	msmsdcc_writel(host, host->cmd_timeout, MMCIDATATIMER); -	msmsdcc_writel(host, (unsigned int)host->curr.xfer_size, -		       MMCIDATALENGTH); -	msmsdcc_writel(host, (msmsdcc_readl(host, MMCIMASK0) & -			(~MCI_IRQ_PIO)) | host->cmd_pio_irqmask, MMCIMASK0); -	msmsdcc_writel(host, host->cmd_datactrl, MMCIDATACTRL); - -	if (host->cmd_cmd) { -		msmsdcc_start_command_exec(host, -					   (u32) host->cmd_cmd->arg, -					   (u32) host->cmd_c); -	} -	host->dma.active = 1; -} - -static void -msmsdcc_dma_complete_tlet(unsigned long data) -{ -	struct msmsdcc_host *host = (struct msmsdcc_host *)data; -	unsigned long		flags; -	struct mmc_request	*mrq; -	struct msm_dmov_errdata err; - -	spin_lock_irqsave(&host->lock, flags); -	host->dma.active = 0; - -	err = host->dma.err; -	mrq = host->curr.mrq; -	BUG_ON(!mrq); -	WARN_ON(!mrq->data); - -	if (!(host->dma.result & DMOV_RSLT_VALID)) { -		pr_err("msmsdcc: Invalid DataMover result\n"); -		goto out; -	} - -	if (host->dma.result & DMOV_RSLT_DONE) { -		host->curr.data_xfered = host->curr.xfer_size; -	} else { -		/* Error or flush  */ -		if (host->dma.result & DMOV_RSLT_ERROR) -			pr_err("%s: DMA error (0x%.8x)\n", -			       mmc_hostname(host->mmc), host->dma.result); -		if (host->dma.result & DMOV_RSLT_FLUSH) -			pr_err("%s: DMA channel flushed (0x%.8x)\n", -			       mmc_hostname(host->mmc), host->dma.result); - -		pr_err("Flush data: %.8x %.8x %.8x %.8x %.8x %.8x\n", -		       err.flush[0], err.flush[1], err.flush[2], -		       err.flush[3], err.flush[4], err.flush[5]); - -		msmsdcc_reset_and_restore(host); -		if (!mrq->data->error) -			mrq->data->error = -EIO; -	} -	dma_unmap_sg(mmc_dev(host->mmc), host->dma.sg, host->dma.num_ents, -		     host->dma.dir); - -	host->dma.sg = NULL; -	host->dma.busy = 0; - -	if (host->curr.got_dataend || mrq->data->error) { - -		/* -		 * If we've already gotten our DATAEND / DATABLKEND -		 * for this request, then complete it through here. -		 */ -		msmsdcc_stop_data(host); - -		if (!mrq->data->error) -			host->curr.data_xfered = host->curr.xfer_size; -		if (!mrq->data->stop || mrq->cmd->error) { -			host->curr.mrq = NULL; -			host->curr.cmd = NULL; -			mrq->data->bytes_xfered = host->curr.data_xfered; - -			spin_unlock_irqrestore(&host->lock, flags); -#if BUSCLK_PWRSAVE -			msmsdcc_disable_clocks(host, 1); -#endif -			mmc_request_done(host->mmc, mrq); -			return; -		} else -			msmsdcc_start_command(host, mrq->data->stop, 0); -	} - -out: -	spin_unlock_irqrestore(&host->lock, flags); -	return; -} - -static void -msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, -			  unsigned int result, -			  struct msm_dmov_errdata *err) -{ -	struct msmsdcc_dma_data	*dma_data = -		container_of(cmd, struct msmsdcc_dma_data, hdr); -	struct msmsdcc_host *host = dma_data->host; - -	dma_data->result = result; -	if (err) -		memcpy(&dma_data->err, err, sizeof(struct msm_dmov_errdata)); - -	tasklet_schedule(&host->dma_tlet); -} - -static int validate_dma(struct msmsdcc_host *host, struct mmc_data *data) -{ -	if (host->dma.channel == -1) -		return -ENOENT; - -	if ((data->blksz * data->blocks) < MCI_FIFOSIZE) -		return -EINVAL; -	if ((data->blksz * data->blocks) % MCI_FIFOSIZE) -		return -EINVAL; -	return 0; -} - -static int msmsdcc_config_dma(struct msmsdcc_host *host, struct mmc_data *data) -{ -	struct msmsdcc_nc_dmadata *nc; -	dmov_box *box; -	uint32_t rows; -	uint32_t crci; -	unsigned int n; -	int i, rc; -	struct scatterlist *sg = data->sg; - -	rc = validate_dma(host, data); -	if (rc) -		return rc; - -	host->dma.sg = data->sg; -	host->dma.num_ents = data->sg_len; - -       BUG_ON(host->dma.num_ents > NR_SG); /* Prevent memory corruption */ - -	nc = host->dma.nc; - -	switch (host->pdev_id) { -	case 1: -		crci = MSMSDCC_CRCI_SDC1; -		break; -	case 2: -		crci = MSMSDCC_CRCI_SDC2; -		break; -	case 3: -		crci = MSMSDCC_CRCI_SDC3; -		break; -	case 4: -		crci = MSMSDCC_CRCI_SDC4; -		break; -	default: -		host->dma.sg = NULL; -		host->dma.num_ents = 0; -		return -ENOENT; -	} - -	if (data->flags & MMC_DATA_READ) -		host->dma.dir = DMA_FROM_DEVICE; -	else -		host->dma.dir = DMA_TO_DEVICE; - -	host->curr.user_pages = 0; - -	box = &nc->cmd[0]; - -	/* location of command block must be 64 bit aligned */ -	BUG_ON(host->dma.cmd_busaddr & 0x07); - -	nc->cmdptr = (host->dma.cmd_busaddr >> 3) | CMD_PTR_LP; -	host->dma.hdr.cmdptr = DMOV_CMD_PTR_LIST | -			       DMOV_CMD_ADDR(host->dma.cmdptr_busaddr); -	host->dma.hdr.complete_func = msmsdcc_dma_complete_func; - -	n = dma_map_sg(mmc_dev(host->mmc), host->dma.sg, -			host->dma.num_ents, host->dma.dir); -	if (n == 0) { -		pr_err("%s: Unable to map in all sg elements\n", -			mmc_hostname(host->mmc)); -		host->dma.sg = NULL; -		host->dma.num_ents = 0; -		return -ENOMEM; -	} - -	for_each_sg(host->dma.sg, sg, n, i) { - -		box->cmd = CMD_MODE_BOX; - -		if (i == n - 1) -			box->cmd |= CMD_LC; -		rows = (sg_dma_len(sg) % MCI_FIFOSIZE) ? -			(sg_dma_len(sg) / MCI_FIFOSIZE) + 1 : -			(sg_dma_len(sg) / MCI_FIFOSIZE) ; - -		if (data->flags & MMC_DATA_READ) { -			box->src_row_addr = msmsdcc_fifo_addr(host); -			box->dst_row_addr = sg_dma_address(sg); - -			box->src_dst_len = (MCI_FIFOSIZE << 16) | -					   (MCI_FIFOSIZE); -			box->row_offset = MCI_FIFOSIZE; - -			box->num_rows = rows * ((1 << 16) + 1); -			box->cmd |= CMD_SRC_CRCI(crci); -		} else { -			box->src_row_addr = sg_dma_address(sg); -			box->dst_row_addr = msmsdcc_fifo_addr(host); - -			box->src_dst_len = (MCI_FIFOSIZE << 16) | -					   (MCI_FIFOSIZE); -			box->row_offset = (MCI_FIFOSIZE << 16); - -			box->num_rows = rows * ((1 << 16) + 1); -			box->cmd |= CMD_DST_CRCI(crci); -		} -		box++; -	} - -	return 0; -} - -static int -snoop_cccr_abort(struct mmc_command *cmd) -{ -	if ((cmd->opcode == 52) && -	    (cmd->arg & 0x80000000) && -	    (((cmd->arg >> 9) & 0x1ffff) == SDIO_CCCR_ABORT)) -		return 1; -	return 0; -} - -static void -msmsdcc_start_command_deferred(struct msmsdcc_host *host, -				struct mmc_command *cmd, u32 *c) -{ -	*c |= (cmd->opcode | MCI_CPSM_ENABLE); - -	if (cmd->flags & MMC_RSP_PRESENT) { -		if (cmd->flags & MMC_RSP_136) -			*c |= MCI_CPSM_LONGRSP; -		*c |= MCI_CPSM_RESPONSE; -	} - -	if (/*interrupt*/0) -		*c |= MCI_CPSM_INTERRUPT; - -	if ((((cmd->opcode == 17) || (cmd->opcode == 18))  || -	     ((cmd->opcode == 24) || (cmd->opcode == 25))) || -	      (cmd->opcode == 53)) -		*c |= MCI_CSPM_DATCMD; - -	if (host->prog_scan && (cmd->opcode == 12)) { -		*c |= MCI_CPSM_PROGENA; -		host->prog_enable = true; -	} - -	if (cmd == cmd->mrq->stop) -		*c |= MCI_CSPM_MCIABORT; - -	if (snoop_cccr_abort(cmd)) -		*c |= MCI_CSPM_MCIABORT; - -	if (host->curr.cmd != NULL) { -		pr_err("%s: Overlapping command requests\n", -			mmc_hostname(host->mmc)); -	} -	host->curr.cmd = cmd; -} - -static void -msmsdcc_start_data(struct msmsdcc_host *host, struct mmc_data *data, -			struct mmc_command *cmd, u32 c) -{ -	unsigned int datactrl, timeout; -	unsigned long long clks; -	unsigned int pio_irqmask = 0; - -	host->curr.data = data; -	host->curr.xfer_size = data->blksz * data->blocks; -	host->curr.xfer_remain = host->curr.xfer_size; -	host->curr.data_xfered = 0; -	host->curr.got_dataend = 0; - -	memset(&host->pio, 0, sizeof(host->pio)); - -	datactrl = MCI_DPSM_ENABLE | (data->blksz << 4); - -	if (!msmsdcc_config_dma(host, data)) -		datactrl |= MCI_DPSM_DMAENABLE; -	else { -		host->pio.sg = data->sg; -		host->pio.sg_len = data->sg_len; -		host->pio.sg_off = 0; - -		if (data->flags & MMC_DATA_READ) { -			pio_irqmask = MCI_RXFIFOHALFFULLMASK; -			if (host->curr.xfer_remain < MCI_FIFOSIZE) -				pio_irqmask |= MCI_RXDATAAVLBLMASK; -		} else -			pio_irqmask = MCI_TXFIFOHALFEMPTYMASK; -	} - -	if (data->flags & MMC_DATA_READ) -		datactrl |= MCI_DPSM_DIRECTION; - -	clks = (unsigned long long)data->timeout_ns * host->clk_rate; -	do_div(clks, NSEC_PER_SEC); -	timeout = data->timeout_clks + (unsigned int)clks*2 ; - -	if (datactrl & MCI_DPSM_DMAENABLE) { -		/* Save parameters for the exec function */ -		host->cmd_timeout = timeout; -		host->cmd_pio_irqmask = pio_irqmask; -		host->cmd_datactrl = datactrl; -		host->cmd_cmd = cmd; - -		host->dma.hdr.execute_func = msmsdcc_dma_exec_func; -		host->dma.hdr.data = (void *)host; -		host->dma.busy = 1; - -		if (cmd) { -			msmsdcc_start_command_deferred(host, cmd, &c); -			host->cmd_c = c; -		} -		msm_dmov_enqueue_cmd(host->dma.channel, &host->dma.hdr); -		if (data->flags & MMC_DATA_WRITE) -			host->prog_scan = true; -	} else { -		msmsdcc_writel(host, timeout, MMCIDATATIMER); - -		msmsdcc_writel(host, host->curr.xfer_size, MMCIDATALENGTH); - -		msmsdcc_writel(host, (msmsdcc_readl(host, MMCIMASK0) & -				(~MCI_IRQ_PIO)) | pio_irqmask, MMCIMASK0); - -		msmsdcc_writel(host, datactrl, MMCIDATACTRL); - -		if (cmd) { -			/* Daisy-chain the command if requested */ -			msmsdcc_start_command(host, cmd, c); -		} -	} -} - -static void -msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) -{ -	if (cmd == cmd->mrq->stop) -		c |= MCI_CSPM_MCIABORT; - -	host->stats.cmds++; - -	msmsdcc_start_command_deferred(host, cmd, &c); -	msmsdcc_start_command_exec(host, cmd->arg, c); -} - -static void -msmsdcc_data_err(struct msmsdcc_host *host, struct mmc_data *data, -		 unsigned int status) -{ -	if (status & MCI_DATACRCFAIL) { -		pr_err("%s: Data CRC error\n", mmc_hostname(host->mmc)); -		pr_err("%s: opcode 0x%.8x\n", __func__, -		       data->mrq->cmd->opcode); -		pr_err("%s: blksz %d, blocks %d\n", __func__, -		       data->blksz, data->blocks); -		data->error = -EILSEQ; -	} else if (status & MCI_DATATIMEOUT) { -		pr_err("%s: Data timeout\n", mmc_hostname(host->mmc)); -		data->error = -ETIMEDOUT; -	} else if (status & MCI_RXOVERRUN) { -		pr_err("%s: RX overrun\n", mmc_hostname(host->mmc)); -		data->error = -EIO; -	} else if (status & MCI_TXUNDERRUN) { -		pr_err("%s: TX underrun\n", mmc_hostname(host->mmc)); -		data->error = -EIO; -	} else { -		pr_err("%s: Unknown error (0x%.8x)\n", -		       mmc_hostname(host->mmc), status); -		data->error = -EIO; -	} -} - - -static int -msmsdcc_pio_read(struct msmsdcc_host *host, char *buffer, unsigned int remain) -{ -	uint32_t	*ptr = (uint32_t *) buffer; -	int		count = 0; - -	if (remain % 4) -		remain = ((remain >> 2) + 1) << 2; - -	while (msmsdcc_readl(host, MMCISTATUS) & MCI_RXDATAAVLBL) { -		*ptr = msmsdcc_readl(host, MMCIFIFO + (count % MCI_FIFOSIZE)); -		ptr++; -		count += sizeof(uint32_t); - -		remain -=  sizeof(uint32_t); -		if (remain == 0) -			break; -	} -	return count; -} - -static int -msmsdcc_pio_write(struct msmsdcc_host *host, char *buffer, -		  unsigned int remain, u32 status) -{ -	void __iomem *base = host->base; -	char *ptr = buffer; - -	do { -		unsigned int count, maxcnt, sz; - -		maxcnt = status & MCI_TXFIFOEMPTY ? MCI_FIFOSIZE : -						    MCI_FIFOHALFSIZE; -		count = min(remain, maxcnt); - -		sz = count % 4 ? (count >> 2) + 1 : (count >> 2); -		writesl(base + MMCIFIFO, ptr, sz); -		ptr += count; -		remain -= count; - -		if (remain == 0) -			break; - -		status = msmsdcc_readl(host, MMCISTATUS); -	} while (status & MCI_TXFIFOHALFEMPTY); - -	return ptr - buffer; -} - -static int -msmsdcc_spin_on_status(struct msmsdcc_host *host, uint32_t mask, int maxspin) -{ -	while (maxspin) { -		if ((msmsdcc_readl(host, MMCISTATUS) & mask)) -			return 0; -		udelay(1); -		--maxspin; -	} -	return -ETIMEDOUT; -} - -static irqreturn_t -msmsdcc_pio_irq(int irq, void *dev_id) -{ -	struct msmsdcc_host	*host = dev_id; -	uint32_t		status; -	u32 mci_mask0; - -	status = msmsdcc_readl(host, MMCISTATUS); -	mci_mask0 = msmsdcc_readl(host, MMCIMASK0); - -	if (((mci_mask0 & status) & MCI_IRQ_PIO) == 0) -		return IRQ_NONE; - -	do { -		unsigned long flags; -		unsigned int remain, len; -		char *buffer; - -		if (!(status & (MCI_TXFIFOHALFEMPTY | MCI_RXDATAAVLBL))) { -			if (host->curr.xfer_remain == 0 || !msmsdcc_piopoll) -				break; - -			if (msmsdcc_spin_on_status(host, -						   (MCI_TXFIFOHALFEMPTY | -						   MCI_RXDATAAVLBL), -						   PIO_SPINMAX)) { -				break; -			} -		} - -		/* Map the current scatter buffer */ -		local_irq_save(flags); -		buffer = kmap_atomic(sg_page(host->pio.sg)) -				     + host->pio.sg->offset; -		buffer += host->pio.sg_off; -		remain = host->pio.sg->length - host->pio.sg_off; -		len = 0; -		if (status & MCI_RXACTIVE) -			len = msmsdcc_pio_read(host, buffer, remain); -		if (status & MCI_TXACTIVE) -			len = msmsdcc_pio_write(host, buffer, remain, status); - -		/* Unmap the buffer */ -		kunmap_atomic(buffer); -		local_irq_restore(flags); - -		host->pio.sg_off += len; -		host->curr.xfer_remain -= len; -		host->curr.data_xfered += len; -		remain -= len; - -		if (remain == 0) { -			/* This sg page is full - do some housekeeping */ -			if (status & MCI_RXACTIVE && host->curr.user_pages) -				flush_dcache_page(sg_page(host->pio.sg)); - -			if (!--host->pio.sg_len) { -				memset(&host->pio, 0, sizeof(host->pio)); -				break; -			} - -			/* Advance to next sg */ -			host->pio.sg++; -			host->pio.sg_off = 0; -		} - -		status = msmsdcc_readl(host, MMCISTATUS); -	} while (1); - -	if (status & MCI_RXACTIVE && host->curr.xfer_remain < MCI_FIFOSIZE) -		msmsdcc_writel(host, (mci_mask0 & (~MCI_IRQ_PIO)) | -					MCI_RXDATAAVLBLMASK, MMCIMASK0); - -	if (!host->curr.xfer_remain) -		msmsdcc_writel(host, (mci_mask0 & (~MCI_IRQ_PIO)) | 0, -					MMCIMASK0); - -	return IRQ_HANDLED; -} - -static void msmsdcc_do_cmdirq(struct msmsdcc_host *host, uint32_t status) -{ -	struct mmc_command *cmd = host->curr.cmd; - -	host->curr.cmd = NULL; -	cmd->resp[0] = msmsdcc_readl(host, MMCIRESPONSE0); -	cmd->resp[1] = msmsdcc_readl(host, MMCIRESPONSE1); -	cmd->resp[2] = msmsdcc_readl(host, MMCIRESPONSE2); -	cmd->resp[3] = msmsdcc_readl(host, MMCIRESPONSE3); - -	if (status & MCI_CMDTIMEOUT) { -		cmd->error = -ETIMEDOUT; -	} else if (status & MCI_CMDCRCFAIL && -		   cmd->flags & MMC_RSP_CRC) { -		pr_err("%s: Command CRC error\n", mmc_hostname(host->mmc)); -		cmd->error = -EILSEQ; -	} - -	if (!cmd->data || cmd->error) { -		if (host->curr.data && host->dma.sg) -			msm_dmov_stop_cmd(host->dma.channel, -					  &host->dma.hdr, 0); -		else if (host->curr.data) { /* Non DMA */ -			msmsdcc_reset_and_restore(host); -			msmsdcc_stop_data(host); -			msmsdcc_request_end(host, cmd->mrq); -		} else { /* host->data == NULL */ -			if (!cmd->error && host->prog_enable) { -				if (status & MCI_PROGDONE) { -					host->prog_scan = false; -					host->prog_enable = false; -					msmsdcc_request_end(host, cmd->mrq); -				} else { -					host->curr.cmd = cmd; -				} -			} else { -				if (host->prog_enable) { -					host->prog_scan = false; -					host->prog_enable = false; -				} -				msmsdcc_request_end(host, cmd->mrq); -			} -		} -	} else if (cmd->data) -		if (!(cmd->data->flags & MMC_DATA_READ)) -			msmsdcc_start_data(host, cmd->data, -						NULL, 0); -} - -static void -msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, -			void __iomem *base) -{ -	struct mmc_data *data = host->curr.data; - -	if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL | -			MCI_CMDTIMEOUT | MCI_PROGDONE) && host->curr.cmd) { -		msmsdcc_do_cmdirq(host, status); -	} - -	if (!data) -		return; - -	/* Check for data errors */ -	if (status & (MCI_DATACRCFAIL | MCI_DATATIMEOUT | -		      MCI_TXUNDERRUN | MCI_RXOVERRUN)) { -		msmsdcc_data_err(host, data, status); -		host->curr.data_xfered = 0; -		if (host->dma.sg) -			msm_dmov_stop_cmd(host->dma.channel, -					  &host->dma.hdr, 0); -		else { -			msmsdcc_reset_and_restore(host); -			if (host->curr.data) -				msmsdcc_stop_data(host); -			if (!data->stop) -				msmsdcc_request_end(host, data->mrq); -			else -				msmsdcc_start_command(host, data->stop, 0); -		} -	} - -	/* Check for data done */ -	if (!host->curr.got_dataend && (status & MCI_DATAEND)) -		host->curr.got_dataend = 1; - -	/* -	 * If DMA is still in progress, we complete via the completion handler -	 */ -	if (host->curr.got_dataend && !host->dma.busy) { -		/* -		 * There appears to be an issue in the controller where -		 * if you request a small block transfer (< fifo size), -		 * you may get your DATAEND/DATABLKEND irq without the -		 * PIO data irq. -		 * -		 * Check to see if there is still data to be read, -		 * and simulate a PIO irq. -		 */ -		if (readl(base + MMCISTATUS) & MCI_RXDATAAVLBL) -			msmsdcc_pio_irq(1, host); - -		msmsdcc_stop_data(host); -		if (!data->error) -			host->curr.data_xfered = host->curr.xfer_size; - -		if (!data->stop) -			msmsdcc_request_end(host, data->mrq); -		else -			msmsdcc_start_command(host, data->stop, 0); -	} -} - -static irqreturn_t -msmsdcc_irq(int irq, void *dev_id) -{ -	struct msmsdcc_host	*host = dev_id; -	void __iomem		*base = host->base; -	u32			status; -	int			ret = 0; -	int			cardint = 0; - -	spin_lock(&host->lock); - -	do { -		status = msmsdcc_readl(host, MMCISTATUS); -		status &= msmsdcc_readl(host, MMCIMASK0); -		if ((status & (~MCI_IRQ_PIO)) == 0) -			break; -		msmsdcc_writel(host, status, MMCICLEAR); - -		if (status & MCI_SDIOINTR) -			status &= ~MCI_SDIOINTR; - -		if (!status) -			break; - -		msmsdcc_handle_irq_data(host, status, base); - -		if (status & MCI_SDIOINTOPER) { -			cardint = 1; -			status &= ~MCI_SDIOINTOPER; -		} -		ret = 1; -	} while (status); - -	spin_unlock(&host->lock); - -	/* -	 * We have to delay handling the card interrupt as it calls -	 * back into the driver. -	 */ -	if (cardint) -		mmc_signal_sdio_irq(host->mmc); - -	return IRQ_RETVAL(ret); -} - -static void -msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) -{ -	struct msmsdcc_host *host = mmc_priv(mmc); -	unsigned long flags; - -	WARN_ON(host->curr.mrq != NULL); -	WARN_ON(host->pwr == 0); - -	spin_lock_irqsave(&host->lock, flags); - -	host->stats.reqs++; - -	if (host->eject) { -		if (mrq->data && !(mrq->data->flags & MMC_DATA_READ)) { -			mrq->cmd->error = 0; -			mrq->data->bytes_xfered = mrq->data->blksz * -						  mrq->data->blocks; -		} else -			mrq->cmd->error = -ENOMEDIUM; - -		spin_unlock_irqrestore(&host->lock, flags); -		mmc_request_done(mmc, mrq); -		return; -	} - -	msmsdcc_enable_clocks(host); - -	host->curr.mrq = mrq; - -	if (mrq->data && mrq->data->flags & MMC_DATA_READ) -		/* Queue/read data, daisy-chain command when data starts */ -		msmsdcc_start_data(host, mrq->data, mrq->cmd, 0); -	else -		msmsdcc_start_command(host, mrq->cmd, 0); - -	if (host->cmdpoll && !msmsdcc_spin_on_status(host, -				MCI_CMDRESPEND|MCI_CMDCRCFAIL|MCI_CMDTIMEOUT, -				CMD_SPINMAX)) { -		uint32_t status = msmsdcc_readl(host, MMCISTATUS); -		msmsdcc_do_cmdirq(host, status); -		msmsdcc_writel(host, -			       MCI_CMDRESPEND | MCI_CMDCRCFAIL | MCI_CMDTIMEOUT, -			       MMCICLEAR); -		host->stats.cmdpoll_hits++; -	} else { -		host->stats.cmdpoll_misses++; -	} -	spin_unlock_irqrestore(&host->lock, flags); -} - -static void msmsdcc_setup_gpio(struct msmsdcc_host *host, bool enable) -{ -	struct msm_mmc_gpio_data *curr; -	int i, rc = 0; - -	if (!host->plat->gpio_data || host->gpio_config_status == enable) -		return; - -	curr = host->plat->gpio_data; -	for (i = 0; i < curr->size; i++) { -		if (enable) { -			rc = gpio_request(curr->gpio[i].no, -						curr->gpio[i].name); -			if (rc) { -				pr_err("%s: gpio_request(%d, %s) failed %d\n", -					mmc_hostname(host->mmc), -					curr->gpio[i].no, -					curr->gpio[i].name, rc); -				goto free_gpios; -			} -		} else { -			gpio_free(curr->gpio[i].no); -		} -	} -	host->gpio_config_status = enable; -	return; - -free_gpios: -	for (; i >= 0; i--) -		gpio_free(curr->gpio[i].no); -} - -static void -msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -{ -	struct msmsdcc_host *host = mmc_priv(mmc); -	u32 clk = 0, pwr = 0; -	int rc; -	unsigned long flags; - -	spin_lock_irqsave(&host->lock, flags); - -	msmsdcc_enable_clocks(host); - -	spin_unlock_irqrestore(&host->lock, flags); - -	if (ios->clock) { -		if (ios->clock != host->clk_rate) { -			rc = clk_set_rate(host->clk, ios->clock); -			if (rc < 0) -				pr_err("%s: Error setting clock rate (%d)\n", -				       mmc_hostname(host->mmc), rc); -			else -				host->clk_rate = ios->clock; -		} -		clk |= MCI_CLK_ENABLE; -	} - -	if (ios->bus_width == MMC_BUS_WIDTH_4) -		clk |= (2 << 10); /* Set WIDEBUS */ - -	if (ios->clock > 400000 && msmsdcc_pwrsave) -		clk |= (1 << 9); /* PWRSAVE */ - -	clk |= (1 << 12); /* FLOW_ENA */ -	clk |= (1 << 15); /* feedback clock */ - -	if (host->plat->translate_vdd) -		pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); - -	switch (ios->power_mode) { -	case MMC_POWER_OFF: -		msmsdcc_setup_gpio(host, false); -		break; -	case MMC_POWER_UP: -		pwr |= MCI_PWR_UP; -		msmsdcc_setup_gpio(host, true); -		break; -	case MMC_POWER_ON: -		pwr |= MCI_PWR_ON; -		break; -	} - -	if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) -		pwr |= MCI_OD; - -	msmsdcc_writel(host, clk, MMCICLOCK); - -	if (host->pwr != pwr) { -		host->pwr = pwr; -		msmsdcc_writel(host, pwr, MMCIPOWER); -	} -#if BUSCLK_PWRSAVE -	spin_lock_irqsave(&host->lock, flags); -	msmsdcc_disable_clocks(host, 1); -	spin_unlock_irqrestore(&host->lock, flags); -#endif -} - -static void msmsdcc_enable_sdio_irq(struct mmc_host *mmc, int enable) -{ -	struct msmsdcc_host *host = mmc_priv(mmc); -	unsigned long flags; -	u32 status; - -	spin_lock_irqsave(&host->lock, flags); -	if (msmsdcc_sdioirq == 1) { -		status = msmsdcc_readl(host, MMCIMASK0); -		if (enable) -			status |= MCI_SDIOINTOPERMASK; -		else -			status &= ~MCI_SDIOINTOPERMASK; -		host->saved_irq0mask = status; -		msmsdcc_writel(host, status, MMCIMASK0); -	} -	spin_unlock_irqrestore(&host->lock, flags); -} - -static void msmsdcc_init_card(struct mmc_host *mmc, struct mmc_card *card) -{ -	struct msmsdcc_host *host = mmc_priv(mmc); - -	if (host->plat->init_card) -		host->plat->init_card(card); -} - -static const struct mmc_host_ops msmsdcc_ops = { -	.request	= msmsdcc_request, -	.set_ios	= msmsdcc_set_ios, -	.enable_sdio_irq = msmsdcc_enable_sdio_irq, -	.init_card	= msmsdcc_init_card, -}; - -static void -msmsdcc_check_status(unsigned long data) -{ -	struct msmsdcc_host *host = (struct msmsdcc_host *)data; -	unsigned int status; - -	if (!host->plat->status) { -		mmc_detect_change(host->mmc, 0); -		goto out; -	} - -	status = host->plat->status(mmc_dev(host->mmc)); -	host->eject = !status; -	if (status ^ host->oldstat) { -		pr_info("%s: Slot status change detected (%d -> %d)\n", -			mmc_hostname(host->mmc), host->oldstat, status); -		if (status) -			mmc_detect_change(host->mmc, (5 * HZ) / 2); -		else -			mmc_detect_change(host->mmc, 0); -	} - -	host->oldstat = status; - -out: -	if (host->timer.function) -		mod_timer(&host->timer, jiffies + HZ); -} - -static irqreturn_t -msmsdcc_platform_status_irq(int irq, void *dev_id) -{ -	struct msmsdcc_host *host = dev_id; - -	pr_debug("%s: %d\n", __func__, irq); -	msmsdcc_check_status((unsigned long) host); -	return IRQ_HANDLED; -} - -static void -msmsdcc_status_notify_cb(int card_present, void *dev_id) -{ -	struct msmsdcc_host *host = dev_id; - -	pr_debug("%s: card_present %d\n", mmc_hostname(host->mmc), -	       card_present); -	msmsdcc_check_status((unsigned long) host); -} - -static void -msmsdcc_busclk_expired(unsigned long _data) -{ -	struct msmsdcc_host	*host = (struct msmsdcc_host *) _data; - -	if (host->clks_on) -		msmsdcc_disable_clocks(host, 0); -} - -static int -msmsdcc_init_dma(struct msmsdcc_host *host) -{ -	memset(&host->dma, 0, sizeof(struct msmsdcc_dma_data)); -	host->dma.host = host; -	host->dma.channel = -1; - -	if (!host->dmares) -		return -ENODEV; - -	host->dma.nc = dma_alloc_coherent(NULL, -					  sizeof(struct msmsdcc_nc_dmadata), -					  &host->dma.nc_busaddr, -					  GFP_KERNEL); -	if (host->dma.nc == NULL) { -		pr_err("Unable to allocate DMA buffer\n"); -		return -ENOMEM; -	} -	memset(host->dma.nc, 0x00, sizeof(struct msmsdcc_nc_dmadata)); -	host->dma.cmd_busaddr = host->dma.nc_busaddr; -	host->dma.cmdptr_busaddr = host->dma.nc_busaddr + -				offsetof(struct msmsdcc_nc_dmadata, cmdptr); -	host->dma.channel = host->dmares->start; - -	return 0; -} - -static int -msmsdcc_probe(struct platform_device *pdev) -{ -	struct msm_mmc_platform_data *plat = pdev->dev.platform_data; -	struct msmsdcc_host *host; -	struct mmc_host *mmc; -	struct resource *cmd_irqres = NULL; -	struct resource *stat_irqres = NULL; -	struct resource *memres = NULL; -	struct resource *dmares = NULL; -	int ret; - -	/* must have platform data */ -	if (!plat) { -		pr_err("%s: Platform data not available\n", __func__); -		ret = -EINVAL; -		goto out; -	} - -	if (pdev->id < 1 || pdev->id > 4) -		return -EINVAL; - -	if (pdev->resource == NULL || pdev->num_resources < 2) { -		pr_err("%s: Invalid resource\n", __func__); -		return -ENXIO; -	} - -	memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); -	cmd_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, -						  "cmd_irq"); -	stat_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, -						   "status_irq"); - -	if (!cmd_irqres || !memres) { -		pr_err("%s: Invalid resource\n", __func__); -		return -ENXIO; -	} - -	/* -	 * Setup our host structure -	 */ - -	mmc = mmc_alloc_host(sizeof(struct msmsdcc_host), &pdev->dev); -	if (!mmc) { -		ret = -ENOMEM; -		goto out; -	} - -	host = mmc_priv(mmc); -	host->pdev_id = pdev->id; -	host->plat = plat; -	host->mmc = mmc; -	host->curr.cmd = NULL; -	init_timer(&host->busclk_timer); -	host->busclk_timer.data = (unsigned long) host; -	host->busclk_timer.function = msmsdcc_busclk_expired; - - -	host->cmdpoll = 1; - -	host->base = ioremap(memres->start, PAGE_SIZE); -	if (!host->base) { -		ret = -ENOMEM; -		goto host_free; -	} - -	host->cmd_irqres = cmd_irqres; -	host->memres = memres; -	host->dmares = dmares; -	spin_lock_init(&host->lock); - -	tasklet_init(&host->dma_tlet, msmsdcc_dma_complete_tlet, -			(unsigned long)host); - -	/* -	 * Setup DMA -	 */ -	if (host->dmares) { -		ret = msmsdcc_init_dma(host); -		if (ret) -			goto ioremap_free; -	} else { -		host->dma.channel = -1; -	} - -	/* Get our clocks */ -	host->pclk = clk_get(&pdev->dev, "sdc_pclk"); -	if (IS_ERR(host->pclk)) { -		ret = PTR_ERR(host->pclk); -		goto dma_free; -	} - -	host->clk = clk_get(&pdev->dev, "sdc_clk"); -	if (IS_ERR(host->clk)) { -		ret = PTR_ERR(host->clk); -		goto pclk_put; -	} - -	ret = clk_set_rate(host->clk, msmsdcc_fmin); -	if (ret) { -		pr_err("%s: Clock rate set failed (%d)\n", __func__, ret); -		goto clk_put; -	} - -	ret = clk_prepare(host->pclk); -	if (ret) -		goto clk_put; - -	ret = clk_prepare(host->clk); -	if (ret) -		goto clk_unprepare_p; - -	/* Enable clocks */ -	ret = msmsdcc_enable_clocks(host); -	if (ret) -		goto clk_unprepare; - -	host->pclk_rate = clk_get_rate(host->pclk); -	host->clk_rate = clk_get_rate(host->clk); - -	/* -	 * Setup MMC host structure -	 */ -	mmc->ops = &msmsdcc_ops; -	mmc->f_min = msmsdcc_fmin; -	mmc->f_max = msmsdcc_fmax; -	mmc->ocr_avail = plat->ocr_mask; - -	if (msmsdcc_4bit) -		mmc->caps |= MMC_CAP_4_BIT_DATA; -	if (msmsdcc_sdioirq) -		mmc->caps |= MMC_CAP_SDIO_IRQ; -	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED; - -	mmc->max_segs = NR_SG; -	mmc->max_blk_size = 4096;	/* MCI_DATA_CTL BLOCKSIZE up to 4096 */ -	mmc->max_blk_count = 65536; - -	mmc->max_req_size = 33554432;	/* MCI_DATA_LENGTH is 25 bits */ -	mmc->max_seg_size = mmc->max_req_size; - -	msmsdcc_writel(host, 0, MMCIMASK0); -	msmsdcc_writel(host, 0x5e007ff, MMCICLEAR); - -	msmsdcc_writel(host, MCI_IRQENABLE, MMCIMASK0); -	host->saved_irq0mask = MCI_IRQENABLE; - -	/* -	 * Setup card detect change -	 */ - -	memset(&host->timer, 0, sizeof(host->timer)); - -	if (stat_irqres && !(stat_irqres->flags & IORESOURCE_DISABLED)) { -		unsigned long irqflags = IRQF_SHARED | -			(stat_irqres->flags & IRQF_TRIGGER_MASK); - -		host->stat_irq = stat_irqres->start; -		ret = request_irq(host->stat_irq, -				  msmsdcc_platform_status_irq, -				  irqflags, -				  DRIVER_NAME " (slot)", -				  host); -		if (ret) { -			pr_err("%s: Unable to get slot IRQ %d (%d)\n", -			       mmc_hostname(mmc), host->stat_irq, ret); -			goto clk_disable; -		} -	} else if (plat->register_status_notify) { -		plat->register_status_notify(msmsdcc_status_notify_cb, host); -	} else if (!plat->status) -		pr_err("%s: No card detect facilities available\n", -		       mmc_hostname(mmc)); -	else { -		init_timer(&host->timer); -		host->timer.data = (unsigned long)host; -		host->timer.function = msmsdcc_check_status; -		host->timer.expires = jiffies + HZ; -		add_timer(&host->timer); -	} - -	if (plat->status) { -		host->oldstat = host->plat->status(mmc_dev(host->mmc)); -		host->eject = !host->oldstat; -	} - -	ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED, -			  DRIVER_NAME " (cmd)", host); -	if (ret) -		goto stat_irq_free; - -	ret = request_irq(cmd_irqres->start, msmsdcc_pio_irq, IRQF_SHARED, -			  DRIVER_NAME " (pio)", host); -	if (ret) -		goto cmd_irq_free; - -	platform_set_drvdata(pdev, mmc); -	mmc_add_host(mmc); - -	pr_info("%s: Qualcomm MSM SDCC at 0x%016llx irq %d,%d dma %d\n", -		mmc_hostname(mmc), (unsigned long long)memres->start, -		(unsigned int) cmd_irqres->start, -		(unsigned int) host->stat_irq, host->dma.channel); -	pr_info("%s: 4 bit data mode %s\n", mmc_hostname(mmc), -		(mmc->caps & MMC_CAP_4_BIT_DATA ? "enabled" : "disabled")); -	pr_info("%s: MMC clock %u -> %u Hz, PCLK %u Hz\n", -		mmc_hostname(mmc), msmsdcc_fmin, msmsdcc_fmax, host->pclk_rate); -	pr_info("%s: Slot eject status = %d\n", mmc_hostname(mmc), host->eject); -	pr_info("%s: Power save feature enable = %d\n", -		mmc_hostname(mmc), msmsdcc_pwrsave); - -	if (host->dma.channel != -1) { -		pr_info("%s: DM non-cached buffer at %p, dma_addr 0x%.8x\n", -			mmc_hostname(mmc), host->dma.nc, host->dma.nc_busaddr); -		pr_info("%s: DM cmd busaddr 0x%.8x, cmdptr busaddr 0x%.8x\n", -			mmc_hostname(mmc), host->dma.cmd_busaddr, -			host->dma.cmdptr_busaddr); -	} else -		pr_info("%s: PIO transfer enabled\n", mmc_hostname(mmc)); -	if (host->timer.function) -		pr_info("%s: Polling status mode enabled\n", mmc_hostname(mmc)); - -	return 0; - cmd_irq_free: -	free_irq(cmd_irqres->start, host); - stat_irq_free: -	if (host->stat_irq) -		free_irq(host->stat_irq, host); - clk_disable: -	msmsdcc_disable_clocks(host, 0); - clk_unprepare: -	clk_unprepare(host->clk); - clk_unprepare_p: -	clk_unprepare(host->pclk); - clk_put: -	clk_put(host->clk); - pclk_put: -	clk_put(host->pclk); -dma_free: -	if (host->dmares) -		dma_free_coherent(NULL, sizeof(struct msmsdcc_nc_dmadata), -					host->dma.nc, host->dma.nc_busaddr); -ioremap_free: -	tasklet_kill(&host->dma_tlet); -	iounmap(host->base); - host_free: -	mmc_free_host(mmc); - out: -	return ret; -} - -#ifdef CONFIG_PM -static int -msmsdcc_suspend(struct platform_device *dev, pm_message_t state) -{ -	struct mmc_host *mmc = platform_get_drvdata(dev); - -	if (mmc) { -		struct msmsdcc_host *host = mmc_priv(mmc); - -		if (host->stat_irq) -			disable_irq(host->stat_irq); - -		msmsdcc_writel(host, 0, MMCIMASK0); -		if (host->clks_on) -			msmsdcc_disable_clocks(host, 0); -	} -	return 0; -} - -static int -msmsdcc_resume(struct platform_device *dev) -{ -	struct mmc_host *mmc = platform_get_drvdata(dev); - -	if (mmc) { -		struct msmsdcc_host *host = mmc_priv(mmc); - -		msmsdcc_enable_clocks(host); - -		msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0); - -		if (host->stat_irq) -			enable_irq(host->stat_irq); -#if BUSCLK_PWRSAVE -		msmsdcc_disable_clocks(host, 1); -#endif -	} -	return 0; -} -#else -#define msmsdcc_suspend	0 -#define msmsdcc_resume 0 -#endif - -static struct platform_driver msmsdcc_driver = { -	.probe		= msmsdcc_probe, -	.suspend	= msmsdcc_suspend, -	.resume		= msmsdcc_resume, -	.driver		= { -		.name	= "msm_sdcc", -	}, -}; - -module_platform_driver(msmsdcc_driver); - -MODULE_DESCRIPTION("Qualcomm MSM 7X00A Multimedia Card Interface driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/msm_sdcc.h b/drivers/mmc/host/msm_sdcc.h deleted file mode 100644 index 402028d16b86..000000000000 --- a/drivers/mmc/host/msm_sdcc.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - *  linux/drivers/mmc/host/msmsdcc.h - QCT MSM7K SDC Controller - * - *  Copyright (C) 2008 Google, All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * - Based on mmci.h - */ - -#ifndef _MSM_SDCC_H -#define _MSM_SDCC_H - -#define MSMSDCC_CRCI_SDC1	6 -#define MSMSDCC_CRCI_SDC2	7 -#define MSMSDCC_CRCI_SDC3	12 -#define MSMSDCC_CRCI_SDC4	13 - -#define MMCIPOWER		0x000 -#define MCI_PWR_OFF		0x00 -#define MCI_PWR_UP		0x02 -#define MCI_PWR_ON		0x03 -#define MCI_OD			(1 << 6) - -#define MMCICLOCK		0x004 -#define MCI_CLK_ENABLE		(1 << 8) -#define MCI_CLK_PWRSAVE		(1 << 9) -#define MCI_CLK_WIDEBUS		(1 << 10) -#define MCI_CLK_FLOWENA		(1 << 12) -#define MCI_CLK_INVERTOUT	(1 << 13) -#define MCI_CLK_SELECTIN	(1 << 14) - -#define MMCIARGUMENT		0x008 -#define MMCICOMMAND		0x00c -#define MCI_CPSM_RESPONSE	(1 << 6) -#define MCI_CPSM_LONGRSP	(1 << 7) -#define MCI_CPSM_INTERRUPT	(1 << 8) -#define MCI_CPSM_PENDING	(1 << 9) -#define MCI_CPSM_ENABLE		(1 << 10) -#define MCI_CPSM_PROGENA	(1 << 11) -#define MCI_CSPM_DATCMD		(1 << 12) -#define MCI_CSPM_MCIABORT	(1 << 13) -#define MCI_CSPM_CCSENABLE	(1 << 14) -#define MCI_CSPM_CCSDISABLE	(1 << 15) - - -#define MMCIRESPCMD		0x010 -#define MMCIRESPONSE0		0x014 -#define MMCIRESPONSE1		0x018 -#define MMCIRESPONSE2		0x01c -#define MMCIRESPONSE3		0x020 -#define MMCIDATATIMER		0x024 -#define MMCIDATALENGTH		0x028 - -#define MMCIDATACTRL		0x02c -#define MCI_DPSM_ENABLE		(1 << 0) -#define MCI_DPSM_DIRECTION	(1 << 1) -#define MCI_DPSM_MODE		(1 << 2) -#define MCI_DPSM_DMAENABLE	(1 << 3) - -#define MMCIDATACNT		0x030 -#define MMCISTATUS		0x034 -#define MCI_CMDCRCFAIL		(1 << 0) -#define MCI_DATACRCFAIL		(1 << 1) -#define MCI_CMDTIMEOUT		(1 << 2) -#define MCI_DATATIMEOUT		(1 << 3) -#define MCI_TXUNDERRUN		(1 << 4) -#define MCI_RXOVERRUN		(1 << 5) -#define MCI_CMDRESPEND		(1 << 6) -#define MCI_CMDSENT		(1 << 7) -#define MCI_DATAEND		(1 << 8) -#define MCI_DATABLOCKEND	(1 << 10) -#define MCI_CMDACTIVE		(1 << 11) -#define MCI_TXACTIVE		(1 << 12) -#define MCI_RXACTIVE		(1 << 13) -#define MCI_TXFIFOHALFEMPTY	(1 << 14) -#define MCI_RXFIFOHALFFULL	(1 << 15) -#define MCI_TXFIFOFULL		(1 << 16) -#define MCI_RXFIFOFULL		(1 << 17) -#define MCI_TXFIFOEMPTY		(1 << 18) -#define MCI_RXFIFOEMPTY		(1 << 19) -#define MCI_TXDATAAVLBL		(1 << 20) -#define MCI_RXDATAAVLBL		(1 << 21) -#define MCI_SDIOINTR		(1 << 22) -#define MCI_PROGDONE		(1 << 23) -#define MCI_ATACMDCOMPL		(1 << 24) -#define MCI_SDIOINTOPER		(1 << 25) -#define MCI_CCSTIMEOUT		(1 << 26) - -#define MMCICLEAR		0x038 -#define MCI_CMDCRCFAILCLR	(1 << 0) -#define MCI_DATACRCFAILCLR	(1 << 1) -#define MCI_CMDTIMEOUTCLR	(1 << 2) -#define MCI_DATATIMEOUTCLR	(1 << 3) -#define MCI_TXUNDERRUNCLR	(1 << 4) -#define MCI_RXOVERRUNCLR	(1 << 5) -#define MCI_CMDRESPENDCLR	(1 << 6) -#define MCI_CMDSENTCLR		(1 << 7) -#define MCI_DATAENDCLR		(1 << 8) -#define MCI_DATABLOCKENDCLR	(1 << 10) - -#define MMCIMASK0		0x03c -#define MCI_CMDCRCFAILMASK	(1 << 0) -#define MCI_DATACRCFAILMASK	(1 << 1) -#define MCI_CMDTIMEOUTMASK	(1 << 2) -#define MCI_DATATIMEOUTMASK	(1 << 3) -#define MCI_TXUNDERRUNMASK	(1 << 4) -#define MCI_RXOVERRUNMASK	(1 << 5) -#define MCI_CMDRESPENDMASK	(1 << 6) -#define MCI_CMDSENTMASK		(1 << 7) -#define MCI_DATAENDMASK		(1 << 8) -#define MCI_DATABLOCKENDMASK	(1 << 10) -#define MCI_CMDACTIVEMASK	(1 << 11) -#define MCI_TXACTIVEMASK	(1 << 12) -#define MCI_RXACTIVEMASK	(1 << 13) -#define MCI_TXFIFOHALFEMPTYMASK	(1 << 14) -#define MCI_RXFIFOHALFFULLMASK	(1 << 15) -#define MCI_TXFIFOFULLMASK	(1 << 16) -#define MCI_RXFIFOFULLMASK	(1 << 17) -#define MCI_TXFIFOEMPTYMASK	(1 << 18) -#define MCI_RXFIFOEMPTYMASK	(1 << 19) -#define MCI_TXDATAAVLBLMASK	(1 << 20) -#define MCI_RXDATAAVLBLMASK	(1 << 21) -#define MCI_SDIOINTMASK		(1 << 22) -#define MCI_PROGDONEMASK	(1 << 23) -#define MCI_ATACMDCOMPLMASK	(1 << 24) -#define MCI_SDIOINTOPERMASK	(1 << 25) -#define MCI_CCSTIMEOUTMASK	(1 << 26) - -#define MMCIMASK1		0x040 -#define MMCIFIFOCNT		0x044 -#define MCICCSTIMER		0x058 - -#define MMCIFIFO		0x080 /* to 0x0bc */ - -#define MCI_IRQENABLE	\ -	(MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK|	\ -	MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK|	\ -	MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATAENDMASK|MCI_PROGDONEMASK) - -#define MCI_IRQ_PIO \ -	(MCI_RXDATAAVLBLMASK | MCI_TXDATAAVLBLMASK | MCI_RXFIFOEMPTYMASK | \ -	 MCI_TXFIFOEMPTYMASK | MCI_RXFIFOFULLMASK | MCI_TXFIFOFULLMASK | \ -	 MCI_RXFIFOHALFFULLMASK | MCI_TXFIFOHALFEMPTYMASK | \ -	 MCI_RXACTIVEMASK | MCI_TXACTIVEMASK) -/* - * The size of the FIFO in bytes. - */ -#define MCI_FIFOSIZE	(16*4) - -#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2) - -#define NR_SG		32 - -struct clk; - -struct msmsdcc_nc_dmadata { -	dmov_box	cmd[NR_SG]; -	uint32_t	cmdptr; -}; - -struct msmsdcc_dma_data { -	struct msmsdcc_nc_dmadata	*nc; -	dma_addr_t			nc_busaddr; -	dma_addr_t			cmd_busaddr; -	dma_addr_t			cmdptr_busaddr; - -	struct msm_dmov_cmd		hdr; -	enum dma_data_direction		dir; - -	struct scatterlist		*sg; -	int				num_ents; - -	int				channel; -	struct msmsdcc_host		*host; -	int				busy; /* Set if DM is busy */ -	int				active; -	unsigned int			result; -	struct msm_dmov_errdata		err; -}; - -struct msmsdcc_pio_data { -	struct scatterlist	*sg; -	unsigned int		sg_len; -	unsigned int		sg_off; -}; - -struct msmsdcc_curr_req { -	struct mmc_request	*mrq; -	struct mmc_command	*cmd; -	struct mmc_data		*data; -	unsigned int		xfer_size;	/* Total data size */ -	unsigned int		xfer_remain;	/* Bytes remaining to send */ -	unsigned int		data_xfered;	/* Bytes acked by BLKEND irq */ -	int			got_dataend; -	int			user_pages; -}; - -struct msmsdcc_stats { -	unsigned int reqs; -	unsigned int cmds; -	unsigned int cmdpoll_hits; -	unsigned int cmdpoll_misses; -}; - -struct msmsdcc_host { -	struct resource		*cmd_irqres; -	struct resource		*memres; -	struct resource		*dmares; -	void __iomem		*base; -	int			pdev_id; -	unsigned int		stat_irq; - -	struct msmsdcc_curr_req	curr; - -	struct mmc_host		*mmc; -	struct clk		*clk;		/* main MMC bus clock */ -	struct clk		*pclk;		/* SDCC peripheral bus clock */ -	unsigned int		clks_on;	/* set if clocks are enabled */ -	struct timer_list	busclk_timer; - -	unsigned int		eject;		/* eject state */ - -	spinlock_t		lock; - -	unsigned int		clk_rate;	/* Current clock rate */ -	unsigned int		pclk_rate; - -	u32			pwr; -	u32			saved_irq0mask;	/* MMCIMASK0 reg value */ -	struct msm_mmc_platform_data *plat; - -	struct timer_list	timer; -	unsigned int		oldstat; - -	struct msmsdcc_dma_data	dma; -	struct msmsdcc_pio_data	pio; -	int			cmdpoll; -	struct msmsdcc_stats	stats; - -	struct tasklet_struct	dma_tlet; -	/* Command parameters */ -	unsigned int		cmd_timeout; -	unsigned int		cmd_pio_irqmask; -	unsigned int		cmd_datactrl; -	struct mmc_command	*cmd_cmd; -	u32			cmd_c; -	bool			gpio_config_status; - -	bool prog_scan; -	bool prog_enable; -}; - -#endif diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 5316d9b9e7b4..317d709f7550 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -281,7 +281,7 @@ static inline void buffer_swap32(u32 *buf, int len)  	int i;  	for (i = 0; i < ((len + 3) / 4); i++) { -		st_le32(buf, *buf); +		*buf = swab32(*buf);  		buf++;  	}  } diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index f84cfb01716d..9df2b6801f76 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -222,10 +222,6 @@ struct omap_hsmmc_host {  	struct omap_hsmmc_next	next_data;  	struct	omap_hsmmc_platform_data	*pdata; -	/* To handle board related suspend/resume functionality for MMC */ -	int (*suspend)(struct device *dev); -	int (*resume)(struct device *dev); -  	/* return MMC cover switch state, can be NULL if not supported.  	 *  	 * possible return values: @@ -234,12 +230,7 @@ struct omap_hsmmc_host {  	 */  	int (*get_cover_state)(struct device *dev); -	/* Card detection IRQs */ -	int card_detect_irq; -  	int (*card_detect)(struct device *dev); -	int (*get_ro)(struct device *dev); -  };  struct omap_mmc_of_data { @@ -256,13 +247,6 @@ static int omap_hsmmc_card_detect(struct device *dev)  	return mmc_gpio_get_cd(host->mmc);  } -static int omap_hsmmc_get_wp(struct device *dev) -{ -	struct omap_hsmmc_host *host = dev_get_drvdata(dev); - -	return mmc_gpio_get_ro(host->mmc); -} -  static int omap_hsmmc_get_cover_state(struct device *dev)  {  	struct omap_hsmmc_host *host = dev_get_drvdata(dev); @@ -434,7 +418,7 @@ static inline int omap_hsmmc_have_reg(void)  #endif -static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id); +static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id);  static int omap_hsmmc_gpio_init(struct mmc_host *mmc,  				struct omap_hsmmc_host *host, @@ -442,29 +426,25 @@ static int omap_hsmmc_gpio_init(struct mmc_host *mmc,  {  	int ret; -	if (gpio_is_valid(pdata->switch_pin)) { -		if (pdata->cover) -			host->get_cover_state = -				omap_hsmmc_get_cover_state; -		else -			host->card_detect = omap_hsmmc_card_detect; -		host->card_detect_irq = -				gpio_to_irq(pdata->switch_pin); -		mmc_gpio_set_cd_isr(mmc, omap_hsmmc_detect); -		ret = mmc_gpio_request_cd(mmc, pdata->switch_pin, 0); +	if (gpio_is_valid(pdata->gpio_cod)) { +		ret = mmc_gpio_request_cd(mmc, pdata->gpio_cod, 0);  		if (ret)  			return ret; -	} else { -		pdata->switch_pin = -EINVAL; + +		host->get_cover_state = omap_hsmmc_get_cover_state; +		mmc_gpio_set_cd_isr(mmc, omap_hsmmc_cover_irq); +	} else if (gpio_is_valid(pdata->gpio_cd)) { +		ret = mmc_gpio_request_cd(mmc, pdata->gpio_cd, 0); +		if (ret) +			return ret; + +		host->card_detect = omap_hsmmc_card_detect;  	}  	if (gpio_is_valid(pdata->gpio_wp)) { -		host->get_ro = omap_hsmmc_get_wp;  		ret = mmc_gpio_request_ro(mmc, pdata->gpio_wp);  		if (ret)  			return ret; -	} else { -		pdata->gpio_wp = -EINVAL;  	}  	return 0; @@ -882,6 +862,8 @@ static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_req  		return;  	host->mrq = NULL;  	mmc_request_done(host->mmc, mrq); +	pm_runtime_mark_last_busy(host->dev); +	pm_runtime_put_autosuspend(host->dev);  }  /* @@ -1252,26 +1234,16 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)  }  /* - * irq handler to notify the core about card insertion/removal + * irq handler when (cell-phone) cover is mounted/removed   */ -static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id) +static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id)  {  	struct omap_hsmmc_host *host = dev_id; -	int carddetect;  	sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); -	if (host->card_detect) -		carddetect = host->card_detect(host->dev); -	else { -		omap_hsmmc_protect_card(host); -		carddetect = -ENOSYS; -	} - -	if (carddetect) -		mmc_detect_change(host->mmc, (HZ * 200) / 1000); -	else -		mmc_detect_change(host->mmc, (HZ * 50) / 1000); +	omap_hsmmc_protect_card(host); +	mmc_detect_change(host->mmc, (HZ * 200) / 1000);  	return IRQ_HANDLED;  } @@ -1305,6 +1277,8 @@ static void omap_hsmmc_dma_callback(void *param)  		host->mrq = NULL;  		mmc_request_done(host->mmc, mrq); +		pm_runtime_mark_last_busy(host->dev); +		pm_runtime_put_autosuspend(host->dev);  	}  } @@ -1537,6 +1511,7 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)  	BUG_ON(host->req_in_progress);  	BUG_ON(host->dma_ch != -1); +	pm_runtime_get_sync(host->dev);  	if (host->protect_card) {  		if (host->reqs_blocked < 3) {  			/* @@ -1553,6 +1528,8 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)  			req->data->error = -EBADF;  		req->cmd->retries = 0;  		mmc_request_done(mmc, req); +		pm_runtime_mark_last_busy(host->dev); +		pm_runtime_put_autosuspend(host->dev);  		return;  	} else if (host->reqs_blocked)  		host->reqs_blocked = 0; @@ -1566,6 +1543,8 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)  			req->data->error = err;  		host->mrq = NULL;  		mmc_request_done(mmc, req); +		pm_runtime_mark_last_busy(host->dev); +		pm_runtime_put_autosuspend(host->dev);  		return;  	}  	if (req->sbc && !(host->flags & AUTO_CMD23)) { @@ -1641,15 +1620,6 @@ static int omap_hsmmc_get_cd(struct mmc_host *mmc)  	return host->card_detect(host->dev);  } -static int omap_hsmmc_get_ro(struct mmc_host *mmc) -{ -	struct omap_hsmmc_host *host = mmc_priv(mmc); - -	if (!host->get_ro) -		return -ENOSYS; -	return host->get_ro(host->dev); -} -  static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)  {  	struct omap_hsmmc_host *host = mmc_priv(mmc); @@ -1778,25 +1748,6 @@ static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)  	set_sd_bus_power(host);  } -static int omap_hsmmc_enable_fclk(struct mmc_host *mmc) -{ -	struct omap_hsmmc_host *host = mmc_priv(mmc); - -	pm_runtime_get_sync(host->dev); - -	return 0; -} - -static int omap_hsmmc_disable_fclk(struct mmc_host *mmc) -{ -	struct omap_hsmmc_host *host = mmc_priv(mmc); - -	pm_runtime_mark_last_busy(host->dev); -	pm_runtime_put_autosuspend(host->dev); - -	return 0; -} -  static int omap_hsmmc_multi_io_quirk(struct mmc_card *card,  				     unsigned int direction, int blk_size)  { @@ -1808,14 +1759,12 @@ static int omap_hsmmc_multi_io_quirk(struct mmc_card *card,  }  static struct mmc_host_ops omap_hsmmc_ops = { -	.enable = omap_hsmmc_enable_fclk, -	.disable = omap_hsmmc_disable_fclk,  	.post_req = omap_hsmmc_post_req,  	.pre_req = omap_hsmmc_pre_req,  	.request = omap_hsmmc_request,  	.set_ios = omap_hsmmc_set_ios,  	.get_cd = omap_hsmmc_get_cd, -	.get_ro = omap_hsmmc_get_ro, +	.get_ro = mmc_gpio_get_ro,  	.init_card = omap_hsmmc_init_card,  	.enable_sdio_irq = omap_hsmmc_enable_sdio_irq,  }; @@ -1937,7 +1886,8 @@ static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev)  	if (of_find_property(np, "ti,dual-volt", NULL))  		pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT; -	pdata->switch_pin = -EINVAL; +	pdata->gpio_cd = -EINVAL; +	pdata->gpio_cod = -EINVAL;  	pdata->gpio_wp = -EINVAL;  	if (of_find_property(np, "ti,non-removable", NULL)) { @@ -2179,9 +2129,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev)  		if (ret < 0)  			goto err_slot_name;  	} -	if (host->card_detect_irq && host->get_cover_state) { +	if (host->get_cover_state) {  		ret = device_create_file(&mmc->class_dev, -					&dev_attr_cover_switch); +					 &dev_attr_cover_switch);  		if (ret < 0)  			goto err_slot_name;  	} @@ -2236,7 +2186,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int omap_hsmmc_suspend(struct device *dev)  {  	struct omap_hsmmc_host *host = dev_get_drvdata(dev); @@ -2292,10 +2242,6 @@ static int omap_hsmmc_resume(struct device *dev)  	pm_runtime_put_autosuspend(host->dev);  	return 0;  } - -#else -#define omap_hsmmc_suspend	NULL -#define omap_hsmmc_resume	NULL  #endif  static int omap_hsmmc_runtime_suspend(struct device *dev) @@ -2376,8 +2322,7 @@ static int omap_hsmmc_runtime_resume(struct device *dev)  }  static struct dev_pm_ops omap_hsmmc_dev_pm_ops = { -	.suspend	= omap_hsmmc_suspend, -	.resume		= omap_hsmmc_resume, +	SET_SYSTEM_SLEEP_PM_OPS(omap_hsmmc_suspend, omap_hsmmc_resume)  	.runtime_suspend = omap_hsmmc_runtime_suspend,  	.runtime_resume = omap_hsmmc_runtime_resume,  }; diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index a45ed39d062c..22d929fa3371 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -40,7 +40,6 @@  #include <linux/mmc/host.h>  #include <linux/mmc/pm.h>  #include <linux/mmc/slot-gpio.h> -#include <linux/mmc/sdhci.h>  #include "sdhci.h" diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c index 34bb8f92586e..2bd90fb35c75 100644 --- a/drivers/mmc/host/sdhci-bcm-kona.c +++ b/drivers/mmc/host/sdhci-bcm-kona.c @@ -54,7 +54,6 @@  struct sdhci_bcm_kona_dev {  	struct mutex	write_lock; /* protect back to back writes */ -	struct clk	*external_clk;  }; @@ -175,24 +174,6 @@ static void sdhci_bcm_kona_card_event(struct sdhci_host *host)  	}  } -/* - * Get the base clock. Use central clock source for now. Not sure if different - * clock speed to each dev is allowed - */ -static unsigned int sdhci_bcm_kona_get_max_clk(struct sdhci_host *host) -{ -	struct sdhci_bcm_kona_dev *kona_dev; -	struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host); -	kona_dev = sdhci_pltfm_priv(pltfm_priv); - -	return host->mmc->f_max; -} - -static unsigned int sdhci_bcm_kona_get_timeout_clock(struct sdhci_host *host) -{ -	return sdhci_bcm_kona_get_max_clk(host); -} -  static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host,  				u8 power_mode)  { @@ -207,8 +188,8 @@ static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host,  static struct sdhci_ops sdhci_bcm_kona_ops = {  	.set_clock = sdhci_set_clock, -	.get_max_clock = sdhci_bcm_kona_get_max_clk, -	.get_timeout_clock = sdhci_bcm_kona_get_timeout_clock, +	.get_max_clock = sdhci_pltfm_clk_get_max_clock, +	.get_timeout_clock = sdhci_pltfm_clk_get_max_clock,  	.platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks,  	.set_bus_width = sdhci_set_bus_width,  	.reset = sdhci_reset, @@ -264,21 +245,21 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)  		goto err_pltfm_free;  	} -	/* Get and enable the external clock */ -	kona_dev->external_clk = devm_clk_get(dev, NULL); -	if (IS_ERR(kona_dev->external_clk)) { -		dev_err(dev, "Failed to get external clock\n"); -		ret = PTR_ERR(kona_dev->external_clk); +	/* Get and enable the core clock */ +	pltfm_priv->clk = devm_clk_get(dev, NULL); +	if (IS_ERR(pltfm_priv->clk)) { +		dev_err(dev, "Failed to get core clock\n"); +		ret = PTR_ERR(pltfm_priv->clk);  		goto err_pltfm_free;  	} -	if (clk_set_rate(kona_dev->external_clk, host->mmc->f_max) != 0) { -		dev_err(dev, "Failed to set rate external clock\n"); +	if (clk_set_rate(pltfm_priv->clk, host->mmc->f_max) != 0) { +		dev_err(dev, "Failed to set rate core clock\n");  		goto err_pltfm_free;  	} -	if (clk_prepare_enable(kona_dev->external_clk) != 0) { -		dev_err(dev, "Failed to enable external clock\n"); +	if (clk_prepare_enable(pltfm_priv->clk) != 0) { +		dev_err(dev, "Failed to enable core clock\n");  		goto err_pltfm_free;  	} @@ -333,7 +314,7 @@ err_reset:  	sdhci_bcm_kona_sd_reset(host);  err_clk_disable: -	clk_disable_unprepare(kona_dev->external_clk); +	clk_disable_unprepare(pltfm_priv->clk);  err_pltfm_free:  	sdhci_pltfm_free(pdev); @@ -342,22 +323,6 @@ err_pltfm_free:  	return ret;  } -static int sdhci_bcm_kona_remove(struct platform_device *pdev) -{ -	struct sdhci_host *host = platform_get_drvdata(pdev); -	struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host); -	struct sdhci_bcm_kona_dev *kona_dev = sdhci_pltfm_priv(pltfm_priv); -	int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); - -	sdhci_remove_host(host, dead); - -	clk_disable_unprepare(kona_dev->external_clk); - -	sdhci_pltfm_free(pdev); - -	return 0; -} -  static struct platform_driver sdhci_bcm_kona_driver = {  	.driver		= {  		.name	= "sdhci-kona", @@ -365,7 +330,7 @@ static struct platform_driver sdhci_bcm_kona_driver = {  		.of_match_table = sdhci_bcm_kona_of_match,  	},  	.probe		= sdhci_bcm_kona_probe, -	.remove		= sdhci_bcm_kona_remove, +	.remove		= sdhci_pltfm_unregister,  };  module_platform_driver(sdhci_bcm_kona_driver); diff --git a/drivers/mmc/host/sdhci-bcm2835.c b/drivers/mmc/host/sdhci-bcm2835.c index 439d259fdf1d..0ef0343c603a 100644 --- a/drivers/mmc/host/sdhci-bcm2835.c +++ b/drivers/mmc/host/sdhci-bcm2835.c @@ -180,11 +180,6 @@ err:  	return ret;  } -static int bcm2835_sdhci_remove(struct platform_device *pdev) -{ -	return sdhci_pltfm_unregister(pdev); -} -  static const struct of_device_id bcm2835_sdhci_of_match[] = {  	{ .compatible = "brcm,bcm2835-sdhci" },  	{ } @@ -198,7 +193,7 @@ static struct platform_driver bcm2835_sdhci_driver = {  		.pm = SDHCI_PLTFM_PMOPS,  	},  	.probe = bcm2835_sdhci_probe, -	.remove = bcm2835_sdhci_remove, +	.remove = sdhci_pltfm_unregister,  };  module_platform_driver(bcm2835_sdhci_driver); diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c index a7935a8d0922..59f2923f8054 100644 --- a/drivers/mmc/host/sdhci-cns3xxx.c +++ b/drivers/mmc/host/sdhci-cns3xxx.c @@ -98,18 +98,13 @@ static int sdhci_cns3xxx_probe(struct platform_device *pdev)  	return sdhci_pltfm_register(pdev, &sdhci_cns3xxx_pdata, 0);  } -static int sdhci_cns3xxx_remove(struct platform_device *pdev) -{ -	return sdhci_pltfm_unregister(pdev); -} -  static struct platform_driver sdhci_cns3xxx_driver = {  	.driver		= {  		.name	= "sdhci-cns3xxx",  		.pm	= SDHCI_PLTFM_PMOPS,  	},  	.probe		= sdhci_cns3xxx_probe, -	.remove		= sdhci_cns3xxx_remove, +	.remove		= sdhci_pltfm_unregister,  };  module_platform_driver(sdhci_cns3xxx_driver); diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c index ca969d271a27..407c21f152b2 100644 --- a/drivers/mmc/host/sdhci-dove.c +++ b/drivers/mmc/host/sdhci-dove.c @@ -28,10 +28,6 @@  #include "sdhci-pltfm.h" -struct sdhci_dove_priv { -	struct clk *clk; -}; -  static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)  {  	u16 ret; @@ -84,27 +80,17 @@ static int sdhci_dove_probe(struct platform_device *pdev)  {  	struct sdhci_host *host;  	struct sdhci_pltfm_host *pltfm_host; -	struct sdhci_dove_priv *priv;  	int ret; -	priv = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_dove_priv), -			    GFP_KERNEL); -	if (!priv) { -		dev_err(&pdev->dev, "unable to allocate private data"); -		return -ENOMEM; -	} - -	priv->clk = devm_clk_get(&pdev->dev, NULL); -  	host = sdhci_pltfm_init(pdev, &sdhci_dove_pdata, 0);  	if (IS_ERR(host))  		return PTR_ERR(host);  	pltfm_host = sdhci_priv(host); -	pltfm_host->priv = priv; +	pltfm_host->clk = devm_clk_get(&pdev->dev, NULL); -	if (!IS_ERR(priv->clk)) -		clk_prepare_enable(priv->clk); +	if (!IS_ERR(pltfm_host->clk)) +		clk_prepare_enable(pltfm_host->clk);  	ret = mmc_of_parse(host->mmc);  	if (ret) @@ -117,26 +103,11 @@ static int sdhci_dove_probe(struct platform_device *pdev)  	return 0;  err_sdhci_add: -	if (!IS_ERR(priv->clk)) -		clk_disable_unprepare(priv->clk); +	clk_disable_unprepare(pltfm_host->clk);  	sdhci_pltfm_free(pdev);  	return ret;  } -static int sdhci_dove_remove(struct platform_device *pdev) -{ -	struct sdhci_host *host = platform_get_drvdata(pdev); -	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -	struct sdhci_dove_priv *priv = pltfm_host->priv; - -	sdhci_pltfm_unregister(pdev); - -	if (!IS_ERR(priv->clk)) -		clk_disable_unprepare(priv->clk); - -	return 0; -} -  static const struct of_device_id sdhci_dove_of_match_table[] = {  	{ .compatible = "marvell,dove-sdhci", },  	{} @@ -150,7 +121,7 @@ static struct platform_driver sdhci_dove_driver = {  		.of_match_table = sdhci_dove_of_match_table,  	},  	.probe		= sdhci_dove_probe, -	.remove		= sdhci_dove_remove, +	.remove		= sdhci_pltfm_unregister,  };  module_platform_driver(sdhci_dove_driver); diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 10ef8244a239..82f512d87cb8 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -416,7 +416,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)  			new_val |= ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;  		else  			new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON; -			writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); +		writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);  		return;  	case SDHCI_HOST_CONTROL2:  		new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); @@ -864,6 +864,7 @@ static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {  #ifdef CONFIG_OF  static int  sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, +			 struct sdhci_host *host,  			 struct esdhc_platform_data *boarddata)  {  	struct device_node *np = pdev->dev.of_node; @@ -900,11 +901,14 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,  	if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line))  		boarddata->delay_line = 0; +	mmc_of_parse_voltage(np, &host->ocr_mask); +  	return 0;  }  #else  static inline int  sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, +			 struct sdhci_host *host,  			 struct esdhc_platform_data *boarddata)  {  	return -ENODEV; @@ -999,7 +1003,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)  			host->ioaddr + ESDHC_TUNING_CTRL);  	boarddata = &imx_data->boarddata; -	if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) { +	if (sdhci_esdhc_imx_probe_dt(pdev, host, boarddata) < 0) {  		if (!host->mmc->parent->platform_data) {  			dev_err(mmc_dev(host->mmc), "no board data!\n");  			err = -EINVAL; @@ -1009,40 +1013,9 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)  					host->mmc->parent->platform_data);  	} -	/* write_protect */ -	if (boarddata->wp_type == ESDHC_WP_GPIO) { -		err = mmc_gpio_request_ro(host->mmc, boarddata->wp_gpio); -		if (err) { -			dev_err(mmc_dev(host->mmc), -				"failed to request write-protect gpio!\n"); -			goto disable_clk; -		} -		host->mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; -	} -  	/* card_detect */ -	switch (boarddata->cd_type) { -	case ESDHC_CD_GPIO: -		err = mmc_gpio_request_cd(host->mmc, boarddata->cd_gpio, 0); -		if (err) { -			dev_err(mmc_dev(host->mmc), -				"failed to request card-detect gpio!\n"); -			goto disable_clk; -		} -		/* fall through */ - -	case ESDHC_CD_CONTROLLER: -		/* we have a working card_detect back */ +	if (boarddata->cd_type == ESDHC_CD_CONTROLLER)  		host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; -		break; - -	case ESDHC_CD_PERMANENT: -		host->mmc->caps |= MMC_CAP_NONREMOVABLE; -		break; - -	case ESDHC_CD_NONE: -		break; -	}  	switch (boarddata->max_bus_width) {  	case 8: @@ -1075,6 +1048,11 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)  		host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;  	} +	/* call to generic mmc_of_parse to support additional capabilities */ +	err = mmc_of_parse(host->mmc); +	if (err) +		goto disable_clk; +  	err = sdhci_add_host(host);  	if (err)  		goto disable_clk; diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c new file mode 100644 index 000000000000..3b423b0ad8e7 --- /dev/null +++ b/drivers/mmc/host/sdhci-iproc.c @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2014 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +/* + * iProc SDHCI platform driver + */ + +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/mmc/host.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include "sdhci-pltfm.h" + +struct sdhci_iproc_data { +	const struct sdhci_pltfm_data *pdata; +	u32 caps; +	u32 caps1; +}; + +struct sdhci_iproc_host { +	const struct sdhci_iproc_data *data; +	u32 shadow_cmd; +	u32 shadow_blk; +}; + +#define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18) + +static inline u32 sdhci_iproc_readl(struct sdhci_host *host, int reg) +{ +	u32 val = readl(host->ioaddr + reg); + +	pr_debug("%s: readl [0x%02x] 0x%08x\n", +		 mmc_hostname(host->mmc), reg, val); +	return val; +} + +static u16 sdhci_iproc_readw(struct sdhci_host *host, int reg) +{ +	u32 val = sdhci_iproc_readl(host, (reg & ~3)); +	u16 word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff; +	return word; +} + +static u8 sdhci_iproc_readb(struct sdhci_host *host, int reg) +{ +	u32 val = sdhci_iproc_readl(host, (reg & ~3)); +	u8 byte = val >> REG_OFFSET_IN_BITS(reg) & 0xff; +	return byte; +} + +static inline void sdhci_iproc_writel(struct sdhci_host *host, u32 val, int reg) +{ +	pr_debug("%s: writel [0x%02x] 0x%08x\n", +		 mmc_hostname(host->mmc), reg, val); + +	writel(val, host->ioaddr + reg); + +	if (host->clock <= 400000) { +		/* Round up to micro-second four SD clock delay */ +		if (host->clock) +			udelay((4 * 1000000 + host->clock - 1) / host->clock); +		else +			udelay(10); +	} +} + +/* + * The Arasan has a bugette whereby it may lose the content of successive + * writes to the same register that are within two SD-card clock cycles of + * each other (a clock domain crossing problem). The data + * register does not have this problem, which is just as well - otherwise we'd + * have to nobble the DMA engine too. + * + * This wouldn't be a problem with the code except that we can only write the + * controller with 32-bit writes.  So two different 16-bit registers are + * written back to back creates the problem. + * + * In reality, this only happens when SDHCI_BLOCK_SIZE and SDHCI_BLOCK_COUNT + * are written followed by SDHCI_TRANSFER_MODE and SDHCI_COMMAND. + * The BLOCK_SIZE and BLOCK_COUNT are meaningless until a command issued so + * the work around can be further optimized. We can keep shadow values of + * BLOCK_SIZE, BLOCK_COUNT, and TRANSFER_MODE until a COMMAND is issued. + * Then, write the BLOCK_SIZE+BLOCK_COUNT in a single 32-bit write followed + * by the TRANSFER+COMMAND in another 32-bit write. + */ +static void sdhci_iproc_writew(struct sdhci_host *host, u16 val, int reg) +{ +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct sdhci_iproc_host *iproc_host = sdhci_pltfm_priv(pltfm_host); +	u32 word_shift = REG_OFFSET_IN_BITS(reg); +	u32 mask = 0xffff << word_shift; +	u32 oldval, newval; + +	if (reg == SDHCI_COMMAND) { +		/* Write the block now as we are issuing a command */ +		if (iproc_host->shadow_blk != 0) { +			sdhci_iproc_writel(host, iproc_host->shadow_blk, +				SDHCI_BLOCK_SIZE); +			iproc_host->shadow_blk = 0; +		} +		oldval = iproc_host->shadow_cmd; +	} else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) { +		/* Block size and count are stored in shadow reg */ +		oldval = iproc_host->shadow_blk; +	} else { +		/* Read reg, all other registers are not shadowed */ +		oldval = sdhci_iproc_readl(host, (reg & ~3)); +	} +	newval = (oldval & ~mask) | (val << word_shift); + +	if (reg == SDHCI_TRANSFER_MODE) { +		/* Save the transfer mode until the command is issued */ +		iproc_host->shadow_cmd = newval; +	} else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) { +		/* Save the block info until the command is issued */ +		iproc_host->shadow_blk = newval; +	} else { +		/* Command or other regular 32-bit write */ +		sdhci_iproc_writel(host, newval, reg & ~3); +	} +} + +static void sdhci_iproc_writeb(struct sdhci_host *host, u8 val, int reg) +{ +	u32 oldval = sdhci_iproc_readl(host, (reg & ~3)); +	u32 byte_shift = REG_OFFSET_IN_BITS(reg); +	u32 mask = 0xff << byte_shift; +	u32 newval = (oldval & ~mask) | (val << byte_shift); + +	sdhci_iproc_writel(host, newval, reg & ~3); +} + +static const struct sdhci_ops sdhci_iproc_ops = { +	.read_l = sdhci_iproc_readl, +	.read_w = sdhci_iproc_readw, +	.read_b = sdhci_iproc_readb, +	.write_l = sdhci_iproc_writel, +	.write_w = sdhci_iproc_writew, +	.write_b = sdhci_iproc_writeb, +	.set_clock = sdhci_set_clock, +	.get_max_clock = sdhci_pltfm_clk_get_max_clock, +	.set_bus_width = sdhci_set_bus_width, +	.reset = sdhci_reset, +	.set_uhs_signaling = sdhci_set_uhs_signaling, +}; + +static const struct sdhci_pltfm_data sdhci_iproc_pltfm_data = { +	.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK, +	.quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN, +	.ops = &sdhci_iproc_ops, +}; + +static const struct sdhci_iproc_data iproc_data = { +	.pdata = &sdhci_iproc_pltfm_data, +	.caps = 0x05E90000, +	.caps1 = 0x00000064, +}; + +static const struct of_device_id sdhci_iproc_of_match[] = { +	{ .compatible = "brcm,sdhci-iproc-cygnus", .data = &iproc_data }, +	{ } +}; +MODULE_DEVICE_TABLE(of, sdhci_iproc_of_match); + +static int sdhci_iproc_probe(struct platform_device *pdev) +{ +	const struct of_device_id *match; +	const struct sdhci_iproc_data *iproc_data; +	struct sdhci_host *host; +	struct sdhci_iproc_host *iproc_host; +	struct sdhci_pltfm_host *pltfm_host; +	int ret; + +	match = of_match_device(sdhci_iproc_of_match, &pdev->dev); +	if (!match) +		return -EINVAL; +	iproc_data = match->data; + +	host = sdhci_pltfm_init(pdev, iproc_data->pdata, sizeof(*iproc_host)); +	if (IS_ERR(host)) +		return PTR_ERR(host); + +	pltfm_host = sdhci_priv(host); +	iproc_host = sdhci_pltfm_priv(pltfm_host); + +	iproc_host->data = iproc_data; + +	mmc_of_parse(host->mmc); +	sdhci_get_of_property(pdev); + +	/* Enable EMMC 1/8V DDR capable */ +	host->mmc->caps |= MMC_CAP_1_8V_DDR; + +	pltfm_host->clk = devm_clk_get(&pdev->dev, NULL); +	if (IS_ERR(pltfm_host->clk)) { +		ret = PTR_ERR(pltfm_host->clk); +		goto err; +	} + +	if (iproc_host->data->pdata->quirks & SDHCI_QUIRK_MISSING_CAPS) { +		host->caps = iproc_host->data->caps; +		host->caps1 = iproc_host->data->caps1; +	} + +	return sdhci_add_host(host); + +err: +	sdhci_pltfm_free(pdev); +	return ret; +} + +static int sdhci_iproc_remove(struct platform_device *pdev) +{ +	return sdhci_pltfm_unregister(pdev); +} + +static struct platform_driver sdhci_iproc_driver = { +	.driver = { +		.name = "sdhci-iproc", +		.of_match_table = sdhci_iproc_of_match, +		.pm = SDHCI_PLTFM_PMOPS, +	}, +	.probe = sdhci_iproc_probe, +	.remove = sdhci_iproc_remove, +}; +module_platform_driver(sdhci_iproc_driver); + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("IPROC SDHCI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 3d32ce896b09..4a09f7608c66 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -22,6 +22,11 @@  #include "sdhci-pltfm.h" +#define CORE_MCI_VERSION		0x50 +#define CORE_VERSION_MAJOR_SHIFT	28 +#define CORE_VERSION_MAJOR_MASK		(0xf << CORE_VERSION_MAJOR_SHIFT) +#define CORE_VERSION_MINOR_MASK		0xff +  #define CORE_HC_MODE		0x78  #define HC_MODE_EN		0x1  #define CORE_POWER		0x0 @@ -41,6 +46,8 @@  #define CORE_VENDOR_SPEC	0x10c  #define CORE_CLK_PWRSAVE	BIT(1) +#define CORE_VENDOR_SPEC_CAPABILITIES0	0x11c +  #define CDR_SELEXT_SHIFT	20  #define CDR_SELEXT_MASK		(0xf << CDR_SELEXT_SHIFT)  #define CMUX_SHIFT_PHASE_SHIFT	24 @@ -426,7 +433,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)  	struct sdhci_msm_host *msm_host;  	struct resource *core_memres;  	int ret; -	u16 host_version; +	u16 host_version, core_minor; +	u32 core_version, caps; +	u8 core_major;  	msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL);  	if (!msm_host) @@ -516,6 +525,24 @@ static int sdhci_msm_probe(struct platform_device *pdev)  		host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>  			       SDHCI_VENDOR_VER_SHIFT)); +	core_version = readl_relaxed(msm_host->core_mem + CORE_MCI_VERSION); +	core_major = (core_version & CORE_VERSION_MAJOR_MASK) >> +		      CORE_VERSION_MAJOR_SHIFT; +	core_minor = core_version & CORE_VERSION_MINOR_MASK; +	dev_dbg(&pdev->dev, "MCI Version: 0x%08x, major: 0x%04x, minor: 0x%02x\n", +		core_version, core_major, core_minor); + +	/* +	 * Support for some capabilities is not advertised by newer +	 * controller versions and must be explicitly enabled. +	 */ +	if (core_major >= 1 && core_minor != 0x11 && core_minor != 0x12) { +		caps = readl_relaxed(host->ioaddr + SDHCI_CAPABILITIES); +		caps |= SDHCI_CAN_VDD_300 | SDHCI_CAN_DO_8BIT; +		writel_relaxed(caps, host->ioaddr + +			       CORE_VENDOR_SPEC_CAPABILITIES0); +	} +  	ret = sdhci_add_host(host);  	if (ret)  		goto clk_disable; diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index bcb51e9dfdcd..6287d426c96b 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -173,6 +173,12 @@ static int sdhci_arasan_probe(struct platform_device *pdev)  	pltfm_host->priv = sdhci_arasan;  	pltfm_host->clk = clk_xin; +	ret = mmc_of_parse(host->mmc); +	if (ret) { +		dev_err(&pdev->dev, "parsing dt failed (%u)\n", ret); +		goto clk_disable_all; +	} +  	ret = sdhci_add_host(host);  	if (ret)  		goto err_pltfm_free; @@ -195,7 +201,6 @@ static int sdhci_arasan_remove(struct platform_device *pdev)  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);  	struct sdhci_arasan_data *sdhci_arasan = pltfm_host->priv; -	clk_disable_unprepare(pltfm_host->clk);  	clk_disable_unprepare(sdhci_arasan->clk_ahb);  	return sdhci_pltfm_unregister(pdev); diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 17fe02ed6672..22e9111b11ff 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -386,11 +386,6 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)  	return ret;  } -static int sdhci_esdhc_remove(struct platform_device *pdev) -{ -	return sdhci_pltfm_unregister(pdev); -} -  static const struct of_device_id sdhci_esdhc_of_match[] = {  	{ .compatible = "fsl,mpc8379-esdhc" },  	{ .compatible = "fsl,mpc8536-esdhc" }, @@ -406,7 +401,7 @@ static struct platform_driver sdhci_esdhc_driver = {  		.pm = ESDHC_PMOPS,  	},  	.probe = sdhci_esdhc_probe, -	.remove = sdhci_esdhc_remove, +	.remove = sdhci_pltfm_unregister,  };  module_platform_driver(sdhci_esdhc_driver); diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c index be479279a1d5..4079a96ad37e 100644 --- a/drivers/mmc/host/sdhci-of-hlwd.c +++ b/drivers/mmc/host/sdhci-of-hlwd.c @@ -75,11 +75,6 @@ static int sdhci_hlwd_probe(struct platform_device *pdev)  	return sdhci_pltfm_register(pdev, &sdhci_hlwd_pdata, 0);  } -static int sdhci_hlwd_remove(struct platform_device *pdev) -{ -	return sdhci_pltfm_unregister(pdev); -} -  static const struct of_device_id sdhci_hlwd_of_match[] = {  	{ .compatible = "nintendo,hollywood-sdhci" },  	{ } @@ -93,7 +88,7 @@ static struct platform_driver sdhci_hlwd_driver = {  		.pm = SDHCI_PLTFM_PMOPS,  	},  	.probe = sdhci_hlwd_probe, -	.remove = sdhci_hlwd_remove, +	.remove = sdhci_pltfm_unregister,  };  module_platform_driver(sdhci_hlwd_driver); diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 29eaff78238e..7a3fc16d0a6c 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -650,6 +650,7 @@ static int rtsx_probe_slot(struct sdhci_pci_slot *slot)  static const struct sdhci_pci_fixes sdhci_rtsx = {  	.quirks2	= SDHCI_QUIRK2_PRESET_VALUE_BROKEN | +			SDHCI_QUIRK2_BROKEN_64_BIT_DMA |  			SDHCI_QUIRK2_BROKEN_DDR50,  	.probe_slot	= rtsx_probe_slot,  }; diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index c5b01d6bb85d..a207f5aaf62f 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -75,43 +75,41 @@ void sdhci_get_of_property(struct platform_device *pdev)  	u32 bus_width;  	int size; -	if (of_device_is_available(np)) { -		if (of_get_property(np, "sdhci,auto-cmd12", NULL)) -			host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; +	if (of_get_property(np, "sdhci,auto-cmd12", NULL)) +		host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12; -		if (of_get_property(np, "sdhci,1-bit-only", NULL) || -		    (of_property_read_u32(np, "bus-width", &bus_width) == 0 && -		    bus_width == 1)) -			host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; +	if (of_get_property(np, "sdhci,1-bit-only", NULL) || +	    (of_property_read_u32(np, "bus-width", &bus_width) == 0 && +	    bus_width == 1)) +		host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; -		if (sdhci_of_wp_inverted(np)) -			host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT; +	if (sdhci_of_wp_inverted(np)) +		host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT; -		if (of_get_property(np, "broken-cd", NULL)) -			host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; +	if (of_get_property(np, "broken-cd", NULL)) +		host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; -		if (of_get_property(np, "no-1-8-v", NULL)) -			host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; +	if (of_get_property(np, "no-1-8-v", NULL)) +		host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; -		if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc")) -			host->quirks |= SDHCI_QUIRK_BROKEN_DMA; +	if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc")) +		host->quirks |= SDHCI_QUIRK_BROKEN_DMA; -		if (of_device_is_compatible(np, "fsl,p2020-esdhc") || -		    of_device_is_compatible(np, "fsl,p1010-esdhc") || -		    of_device_is_compatible(np, "fsl,t4240-esdhc") || -		    of_device_is_compatible(np, "fsl,mpc8536-esdhc")) -			host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; +	if (of_device_is_compatible(np, "fsl,p2020-esdhc") || +	    of_device_is_compatible(np, "fsl,p1010-esdhc") || +	    of_device_is_compatible(np, "fsl,t4240-esdhc") || +	    of_device_is_compatible(np, "fsl,mpc8536-esdhc")) +		host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; -		clk = of_get_property(np, "clock-frequency", &size); -		if (clk && size == sizeof(*clk) && *clk) -			pltfm_host->clock = be32_to_cpup(clk); +	clk = of_get_property(np, "clock-frequency", &size); +	if (clk && size == sizeof(*clk) && *clk) +		pltfm_host->clock = be32_to_cpup(clk); -		if (of_find_property(np, "keep-power-in-suspend", NULL)) -			host->mmc->pm_caps |= MMC_PM_KEEP_POWER; +	if (of_find_property(np, "keep-power-in-suspend", NULL)) +		host->mmc->pm_caps |= MMC_PM_KEEP_POWER; -		if (of_find_property(np, "enable-sdio-wakeup", NULL)) -			host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; -	} +	if (of_find_property(np, "enable-sdio-wakeup", NULL)) +		host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;  }  #else  void sdhci_get_of_property(struct platform_device *pdev) {} @@ -225,9 +223,11 @@ EXPORT_SYMBOL_GPL(sdhci_pltfm_register);  int sdhci_pltfm_unregister(struct platform_device *pdev)  {  	struct sdhci_host *host = platform_get_drvdata(pdev); +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);  	int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);  	sdhci_remove_host(host, dead); +	clk_disable_unprepare(pltfm_host->clk);  	sdhci_pltfm_free(pdev);  	return 0; diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c index f6f82ec3618d..32848eb7ad80 100644 --- a/drivers/mmc/host/sdhci-sirf.c +++ b/drivers/mmc/host/sdhci-sirf.c @@ -20,17 +20,9 @@  #define SIRF_TUNING_COUNT 128  struct sdhci_sirf_priv { -	struct clk *clk;  	int gpio_cd;  }; -static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host) -{ -	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -	struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host); -	return clk_get_rate(priv->clk); -} -  static void sdhci_sirf_set_bus_width(struct sdhci_host *host, int width)  {  	u8 ctrl; @@ -56,7 +48,7 @@ static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode)  	int tuning_seq_cnt = 3;  	u8 phase, tuned_phases[SIRF_TUNING_COUNT];  	u8 tuned_phase_cnt = 0; -	int rc, longest_range = 0; +	int rc = 0, longest_range = 0;  	int start = -1, end = 0, tuning_value = -1, range = 0;  	u16 clock_setting;  	struct mmc_host *mmc = host->mmc; @@ -68,7 +60,7 @@ retry:  	phase = 0;  	do {  		sdhci_writel(host, -			clock_setting | phase | (phase << 7) | (phase << 16), +			clock_setting | phase,  			SDHCI_CLK_DELAY_SETTING);  		if (!mmc_send_tuning(mmc)) { @@ -102,7 +94,7 @@ retry:  		 */  		phase = tuning_value;  		sdhci_writel(host, -			clock_setting | phase | (phase << 7) | (phase << 16), +			clock_setting | phase,  			SDHCI_CLK_DELAY_SETTING);  		dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n", @@ -122,7 +114,7 @@ retry:  static struct sdhci_ops sdhci_sirf_ops = {  	.platform_execute_tuning = sdhci_sirf_execute_tuning,  	.set_clock = sdhci_set_clock, -	.get_max_clock	= sdhci_sirf_get_max_clk, +	.get_max_clock	= sdhci_pltfm_clk_get_max_clock,  	.set_bus_width = sdhci_sirf_set_bus_width,  	.reset = sdhci_reset,  	.set_uhs_signaling = sdhci_set_uhs_signaling, @@ -162,13 +154,13 @@ static int sdhci_sirf_probe(struct platform_device *pdev)  		return PTR_ERR(host);  	pltfm_host = sdhci_priv(host); +	pltfm_host->clk = clk;  	priv = sdhci_pltfm_priv(pltfm_host); -	priv->clk = clk;  	priv->gpio_cd = gpio_cd;  	sdhci_get_of_property(pdev); -	ret = clk_prepare_enable(priv->clk); +	ret = clk_prepare_enable(pltfm_host->clk);  	if (ret)  		goto err_clk_prepare; @@ -195,37 +187,24 @@ static int sdhci_sirf_probe(struct platform_device *pdev)  err_request_cd:  	sdhci_remove_host(host, 0);  err_sdhci_add: -	clk_disable_unprepare(priv->clk); +	clk_disable_unprepare(pltfm_host->clk);  err_clk_prepare:  	sdhci_pltfm_free(pdev);  	return ret;  } -static int sdhci_sirf_remove(struct platform_device *pdev) -{ -	struct sdhci_host *host = platform_get_drvdata(pdev); -	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -	struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host); - -	sdhci_pltfm_unregister(pdev); - -	clk_disable_unprepare(priv->clk); -	return 0; -} -  #ifdef CONFIG_PM_SLEEP  static int sdhci_sirf_suspend(struct device *dev)  {  	struct sdhci_host *host = dev_get_drvdata(dev);  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -	struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);  	int ret;  	ret = sdhci_suspend_host(host);  	if (ret)  		return ret; -	clk_disable(priv->clk); +	clk_disable(pltfm_host->clk);  	return 0;  } @@ -234,10 +213,9 @@ static int sdhci_sirf_resume(struct device *dev)  {  	struct sdhci_host *host = dev_get_drvdata(dev);  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -	struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);  	int ret; -	ret = clk_enable(priv->clk); +	ret = clk_enable(pltfm_host->clk);  	if (ret) {  		dev_dbg(dev, "Resume: Error enabling clock\n");  		return ret; @@ -264,7 +242,7 @@ static struct platform_driver sdhci_sirf_driver = {  #endif  	},  	.probe		= sdhci_sirf_probe, -	.remove		= sdhci_sirf_remove, +	.remove		= sdhci_pltfm_unregister,  };  module_platform_driver(sdhci_sirf_driver); diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index 22e58268545f..df088343d60f 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -26,14 +26,13 @@  #include <linux/pm.h>  #include <linux/slab.h>  #include <linux/mmc/host.h> -#include <linux/mmc/sdhci-spear.h>  #include <linux/mmc/slot-gpio.h>  #include <linux/io.h>  #include "sdhci.h"  struct spear_sdhci {  	struct clk *clk; -	struct sdhci_plat_data *data; +	int card_int_gpio;  };  /* sdhci ops */ @@ -44,38 +43,20 @@ static const struct sdhci_ops sdhci_pltfm_ops = {  	.set_uhs_signaling = sdhci_set_uhs_signaling,  }; -#ifdef CONFIG_OF -static struct sdhci_plat_data *sdhci_probe_config_dt(struct platform_device *pdev) +static void sdhci_probe_config_dt(struct device_node *np, +				struct spear_sdhci *host)  { -	struct device_node *np = pdev->dev.of_node; -	struct sdhci_plat_data *pdata = NULL;  	int cd_gpio;  	cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);  	if (!gpio_is_valid(cd_gpio))  		cd_gpio = -1; -	/* If pdata is required */ -	if (cd_gpio != -1) { -		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); -		if (!pdata) -			dev_err(&pdev->dev, "DT: kzalloc failed\n"); -		else -			pdata->card_int_gpio = cd_gpio; -	} - -	return pdata; -} -#else -static struct sdhci_plat_data *sdhci_probe_config_dt(struct platform_device *pdev) -{ -	return ERR_PTR(-ENOSYS); +	host->card_int_gpio = cd_gpio;  } -#endif  static int sdhci_probe(struct platform_device *pdev)  { -	struct device_node *np = pdev->dev.of_node;  	struct sdhci_host *host;  	struct resource *iomem;  	struct spear_sdhci *sdhci; @@ -124,28 +105,18 @@ static int sdhci_probe(struct platform_device *pdev)  		dev_dbg(&pdev->dev, "Error setting desired clk, clk=%lu\n",  				clk_get_rate(sdhci->clk)); -	if (np) { -		sdhci->data = sdhci_probe_config_dt(pdev); -		if (IS_ERR(sdhci->data)) { -			dev_err(&pdev->dev, "DT: Failed to get pdata\n"); -			goto disable_clk; -		} -	} else { -		sdhci->data = dev_get_platdata(&pdev->dev); -	} - +	sdhci_probe_config_dt(pdev->dev.of_node, sdhci);  	/*  	 * It is optional to use GPIOs for sdhci card detection. If -	 * sdhci->data is NULL, then use original sdhci lines otherwise +	 * sdhci->card_int_gpio < 0, then use original sdhci lines otherwise  	 * GPIO lines. We use the built-in GPIO support for this.  	 */ -	if (sdhci->data && sdhci->data->card_int_gpio >= 0) { -		ret = mmc_gpio_request_cd(host->mmc, -					  sdhci->data->card_int_gpio, 0); +	if (sdhci->card_int_gpio >= 0) { +		ret = mmc_gpio_request_cd(host->mmc, sdhci->card_int_gpio, 0);  		if (ret < 0) {  			dev_dbg(&pdev->dev,  				"failed to request card-detect gpio%d\n", -				sdhci->data->card_int_gpio); +				sdhci->card_int_gpio);  			goto disable_clk;  		}  	} diff --git a/drivers/mmc/host/sdhci-st.c b/drivers/mmc/host/sdhci-st.c index 882b07e9667e..682f2bb0f4bf 100644 --- a/drivers/mmc/host/sdhci-st.c +++ b/drivers/mmc/host/sdhci-st.c @@ -23,9 +23,295 @@  #include <linux/module.h>  #include <linux/err.h>  #include <linux/mmc/host.h> - +#include <linux/reset.h>  #include "sdhci-pltfm.h" +struct st_mmc_platform_data { +	struct  reset_control *rstc; +	void __iomem *top_ioaddr; +}; + +/* MMCSS glue logic to setup the HC on some ST SoCs (e.g. STiH407 family) */ + +#define ST_MMC_CCONFIG_REG_1		0x400 +#define ST_MMC_CCONFIG_TIMEOUT_CLK_UNIT	BIT(24) +#define ST_MMC_CCONFIG_TIMEOUT_CLK_FREQ	BIT(12) +#define ST_MMC_CCONFIG_TUNING_COUNT_DEFAULT	BIT(8) +#define ST_MMC_CCONFIG_ASYNC_WAKEUP	BIT(0) +#define ST_MMC_CCONFIG_1_DEFAULT	\ +				((ST_MMC_CCONFIG_TIMEOUT_CLK_UNIT) | \ +				 (ST_MMC_CCONFIG_TIMEOUT_CLK_FREQ) | \ +				 (ST_MMC_CCONFIG_TUNING_COUNT_DEFAULT)) + +#define ST_MMC_CCONFIG_REG_2		0x404 +#define ST_MMC_CCONFIG_HIGH_SPEED	BIT(28) +#define ST_MMC_CCONFIG_ADMA2		BIT(24) +#define ST_MMC_CCONFIG_8BIT		BIT(20) +#define ST_MMC_CCONFIG_MAX_BLK_LEN	16 +#define  MAX_BLK_LEN_1024		1 +#define  MAX_BLK_LEN_2048		2 +#define BASE_CLK_FREQ_200		0xc8 +#define BASE_CLK_FREQ_100		0x64 +#define BASE_CLK_FREQ_50		0x32 +#define ST_MMC_CCONFIG_2_DEFAULT \ +	(ST_MMC_CCONFIG_HIGH_SPEED | ST_MMC_CCONFIG_ADMA2 | \ +	 ST_MMC_CCONFIG_8BIT | \ +	 (MAX_BLK_LEN_1024 << ST_MMC_CCONFIG_MAX_BLK_LEN)) + +#define ST_MMC_CCONFIG_REG_3			0x408 +#define ST_MMC_CCONFIG_EMMC_SLOT_TYPE		BIT(28) +#define ST_MMC_CCONFIG_64BIT			BIT(24) +#define ST_MMC_CCONFIG_ASYNCH_INTR_SUPPORT	BIT(20) +#define ST_MMC_CCONFIG_1P8_VOLT			BIT(16) +#define ST_MMC_CCONFIG_3P0_VOLT			BIT(12) +#define ST_MMC_CCONFIG_3P3_VOLT			BIT(8) +#define ST_MMC_CCONFIG_SUSP_RES_SUPPORT		BIT(4) +#define ST_MMC_CCONFIG_SDMA			BIT(0) +#define ST_MMC_CCONFIG_3_DEFAULT	\ +			 (ST_MMC_CCONFIG_ASYNCH_INTR_SUPPORT	| \ +			  ST_MMC_CCONFIG_3P3_VOLT		| \ +			  ST_MMC_CCONFIG_SUSP_RES_SUPPORT	| \ +			  ST_MMC_CCONFIG_SDMA) + +#define ST_MMC_CCONFIG_REG_4	0x40c +#define ST_MMC_CCONFIG_D_DRIVER	BIT(20) +#define ST_MMC_CCONFIG_C_DRIVER	BIT(16) +#define ST_MMC_CCONFIG_A_DRIVER	BIT(12) +#define ST_MMC_CCONFIG_DDR50	BIT(8) +#define ST_MMC_CCONFIG_SDR104	BIT(4) +#define ST_MMC_CCONFIG_SDR50	BIT(0) +#define ST_MMC_CCONFIG_4_DEFAULT	0 + +#define ST_MMC_CCONFIG_REG_5		0x410 +#define ST_MMC_CCONFIG_TUNING_FOR_SDR50	BIT(8) +#define RETUNING_TIMER_CNT_MAX		0xf +#define ST_MMC_CCONFIG_5_DEFAULT	0 + +/* I/O configuration for Arasan IP */ +#define ST_MMC_GP_OUTPUT	0x450 +#define ST_MMC_GP_OUTPUT_CD	BIT(12) + +#define ST_MMC_STATUS_R		0x460 + +#define ST_TOP_MMC_DLY_FIX_OFF(x)	(x - 0x8) + +/* TOP config registers to manage static and dynamic delay */ +#define ST_TOP_MMC_TX_CLK_DLY			ST_TOP_MMC_DLY_FIX_OFF(0x8) +#define ST_TOP_MMC_RX_CLK_DLY			ST_TOP_MMC_DLY_FIX_OFF(0xc) +/* MMC delay control register */ +#define ST_TOP_MMC_DLY_CTRL			ST_TOP_MMC_DLY_FIX_OFF(0x18) +#define ST_TOP_MMC_DLY_CTRL_DLL_BYPASS_CMD	BIT(0) +#define ST_TOP_MMC_DLY_CTRL_DLL_BYPASS_PH_SEL	BIT(1) +#define ST_TOP_MMC_DLY_CTRL_TX_DLL_ENABLE	BIT(8) +#define ST_TOP_MMC_DLY_CTRL_RX_DLL_ENABLE	BIT(9) +#define ST_TOP_MMC_DLY_CTRL_ATUNE_NOT_CFG_DLY	BIT(10) +#define ST_TOP_MMC_START_DLL_LOCK		BIT(11) + +/* register to provide the phase-shift value for DLL */ +#define ST_TOP_MMC_TX_DLL_STEP_DLY		ST_TOP_MMC_DLY_FIX_OFF(0x1c) +#define ST_TOP_MMC_RX_DLL_STEP_DLY		ST_TOP_MMC_DLY_FIX_OFF(0x20) +#define ST_TOP_MMC_RX_CMD_STEP_DLY		ST_TOP_MMC_DLY_FIX_OFF(0x24) + +/* phase shift delay on the tx clk 2.188ns */ +#define ST_TOP_MMC_TX_DLL_STEP_DLY_VALID	0x6 + +#define ST_TOP_MMC_DLY_MAX			0xf + +#define ST_TOP_MMC_DYN_DLY_CONF	\ +		(ST_TOP_MMC_DLY_CTRL_TX_DLL_ENABLE | \ +		 ST_TOP_MMC_DLY_CTRL_ATUNE_NOT_CFG_DLY | \ +		 ST_TOP_MMC_START_DLL_LOCK) + +/* + * For clock speeds greater than 90MHz, we need to check that the + * DLL procedure has finished before switching to ultra-speed modes. + */ +#define	CLK_TO_CHECK_DLL_LOCK	90000000 + +static inline void st_mmcss_set_static_delay(void __iomem *ioaddr) +{ +	if (!ioaddr) +		return; + +	writel_relaxed(0x0, ioaddr + ST_TOP_MMC_DLY_CTRL); +	writel_relaxed(ST_TOP_MMC_DLY_MAX, +			ioaddr + ST_TOP_MMC_TX_CLK_DLY); +} + +/** + * st_mmcss_cconfig: configure the Arasan HC inside the flashSS. + * @np: dt device node. + * @host: sdhci host + * Description: this function is to configure the Arasan host controller. + * On some ST SoCs, i.e. STiH407 family, the MMC devices inside a dedicated + * flashSS sub-system which needs to be configured to be compliant to eMMC 4.5 + * or eMMC4.3.  This has to be done before registering the sdhci host. + */ +static void st_mmcss_cconfig(struct device_node *np, struct sdhci_host *host) +{ +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct mmc_host *mhost = host->mmc; +	u32 cconf2, cconf3, cconf4, cconf5; + +	if (!of_device_is_compatible(np, "st,sdhci-stih407")) +		return; + +	cconf2 = ST_MMC_CCONFIG_2_DEFAULT; +	cconf3 = ST_MMC_CCONFIG_3_DEFAULT; +	cconf4 = ST_MMC_CCONFIG_4_DEFAULT; +	cconf5 = ST_MMC_CCONFIG_5_DEFAULT; + +	writel_relaxed(ST_MMC_CCONFIG_1_DEFAULT, +			host->ioaddr + ST_MMC_CCONFIG_REG_1); + +	/* Set clock frequency, default to 50MHz if max-frequency is not +	 * provided */ + +	switch (mhost->f_max) { +	case 200000000: +		clk_set_rate(pltfm_host->clk, mhost->f_max); +		cconf2 |= BASE_CLK_FREQ_200; +		break; +	case 100000000: +		clk_set_rate(pltfm_host->clk, mhost->f_max); +		cconf2 |= BASE_CLK_FREQ_100; +		break; +	default: +		clk_set_rate(pltfm_host->clk, 50000000); +		cconf2 |= BASE_CLK_FREQ_50; +	} + +	writel_relaxed(cconf2, host->ioaddr + ST_MMC_CCONFIG_REG_2); + +	if (mhost->caps & MMC_CAP_NONREMOVABLE) +		cconf3 |= ST_MMC_CCONFIG_EMMC_SLOT_TYPE; +	else +		/* CARD _D ET_CTRL */ +		writel_relaxed(ST_MMC_GP_OUTPUT_CD, +				host->ioaddr + ST_MMC_GP_OUTPUT); + +	if (mhost->caps & MMC_CAP_UHS_SDR50) { +		/* use 1.8V */ +		cconf3 |= ST_MMC_CCONFIG_1P8_VOLT; +		cconf4 |= ST_MMC_CCONFIG_SDR50; +		/* Use tuning */ +		cconf5 |= ST_MMC_CCONFIG_TUNING_FOR_SDR50; +		/* Max timeout for retuning */ +		cconf5 |= RETUNING_TIMER_CNT_MAX; +	} + +	if (mhost->caps & MMC_CAP_UHS_SDR104) { +		/* +		 * SDR104 implies the HC can support HS200 mode, so +		 * it's mandatory to use 1.8V +		 */ +		cconf3 |= ST_MMC_CCONFIG_1P8_VOLT; +		cconf4 |= ST_MMC_CCONFIG_SDR104; +		/* Max timeout for retuning */ +		cconf5 |= RETUNING_TIMER_CNT_MAX; +	} + +	if (mhost->caps & MMC_CAP_UHS_DDR50) +		cconf4 |= ST_MMC_CCONFIG_DDR50; + +	writel_relaxed(cconf3, host->ioaddr + ST_MMC_CCONFIG_REG_3); +	writel_relaxed(cconf4, host->ioaddr + ST_MMC_CCONFIG_REG_4); +	writel_relaxed(cconf5, host->ioaddr + ST_MMC_CCONFIG_REG_5); +} + +static inline void st_mmcss_set_dll(void __iomem *ioaddr) +{ +	if (!ioaddr) +		return; + +	writel_relaxed(ST_TOP_MMC_DYN_DLY_CONF,	ioaddr + ST_TOP_MMC_DLY_CTRL); +	writel_relaxed(ST_TOP_MMC_TX_DLL_STEP_DLY_VALID, +			ioaddr + ST_TOP_MMC_TX_DLL_STEP_DLY); +} + +static int st_mmcss_lock_dll(void __iomem *ioaddr) +{ +	unsigned long curr, value; +	unsigned long finish = jiffies + HZ; + +	/* Checks if the DLL procedure is finished */ +	do { +		curr = jiffies; +		value = readl(ioaddr + ST_MMC_STATUS_R); +		if (value & 0x1) +			return 0; + +		cpu_relax(); +	} while (!time_after_eq(curr, finish)); + +	return -EBUSY; +} + +static int sdhci_st_set_dll_for_clock(struct sdhci_host *host) +{ +	int ret = 0; +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct st_mmc_platform_data *pdata = pltfm_host->priv; + +	if (host->clock > CLK_TO_CHECK_DLL_LOCK) { +		st_mmcss_set_dll(pdata->top_ioaddr); +		ret = st_mmcss_lock_dll(host->ioaddr); +	} + +	return ret; +} + +static void sdhci_st_set_uhs_signaling(struct sdhci_host *host, +					unsigned int uhs) +{ +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct st_mmc_platform_data *pdata = pltfm_host->priv; +	u16 ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); +	int ret = 0; + +	/* Select Bus Speed Mode for host */ +	ctrl_2 &= ~SDHCI_CTRL_UHS_MASK; +	switch (uhs) { +	/* +	 * Set V18_EN -- UHS modes do not work without this. +	 * does not change signaling voltage +	 */ + +	case MMC_TIMING_UHS_SDR12: +		st_mmcss_set_static_delay(pdata->top_ioaddr); +		ctrl_2 |= SDHCI_CTRL_UHS_SDR12 | SDHCI_CTRL_VDD_180; +		break; +	case MMC_TIMING_UHS_SDR25: +		st_mmcss_set_static_delay(pdata->top_ioaddr); +		ctrl_2 |= SDHCI_CTRL_UHS_SDR25 | SDHCI_CTRL_VDD_180; +		break; +	case MMC_TIMING_UHS_SDR50: +		st_mmcss_set_static_delay(pdata->top_ioaddr); +		ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180; +		ret = sdhci_st_set_dll_for_clock(host); +		break; +	case MMC_TIMING_UHS_SDR104: +	case MMC_TIMING_MMC_HS200: +		st_mmcss_set_static_delay(pdata->top_ioaddr); +		ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180; +		ret =  sdhci_st_set_dll_for_clock(host); +		break; +	case MMC_TIMING_UHS_DDR50: +	case MMC_TIMING_MMC_DDR52: +		st_mmcss_set_static_delay(pdata->top_ioaddr); +		ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180; +		break; +	} + +	if (ret) +		dev_warn(mmc_dev(host->mmc), "Error setting dll for clock " +						"(uhs %d)\n", uhs); + +	dev_dbg(mmc_dev(host->mmc), "uhs %d, ctrl_2 %04X\n", uhs, ctrl_2); + +	sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2); +} +  static u32 sdhci_st_readl(struct sdhci_host *host, int reg)  {  	u32 ret; @@ -48,22 +334,33 @@ static const struct sdhci_ops sdhci_st_ops = {  	.set_bus_width = sdhci_set_bus_width,  	.read_l = sdhci_st_readl,  	.reset = sdhci_reset, +	.set_uhs_signaling = sdhci_st_set_uhs_signaling,  };  static const struct sdhci_pltfm_data sdhci_st_pdata = {  	.ops = &sdhci_st_ops,  	.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | -	    SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, +		SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | +		SDHCI_QUIRK_NO_HISPD_BIT, +	.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | +		SDHCI_QUIRK2_STOP_WITH_TC,  };  static int sdhci_st_probe(struct platform_device *pdev)  { +	struct device_node *np = pdev->dev.of_node;  	struct sdhci_host *host; +	struct st_mmc_platform_data *pdata;  	struct sdhci_pltfm_host *pltfm_host;  	struct clk *clk;  	int ret = 0;  	u16 host_version; +	struct resource *res; + +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); +	if (!pdata) +		return -ENOMEM;  	clk =  devm_clk_get(&pdev->dev, "mmc");  	if (IS_ERR(clk)) { @@ -71,10 +368,17 @@ static int sdhci_st_probe(struct platform_device *pdev)  		return PTR_ERR(clk);  	} +	pdata->rstc = devm_reset_control_get(&pdev->dev, NULL); +	if (IS_ERR(pdata->rstc)) +		pdata->rstc = NULL; +	else +		reset_control_deassert(pdata->rstc); +  	host = sdhci_pltfm_init(pdev, &sdhci_st_pdata, 0);  	if (IS_ERR(host)) {  		dev_err(&pdev->dev, "Failed sdhci_pltfm_init\n"); -		return PTR_ERR(host); +		ret = PTR_ERR(host); +		goto err_pltfm_init;  	}  	ret = mmc_of_parse(host->mmc); @@ -85,9 +389,22 @@ static int sdhci_st_probe(struct platform_device *pdev)  	clk_prepare_enable(clk); +	/* Configure the FlashSS Top registers for setting eMMC TX/RX delay */ +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, +					   "top-mmc-delay"); +	pdata->top_ioaddr = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(pdata->top_ioaddr)) { +		dev_warn(&pdev->dev, "FlashSS Top Dly registers not available"); +		pdata->top_ioaddr = NULL; +	} +  	pltfm_host = sdhci_priv(host); +	pltfm_host->priv = pdata;  	pltfm_host->clk = clk; +	/* Configure the Arasan HC inside the flashSS */ +	st_mmcss_cconfig(np, host); +  	ret = sdhci_add_host(host);  	if (ret) {  		dev_err(&pdev->dev, "Failed sdhci_add_host\n"); @@ -109,6 +426,9 @@ err_out:  	clk_disable_unprepare(clk);  err_of:  	sdhci_pltfm_free(pdev); +err_pltfm_init: +	if (pdata->rstc) +		reset_control_assert(pdata->rstc);  	return ret;  } @@ -117,10 +437,15 @@ static int sdhci_st_remove(struct platform_device *pdev)  {  	struct sdhci_host *host = platform_get_drvdata(pdev);  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct st_mmc_platform_data *pdata = pltfm_host->priv; +	int ret; -	clk_disable_unprepare(pltfm_host->clk); +	ret = sdhci_pltfm_unregister(pdev); + +	if (pdata->rstc) +		reset_control_assert(pdata->rstc); -	return sdhci_pltfm_unregister(pdev); +	return ret;  }  #ifdef CONFIG_PM_SLEEP @@ -128,11 +453,15 @@ static int sdhci_st_suspend(struct device *dev)  {  	struct sdhci_host *host = dev_get_drvdata(dev);  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct st_mmc_platform_data *pdata = pltfm_host->priv;  	int ret = sdhci_suspend_host(host);  	if (ret)  		goto out; +	if (pdata->rstc) +		reset_control_assert(pdata->rstc); +  	clk_disable_unprepare(pltfm_host->clk);  out:  	return ret; @@ -142,9 +471,16 @@ static int sdhci_st_resume(struct device *dev)  {  	struct sdhci_host *host = dev_get_drvdata(dev);  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); +	struct st_mmc_platform_data *pdata = pltfm_host->priv; +	struct device_node *np = dev->of_node;  	clk_prepare_enable(pltfm_host->clk); +	if (pdata->rstc) +		reset_control_deassert(pdata->rstc); + +	st_mmcss_cconfig(np, host); +  	return sdhci_resume_host(host);  }  #endif diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index f3778d58d1cd..ad28b49f0203 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -20,11 +20,10 @@  #include <linux/io.h>  #include <linux/of.h>  #include <linux/of_device.h> -#include <linux/of_gpio.h> -#include <linux/gpio.h>  #include <linux/mmc/card.h>  #include <linux/mmc/host.h>  #include <linux/mmc/slot-gpio.h> +#include <linux/gpio/consumer.h>  #include "sdhci-pltfm.h" @@ -41,7 +40,6 @@  #define NVQUIRK_DISABLE_SDR50		BIT(3)  #define NVQUIRK_DISABLE_SDR104		BIT(4)  #define NVQUIRK_DISABLE_DDR50		BIT(5) -#define NVQUIRK_SHADOW_XFER_MODE_REG	BIT(6)  struct sdhci_tegra_soc_data {  	const struct sdhci_pltfm_data *pdata; @@ -50,7 +48,7 @@ struct sdhci_tegra_soc_data {  struct sdhci_tegra {  	const struct sdhci_tegra_soc_data *soc_data; -	int power_gpio; +	struct gpio_desc *power_gpio;  };  static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) @@ -71,23 +69,19 @@ static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)  static void tegra_sdhci_writew(struct sdhci_host *host, u16 val, int reg)  {  	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -	struct sdhci_tegra *tegra_host = pltfm_host->priv; -	const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; -	if (soc_data->nvquirks & NVQUIRK_SHADOW_XFER_MODE_REG) { -		switch (reg) { -		case SDHCI_TRANSFER_MODE: -			/* -			 * Postpone this write, we must do it together with a -			 * command write that is down below. -			 */ -			pltfm_host->xfer_mode_shadow = val; -			return; -		case SDHCI_COMMAND: -			writel((val << 16) | pltfm_host->xfer_mode_shadow, -				host->ioaddr + SDHCI_TRANSFER_MODE); -			return; -		} +	switch (reg) { +	case SDHCI_TRANSFER_MODE: +		/* +		 * Postpone this write, we must do it together with a +		 * command write that is down below. +		 */ +		pltfm_host->xfer_mode_shadow = val; +		return; +	case SDHCI_COMMAND: +		writel((val << 16) | pltfm_host->xfer_mode_shadow, +			host->ioaddr + SDHCI_TRANSFER_MODE); +		return;  	}  	writew(val, host->ioaddr + reg); @@ -173,7 +167,6 @@ static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width)  static const struct sdhci_ops tegra_sdhci_ops = {  	.get_ro     = tegra_sdhci_get_ro,  	.read_w     = tegra_sdhci_readw, -	.write_w    = tegra_sdhci_writew,  	.write_l    = tegra_sdhci_writel,  	.set_clock  = sdhci_set_clock,  	.set_bus_width = tegra_sdhci_set_bus_width, @@ -214,6 +207,18 @@ static struct sdhci_tegra_soc_data soc_data_tegra30 = {  		    NVQUIRK_DISABLE_SDR104,  }; +static const struct sdhci_ops tegra114_sdhci_ops = { +	.get_ro     = tegra_sdhci_get_ro, +	.read_w     = tegra_sdhci_readw, +	.write_w    = tegra_sdhci_writew, +	.write_l    = tegra_sdhci_writel, +	.set_clock  = sdhci_set_clock, +	.set_bus_width = tegra_sdhci_set_bus_width, +	.reset      = tegra_sdhci_reset, +	.set_uhs_signaling = sdhci_set_uhs_signaling, +	.get_max_clock = sdhci_pltfm_clk_get_max_clock, +}; +  static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {  	.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |  		  SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | @@ -221,15 +226,14 @@ static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {  		  SDHCI_QUIRK_NO_HISPD_BIT |  		  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |  		  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, -	.ops  = &tegra_sdhci_ops, +	.ops  = &tegra114_sdhci_ops,  };  static struct sdhci_tegra_soc_data soc_data_tegra114 = {  	.pdata = &sdhci_tegra114_pdata,  	.nvquirks = NVQUIRK_DISABLE_SDR50 |  		    NVQUIRK_DISABLE_DDR50 | -		    NVQUIRK_DISABLE_SDR104 | -		    NVQUIRK_SHADOW_XFER_MODE_REG, +		    NVQUIRK_DISABLE_SDR104,  };  static const struct of_device_id sdhci_tegra_dt_match[] = { @@ -241,17 +245,6 @@ static const struct of_device_id sdhci_tegra_dt_match[] = {  };  MODULE_DEVICE_TABLE(of, sdhci_tegra_dt_match); -static int sdhci_tegra_parse_dt(struct device *dev) -{ -	struct device_node *np = dev->of_node; -	struct sdhci_host *host = dev_get_drvdata(dev); -	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -	struct sdhci_tegra *tegra_host = pltfm_host->priv; - -	tegra_host->power_gpio = of_get_named_gpio(np, "power-gpios", 0); -	return mmc_of_parse(host->mmc); -} -  static int sdhci_tegra_probe(struct platform_device *pdev)  {  	const struct of_device_id *match; @@ -281,21 +274,18 @@ static int sdhci_tegra_probe(struct platform_device *pdev)  	tegra_host->soc_data = soc_data;  	pltfm_host->priv = tegra_host; -	rc = sdhci_tegra_parse_dt(&pdev->dev); +	rc = mmc_of_parse(host->mmc);  	if (rc)  		goto err_parse_dt; -	if (gpio_is_valid(tegra_host->power_gpio)) { -		rc = gpio_request(tegra_host->power_gpio, "sdhci_power"); -		if (rc) { -			dev_err(mmc_dev(host->mmc), -				"failed to allocate power gpio\n"); -			goto err_power_req; -		} -		gpio_direction_output(tegra_host->power_gpio, 1); +	tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power", +							 GPIOD_OUT_HIGH); +	if (IS_ERR(tegra_host->power_gpio)) { +		rc = PTR_ERR(tegra_host->power_gpio); +		goto err_power_req;  	} -	clk = clk_get(mmc_dev(host->mmc), NULL); +	clk = devm_clk_get(mmc_dev(host->mmc), NULL);  	if (IS_ERR(clk)) {  		dev_err(mmc_dev(host->mmc), "clk err\n");  		rc = PTR_ERR(clk); @@ -312,10 +302,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev)  err_add_host:  	clk_disable_unprepare(pltfm_host->clk); -	clk_put(pltfm_host->clk);  err_clk_get: -	if (gpio_is_valid(tegra_host->power_gpio)) -		gpio_free(tegra_host->power_gpio);  err_power_req:  err_parse_dt:  err_alloc_tegra_host: @@ -323,26 +310,6 @@ err_alloc_tegra_host:  	return rc;  } -static int sdhci_tegra_remove(struct platform_device *pdev) -{ -	struct sdhci_host *host = platform_get_drvdata(pdev); -	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); -	struct sdhci_tegra *tegra_host = pltfm_host->priv; -	int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); - -	sdhci_remove_host(host, dead); - -	if (gpio_is_valid(tegra_host->power_gpio)) -		gpio_free(tegra_host->power_gpio); - -	clk_disable_unprepare(pltfm_host->clk); -	clk_put(pltfm_host->clk); - -	sdhci_pltfm_free(pdev); - -	return 0; -} -  static struct platform_driver sdhci_tegra_driver = {  	.driver		= {  		.name	= "sdhci-tegra", @@ -350,7 +317,7 @@ static struct platform_driver sdhci_tegra_driver = {  		.pm	= SDHCI_PLTFM_PMOPS,  	},  	.probe		= sdhci_tegra_probe, -	.remove		= sdhci_tegra_remove, +	.remove		= sdhci_pltfm_unregister,  };  module_platform_driver(sdhci_tegra_driver); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 0ad412a4876f..c80287a02735 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -28,6 +28,7 @@  #include <linux/mmc/mmc.h>  #include <linux/mmc/host.h>  #include <linux/mmc/card.h> +#include <linux/mmc/sdio.h>  #include <linux/mmc/slot-gpio.h>  #include "sdhci.h" @@ -56,6 +57,7 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);  static int sdhci_pre_dma_transfer(struct sdhci_host *host,  					struct mmc_data *data,  					struct sdhci_host_next *next); +static int sdhci_do_get_cd(struct sdhci_host *host);  #ifdef CONFIG_PM  static int sdhci_runtime_pm_get(struct sdhci_host *host); @@ -931,7 +933,8 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,  		 * If we are sending CMD23, CMD12 never gets sent  		 * on successful completion (so no Auto-CMD12).  		 */ -		if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) +		if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12) && +		    (cmd->opcode != SD_IO_RW_EXTENDED))  			mode |= SDHCI_TRNS_AUTO_CMD12;  		else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {  			mode |= SDHCI_TRNS_AUTO_CMD23; @@ -1356,7 +1359,8 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)  	sdhci_runtime_pm_get(host); -	present = mmc_gpio_get_cd(host->mmc); +	/* Firstly check card presence */ +	present = sdhci_do_get_cd(host);  	spin_lock_irqsave(&host->lock, flags); @@ -1379,22 +1383,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)  	host->mrq = mrq; -	/* -	 * Firstly check card presence from cd-gpio.  The return could -	 * be one of the following possibilities: -	 *     negative: cd-gpio is not available -	 *     zero: cd-gpio is used, and card is removed -	 *     one: cd-gpio is used, and card is present -	 */ -	if (present < 0) { -		/* If polling, assume that the card is always present. */ -		if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) -			present = 1; -		else -			present = sdhci_readl(host, SDHCI_PRESENT_STATE) & -					SDHCI_CARD_PRESENT; -	} -  	if (!present || host->flags & SDHCI_DEVICE_DEAD) {  		host->mrq->cmd->error = -ENOMEDIUM;  		tasklet_schedule(&host->finish_tasklet); @@ -3164,7 +3152,8 @@ int sdhci_add_host(struct sdhci_host *host)  	/* Auto-CMD23 stuff only works in ADMA or PIO. */  	if ((host->version >= SDHCI_SPEC_300) &&  	    ((host->flags & SDHCI_USE_ADMA) || -	     !(host->flags & SDHCI_USE_SDMA))) { +	     !(host->flags & SDHCI_USE_SDMA)) && +	     !(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) {  		host->flags |= SDHCI_AUTO_CMD23;  		DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc));  	} else { diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 0315e1844330..e639b7f435e5 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -18,7 +18,7 @@  #include <linux/types.h>  #include <linux/io.h> -#include <linux/mmc/sdhci.h> +#include <linux/mmc/host.h>  /*   * Controller registers @@ -309,6 +309,207 @@ struct sdhci_adma2_64_desc {   */  #define SDHCI_MAX_SEGS		128 +struct sdhci_host_next { +	unsigned int	sg_count; +	s32		cookie; +}; + +struct sdhci_host { +	/* Data set by hardware interface driver */ +	const char *hw_name;	/* Hardware bus name */ + +	unsigned int quirks;	/* Deviations from spec. */ + +/* Controller doesn't honor resets unless we touch the clock register */ +#define SDHCI_QUIRK_CLOCK_BEFORE_RESET			(1<<0) +/* Controller has bad caps bits, but really supports DMA */ +#define SDHCI_QUIRK_FORCE_DMA				(1<<1) +/* Controller doesn't like to be reset when there is no card inserted. */ +#define SDHCI_QUIRK_NO_CARD_NO_RESET			(1<<2) +/* Controller doesn't like clearing the power reg before a change */ +#define SDHCI_QUIRK_SINGLE_POWER_WRITE			(1<<3) +/* Controller has flaky internal state so reset it on each ios change */ +#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS		(1<<4) +/* Controller has an unusable DMA engine */ +#define SDHCI_QUIRK_BROKEN_DMA				(1<<5) +/* Controller has an unusable ADMA engine */ +#define SDHCI_QUIRK_BROKEN_ADMA				(1<<6) +/* Controller can only DMA from 32-bit aligned addresses */ +#define SDHCI_QUIRK_32BIT_DMA_ADDR			(1<<7) +/* Controller can only DMA chunk sizes that are a multiple of 32 bits */ +#define SDHCI_QUIRK_32BIT_DMA_SIZE			(1<<8) +/* Controller can only ADMA chunks that are a multiple of 32 bits */ +#define SDHCI_QUIRK_32BIT_ADMA_SIZE			(1<<9) +/* Controller needs to be reset after each request to stay stable */ +#define SDHCI_QUIRK_RESET_AFTER_REQUEST			(1<<10) +/* Controller needs voltage and power writes to happen separately */ +#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER		(1<<11) +/* Controller provides an incorrect timeout value for transfers */ +#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL			(1<<12) +/* Controller has an issue with buffer bits for small transfers */ +#define SDHCI_QUIRK_BROKEN_SMALL_PIO			(1<<13) +/* Controller does not provide transfer-complete interrupt when not busy */ +#define SDHCI_QUIRK_NO_BUSY_IRQ				(1<<14) +/* Controller has unreliable card detection */ +#define SDHCI_QUIRK_BROKEN_CARD_DETECTION		(1<<15) +/* Controller reports inverted write-protect state */ +#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT		(1<<16) +/* Controller does not like fast PIO transfers */ +#define SDHCI_QUIRK_PIO_NEEDS_DELAY			(1<<18) +/* Controller has to be forced to use block size of 2048 bytes */ +#define SDHCI_QUIRK_FORCE_BLK_SZ_2048			(1<<20) +/* Controller cannot do multi-block transfers */ +#define SDHCI_QUIRK_NO_MULTIBLOCK			(1<<21) +/* Controller can only handle 1-bit data transfers */ +#define SDHCI_QUIRK_FORCE_1_BIT_DATA			(1<<22) +/* Controller needs 10ms delay between applying power and clock */ +#define SDHCI_QUIRK_DELAY_AFTER_POWER			(1<<23) +/* Controller uses SDCLK instead of TMCLK for data timeouts */ +#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK		(1<<24) +/* Controller reports wrong base clock capability */ +#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN		(1<<25) +/* Controller cannot support End Attribute in NOP ADMA descriptor */ +#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC		(1<<26) +/* Controller is missing device caps. Use caps provided by host */ +#define SDHCI_QUIRK_MISSING_CAPS			(1<<27) +/* Controller uses Auto CMD12 command to stop the transfer */ +#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12		(1<<28) +/* Controller doesn't have HISPD bit field in HI-SPEED SD card */ +#define SDHCI_QUIRK_NO_HISPD_BIT			(1<<29) +/* Controller treats ADMA descriptors with length 0000h incorrectly */ +#define SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC		(1<<30) +/* 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_HOST_OFF_CARD_ON			(1<<0) +#define SDHCI_QUIRK2_HOST_NO_CMD23			(1<<1) +/* The system physically doesn't support 1.8v, even if the host does */ +#define SDHCI_QUIRK2_NO_1_8_V				(1<<2) +#define SDHCI_QUIRK2_PRESET_VALUE_BROKEN		(1<<3) +#define SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON		(1<<4) +/* Controller has a non-standard host control register */ +#define SDHCI_QUIRK2_BROKEN_HOST_CONTROL		(1<<5) +/* Controller does not support HS200 */ +#define SDHCI_QUIRK2_BROKEN_HS200			(1<<6) +/* Controller does not support DDR50 */ +#define SDHCI_QUIRK2_BROKEN_DDR50			(1<<7) +/* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */ +#define SDHCI_QUIRK2_STOP_WITH_TC			(1<<8) +/* Controller does not support 64-bit DMA */ +#define SDHCI_QUIRK2_BROKEN_64_BIT_DMA			(1<<9) +/* need clear transfer mode register before send cmd */ +#define SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD	(1<<10) +/* Capability register bit-63 indicates HS400 support */ +#define SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400		(1<<11) +/* forced tuned clock */ +#define SDHCI_QUIRK2_TUNING_WORK_AROUND			(1<<12) +/* disable the block count for single block transactions */ +#define SDHCI_QUIRK2_SUPPORT_SINGLE			(1<<13) +/* Controller broken with using ACMD23 */ +#define SDHCI_QUIRK2_ACMD23_BROKEN			(1<<14) + +	int irq;		/* Device IRQ */ +	void __iomem *ioaddr;	/* Mapped address */ + +	const struct sdhci_ops *ops;	/* Low level hw interface */ + +	/* Internal data */ +	struct mmc_host *mmc;	/* MMC structure */ +	u64 dma_mask;		/* custom DMA mask */ + +#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) +	struct led_classdev led;	/* LED control */ +	char led_name[32]; +#endif + +	spinlock_t lock;	/* Mutex */ + +	int flags;		/* Host attributes */ +#define SDHCI_USE_SDMA		(1<<0)	/* Host is SDMA capable */ +#define SDHCI_USE_ADMA		(1<<1)	/* Host is ADMA capable */ +#define SDHCI_REQ_USE_DMA	(1<<2)	/* Use DMA for this req. */ +#define SDHCI_DEVICE_DEAD	(1<<3)	/* Device unresponsive */ +#define SDHCI_SDR50_NEEDS_TUNING (1<<4)	/* SDR50 needs tuning */ +#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 */ +#define SDHCI_SDR104_NEEDS_TUNING (1<<10)	/* SDR104/HS200 needs tuning */ +#define SDHCI_USING_RETUNING_TIMER (1<<11)	/* Host is using a retuning timer for the card */ +#define SDHCI_USE_64_BIT_DMA	(1<<12)	/* Use 64-bit DMA */ +#define SDHCI_HS400_TUNING	(1<<13)	/* Tuning for HS400 */ + +	unsigned int version;	/* SDHCI spec. version */ + +	unsigned int max_clk;	/* Max possible freq (MHz) */ +	unsigned int timeout_clk;	/* Timeout freq (KHz) */ +	unsigned int clk_mul;	/* Clock Muliplier value */ + +	unsigned int clock;	/* Current clock (MHz) */ +	u8 pwr;			/* Current voltage */ + +	bool runtime_suspended;	/* Host is runtime suspended */ +	bool bus_on;		/* Bus power prevents runtime suspend */ +	bool preset_enabled;	/* Preset is enabled */ + +	struct mmc_request *mrq;	/* Current request */ +	struct mmc_command *cmd;	/* Current command */ +	struct mmc_data *data;	/* Current data request */ +	unsigned int data_early:1;	/* Data finished before cmd */ +	unsigned int busy_handle:1;	/* Handling the order of Busy-end */ + +	struct sg_mapping_iter sg_miter;	/* SG state for PIO */ +	unsigned int blocks;	/* remaining PIO blocks */ + +	int sg_count;		/* Mapped sg entries */ + +	void *adma_table;	/* ADMA descriptor table */ +	void *align_buffer;	/* Bounce buffer */ + +	size_t adma_table_sz;	/* ADMA descriptor table size */ +	size_t align_buffer_sz;	/* Bounce buffer size */ + +	dma_addr_t adma_addr;	/* Mapped ADMA descr. table */ +	dma_addr_t align_addr;	/* Mapped bounce buffer */ + +	unsigned int desc_sz;	/* ADMA descriptor size */ +	unsigned int align_sz;	/* ADMA alignment */ +	unsigned int align_mask;	/* ADMA alignment mask */ + +	struct tasklet_struct finish_tasklet;	/* Tasklet structures */ + +	struct timer_list timer;	/* Timer for timeouts */ + +	u32 caps;		/* Alternative CAPABILITY_0 */ +	u32 caps1;		/* Alternative CAPABILITY_1 */ + +	unsigned int            ocr_avail_sdio;	/* OCR bit masks */ +	unsigned int            ocr_avail_sd; +	unsigned int            ocr_avail_mmc; +	u32 ocr_mask;		/* available voltages */ + +	unsigned		timing;		/* Current timing */ + +	u32			thread_isr; + +	/* cached registers */ +	u32			ier; + +	wait_queue_head_t	buf_ready_int;	/* Waitqueue for Buffer Read Ready interrupt */ +	unsigned int		tuning_done;	/* Condition flag set when CMD19 succeeds */ + +	unsigned int		tuning_count;	/* Timer count for re-tuning */ +	unsigned int		tuning_mode;	/* Re-tuning mode supported by host */ +#define SDHCI_TUNING_MODE_1	0 +	struct timer_list	tuning_timer;	/* Timer for tuning */ + +	struct sdhci_host_next	next_data; +	unsigned long private[0] ____cacheline_aligned; +}; +  struct sdhci_ops {  #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS  	u32		(*read_l)(struct sdhci_host *host, int reg); diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 7d9d6a321521..072f67066df3 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -875,6 +875,7 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,  	struct mmc_command *cmd = mrq->cmd;  	u32 opc = cmd->opcode;  	u32 mask; +	unsigned long flags;  	switch (opc) {  	/* response busy check */ @@ -909,10 +910,12 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,  	/* set arg */  	sh_mmcif_writel(host->addr, MMCIF_CE_ARG, cmd->arg);  	/* set cmd */ +	spin_lock_irqsave(&host->lock, flags);  	sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc);  	host->wait_for = MMCIF_WAIT_FOR_CMD;  	schedule_delayed_work(&host->timeout_work, host->timeout); +	spin_unlock_irqrestore(&host->lock, flags);  }  static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host, @@ -1171,6 +1174,12 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)  	struct sh_mmcif_host *host = dev_id;  	struct mmc_request *mrq;  	bool wait = false; +	unsigned long flags; +	int wait_work; + +	spin_lock_irqsave(&host->lock, flags); +	wait_work = host->wait_for; +	spin_unlock_irqrestore(&host->lock, flags);  	cancel_delayed_work_sync(&host->timeout_work); @@ -1188,7 +1197,7 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)  	 * All handlers return true, if processing continues, and false, if the  	 * request has to be completed - successfully or not  	 */ -	switch (host->wait_for) { +	switch (wait_work) {  	case MMCIF_WAIT_FOR_REQUEST:  		/* We're too late, the timeout has already kicked in */  		mutex_unlock(&host->thread_lock); @@ -1312,15 +1321,15 @@ static void mmcif_timeout_work(struct work_struct *work)  		/* Don't run after mmc_remove_host() */  		return; -	dev_err(&host->pd->dev, "Timeout waiting for %u on CMD%u\n", -		host->wait_for, mrq->cmd->opcode); -  	spin_lock_irqsave(&host->lock, flags);  	if (host->state == STATE_IDLE) {  		spin_unlock_irqrestore(&host->lock, flags);  		return;  	} +	dev_err(&host->pd->dev, "Timeout waiting for %u on CMD%u\n", +		host->wait_for, mrq->cmd->opcode); +  	host->state = STATE_TIMEOUT;  	spin_unlock_irqrestore(&host->lock, flags); diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index e8a4218b5726..4d3e1ffe5508 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -293,7 +293,7 @@ static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host,  				    struct mmc_data *data)  {  	struct sunxi_idma_des *pdes = (struct sunxi_idma_des *)host->sg_cpu; -	struct sunxi_idma_des *pdes_pa = (struct sunxi_idma_des *)host->sg_dma; +	dma_addr_t next_desc = host->sg_dma;  	int i, max_len = (1 << host->idma_des_size_bits);  	for (i = 0; i < data->sg_len; i++) { @@ -305,8 +305,9 @@ static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host,  		else  			pdes[i].buf_size = data->sg[i].length; +		next_desc += sizeof(struct sunxi_idma_des);  		pdes[i].buf_addr_ptr1 = sg_dma_address(&data->sg[i]); -		pdes[i].buf_addr_ptr2 = (u32)&pdes_pa[i + 1]; +		pdes[i].buf_addr_ptr2 = (u32)next_desc;  	}  	pdes[0].config |= SDXC_IDMAC_DES0_FD; @@ -930,7 +931,9 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,  		return PTR_ERR(host->clk_sample);  	} -	host->reset = devm_reset_control_get(&pdev->dev, "ahb"); +	host->reset = devm_reset_control_get_optional(&pdev->dev, "ahb"); +	if (PTR_ERR(host->reset) == -EPROBE_DEFER) +		return PTR_ERR(host->reset);  	ret = clk_prepare_enable(host->clk_ahb);  	if (ret) { @@ -1028,7 +1031,7 @@ static int sunxi_mmc_probe(struct platform_device *pdev)  	mmc->f_min		=   400000;  	mmc->f_max		= 50000000;  	mmc->caps	       |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | -				  MMC_CAP_ERASE; +				  MMC_CAP_ERASE | MMC_CAP_SDIO_IRQ;  	ret = mmc_of_parse(mmc);  	if (ret) diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index a31c3573d386..dba7e1c19dd7 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -1073,8 +1073,6 @@ EXPORT_SYMBOL(tmio_mmc_host_alloc);  void tmio_mmc_host_free(struct tmio_mmc_host *host)  {  	mmc_free_host(host->mmc); - -	host->mmc = NULL;  }  EXPORT_SYMBOL(tmio_mmc_host_free); diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c index dd2e1aa95ba3..5af00559e9d6 100644 --- a/drivers/mmc/host/wmt-sdmmc.c +++ b/drivers/mmc/host/wmt-sdmmc.c @@ -744,7 +744,7 @@ static struct wmt_mci_caps wm8505_caps = {  	.max_blk_size = 2048,  }; -static struct of_device_id wmt_mci_dt_ids[] = { +static const struct of_device_id wmt_mci_dt_ids[] = {  	{ .compatible = "wm,wm8505-sdhc", .data = &wm8505_caps },  	{ /* Sentinel */ },  };  |