diff mbox

[V2] mmc: dwmmc: Add quirk for broken Hardware Config

Message ID 1343045127-20227-2-git-send-email-girish.shivananjappa@linaro.org (mailing list archive)
State Awaiting Upstream, archived
Headers show

Commit Message

Girish K S July 23, 2012, 12:05 p.m. UTC
In some Soc'S that integrate Designware mmc host controllers, the
HCON register is broken. The hardware configuration is not
updated. One specific usecase is the IDMAC. In Exysons5 SoC
there exist a internal DMA, but the HCON register's DMA_INTERFACE
field is not set to indicate its existance.

This quirk can be used in such case to force the existance broken
HCON field.

changes in v2:
	-moved the implementation to quirk framework as per venkat's
	 review comment.
changes in v1:
	-modified the caps2 field access per controller index.Reported
	 by Jaehoon Chung <jh80.chung@samsung.com>.
	-replaced the pointer to device with the pointer to platform
	 device in struct dw_mci.
	-updated driver data for all 4 mmc controllers of exynos5 SoC.
	-added non device-tree support for ctrl_id access.

Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
---
 drivers/mmc/host/dw_mmc-pltfm.c |   10 +++-
 drivers/mmc/host/dw_mmc.c       |  151 ++++++++++++++++++++++++---------------
 drivers/mmc/host/dw_mmc.h       |    1 +
 include/linux/mmc/dw_mmc.h      |    4 +-
 4 files changed, 107 insertions(+), 59 deletions(-)

Comments

Seungwon Jeon July 24, 2012, 5:18 a.m. UTC | #1
Hi Girish,

July 23, 2012, Girish K S <girish.shivananjappa@linaro.org> wrote:
> In some Soc'S that integrate Designware mmc host controllers, the
> HCON register is broken. The hardware configuration is not
> updated. One specific usecase is the IDMAC. In Exysons5 SoC
> there exist a internal DMA, but the HCON register's DMA_INTERFACE
> field is not set to indicate its existance.
> 
> This quirk can be used in such case to force the existance broken
> HCON field.
> 
> changes in v2:
> 	-moved the implementation to quirk framework as per venkat's
> 	 review comment.
> changes in v1:
> 	-modified the caps2 field access per controller index.Reported
> 	 by Jaehoon Chung <jh80.chung@samsung.com>.
> 	-replaced the pointer to device with the pointer to platform
> 	 device in struct dw_mci.
Change related to adding pointer of platform_device is needed in this patch seriously?
I guess that the purpose is to get id of platform_device in case of non-dt.
Although a lot of replace is done throughout dw_mmc, actual usage is only in dw_get_platform_device_id.
You can split it into another patch if this change is needed, or it's good to use other way.
For example, to_platform_device macro is useful to get pointer of platform_device.

Best regards,
Seungwon Jeon

> 	-updated driver data for all 4 mmc controllers of exynos5 SoC.
> 	-added non device-tree support for ctrl_id access.
> 
> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
> ---
>  drivers/mmc/host/dw_mmc-pltfm.c |   10 +++-
>  drivers/mmc/host/dw_mmc.c       |  151 ++++++++++++++++++++++++---------------
>  drivers/mmc/host/dw_mmc.h       |    1 +
>  include/linux/mmc/dw_mmc.h      |    4 +-
>  4 files changed, 107 insertions(+), 59 deletions(-)
> 
> diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
> index 900f412..7d31e90 100644
> --- a/drivers/mmc/host/dw_mmc-pltfm.c
> +++ b/drivers/mmc/host/dw_mmc-pltfm.c
> @@ -35,9 +35,17 @@ static unsigned long exynos5250_dwmmc_caps[4] = {
>  	MMC_CAP_CMD23,
>  };
> 
> +static unsigned long exynos5250_dwmmc_quirks[4] = {
> +	DW_MCI_QUIRK_NO_HCON_DMA_INFO,
> +	DW_MCI_QUIRK_NO_HCON_DMA_INFO,
> +	DW_MCI_QUIRK_NO_HCON_DMA_INFO,
> +	DW_MCI_QUIRK_NO_HCON_DMA_INFO,
> +};
> +
>  static struct dw_mci_drv_data exynos5250_drv_data = {
>  	.ctrl_type	= DW_MCI_TYPE_EXYNOS5250,
>  	.caps		= exynos5250_dwmmc_caps,
> +	.quirks		= exynos5250_dwmmc_quirks,
>  };
> 
>  static const struct of_device_id dw_mci_pltfm_match[] = {
> @@ -74,7 +82,7 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
>  		goto err_free;
>  	}
> 
> -	host->dev = &pdev->dev;
> +	host->pdev = pdev;
>  	host->irq_flags = 0;
>  	host->pdata = pdev->dev.platform_data;
>  	ret = -ENOMEM;
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index 000da16..b32e200 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -283,8 +283,10 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
>  static void dw_mci_start_command(struct dw_mci *host,
>  				 struct mmc_command *cmd, u32 cmd_flags)
>  {
> +	struct device *dev = &host->pdev->dev;
> +
>  	host->cmd = cmd;
> -	dev_vdbg(host->dev,
> +	dev_vdbg(dev,
>  		 "start command: ARGR=0x%08x CMDR=0x%08x\n",
>  		 cmd->arg, cmd_flags);
> 
> @@ -323,10 +325,11 @@ static int dw_mci_get_dma_dir(struct mmc_data *data)
>  static void dw_mci_dma_cleanup(struct dw_mci *host)
>  {
>  	struct mmc_data *data = host->data;
> +	struct device *dev = &host->pdev->dev;
> 
>  	if (data)
>  		if (!data->host_cookie)
> -			dma_unmap_sg(host->dev,
> +			dma_unmap_sg(dev,
>  				     data->sg,
>  				     data->sg_len,
>  				     dw_mci_get_dma_dir(data));
> @@ -351,8 +354,9 @@ static void dw_mci_idmac_stop_dma(struct dw_mci *host)
>  static void dw_mci_idmac_complete_dma(struct dw_mci *host)
>  {
>  	struct mmc_data *data = host->data;
> +	struct device *dev = &host->pdev->dev;
> 
> -	dev_vdbg(host->dev, "DMA complete\n");
> +	dev_vdbg(dev, "DMA complete\n");
> 
>  	host->dma_ops->cleanup(host);
> 
> @@ -420,10 +424,27 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
>  	mci_writel(host, PLDMND, 1);
>  }
> 
> +static int dw_get_platform_device_id(struct dw_mci *host)
> +{
> +	int ctrl_id;
> +	struct device *dev = &host->pdev->dev;
> +
> +	if (dev->of_node)
> +		ctrl_id = of_alias_get_id(dev->of_node, "mshc");
> +	else
> +		ctrl_id = host->pdev->id;
> +
> +	if (ctrl_id < 0)
> +		ctrl_id = 0;
> +
> +	return ctrl_id;
> +}
> +
>  static int dw_mci_idmac_init(struct dw_mci *host)
>  {
>  	struct idmac_desc *p;
>  	int i, dma_support;
> +	struct device *dev = &host->pdev->dev;
> 
>  	/* Number of descriptors in the ring buffer */
>  	host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
> @@ -431,14 +452,20 @@ static int dw_mci_idmac_init(struct dw_mci *host)
>  	/* Check if Hardware Configuration Register has support for DMA */
>  	dma_support = (mci_readl(host, HCON) >> 16) & 0x3;
> 
> -	if (!dma_support || dma_support > 2) {
> -		dev_err(&host->dev,
> +	/*
> +	 * In Some of the Soc's the HCON Register is broken. Even though the
> +	 * Soc's has a internal DMA the HCON register's DMA field doesnt
> +	 * show it. So additional quirk is added for such Soc's
> +	 */
> +	if ((!dma_support || dma_support > 2) &&
> +	    !(host->quirks & DW_MCI_QUIRK_NO_HCON_DMA_INFO)) {
> +		dev_err(dev,
>  			"Host Controller does not support IDMA Tx.\n");
>  		host->dma_ops = NULL;
>  		return -ENODEV;
>  	}
> 
> -	dev_info(&host->dev, "Using internal DMA controller.\n");
> +	dev_info(dev, "Using internal DMA controller.\n");
> 
>  	/* Forward link the descriptor list */
>  	for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
> @@ -474,6 +501,7 @@ static int dw_mci_pre_dma_transfer(struct dw_mci *host,
>  {
>  	struct scatterlist *sg;
>  	unsigned int i, sg_len;
> +	struct device *dev = &host->pdev->dev;
> 
>  	if (!next && data->host_cookie)
>  		return data->host_cookie;
> @@ -494,7 +522,7 @@ static int dw_mci_pre_dma_transfer(struct dw_mci *host,
>  			return -EINVAL;
>  	}
> 
> -	sg_len = dma_map_sg(host->dev,
> +	sg_len = dma_map_sg(dev,
>  			    data->sg,
>  			    data->sg_len,
>  			    dw_mci_get_dma_dir(data));
> @@ -532,12 +560,13 @@ static void dw_mci_post_req(struct mmc_host *mmc,
>  {
>  	struct dw_mci_slot *slot = mmc_priv(mmc);
>  	struct mmc_data *data = mrq->data;
> +	struct device *dev = &slot->host->pdev->dev;
> 
>  	if (!slot->host->use_dma || !data)
>  		return;
> 
>  	if (data->host_cookie)
> -		dma_unmap_sg(slot->host->dev,
> +		dma_unmap_sg(dev,
>  			     data->sg,
>  			     data->sg_len,
>  			     dw_mci_get_dma_dir(data));
> @@ -548,6 +577,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
>  {
>  	int sg_len;
>  	u32 temp;
> +	struct device *dev = &host->pdev->dev;
> 
>  	host->using_dma = 0;
> 
> @@ -563,7 +593,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
> 
>  	host->using_dma = 1;
> 
> -	dev_vdbg(host->dev,
> +	dev_vdbg(dev,
>  		 "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
>  		 (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
>  		 sg_len);
> @@ -928,6 +958,7 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
>  {
>  	struct dw_mci_slot *slot;
>  	struct mmc_host	*prev_mmc = host->cur_slot->mmc;
> +	struct device *dev = &host->pdev->dev;
> 
>  	WARN_ON(host->cmd || host->data);
> 
> @@ -937,12 +968,12 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
>  		slot = list_entry(host->queue.next,
>  				  struct dw_mci_slot, queue_node);
>  		list_del(&slot->queue_node);
> -		dev_vdbg(host->dev, "list not empty: %s is next\n",
> +		dev_vdbg(dev, "list not empty: %s is next\n",
>  			 mmc_hostname(slot->mmc));
>  		host->state = STATE_SENDING_CMD;
>  		dw_mci_start_request(host, slot);
>  	} else {
> -		dev_vdbg(host->dev, "list empty\n");
> +		dev_vdbg(dev, "list empty\n");
>  		host->state = STATE_IDLE;
>  	}
> 
> @@ -1081,7 +1112,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
>  					data->bytes_xfered = 0;
>  					data->error = -ETIMEDOUT;
>  				} else {
> -					dev_err(host->dev,
> +					dev_err(&host->pdev->dev,
>  						"data FIFO error "
>  						"(status=%08x)\n",
>  						status);
> @@ -1829,7 +1860,8 @@ static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
> 
>  static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
>  {
> -	struct device_node *np = dw_mci_of_find_slot_node(host->dev, slot);
> +	struct device *dev = &host->pdev->dev;
> +	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
>  	int idx, gpio, ret;
> 
>  	if (!np)
> @@ -1838,13 +1870,13 @@ static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
>  	for (idx = 0; idx < NUM_PINS(bus_wd); idx++) {
>  		gpio = of_get_gpio(np, idx);
>  		if (!gpio_is_valid(gpio)) {
> -			dev_err(host->dev, "invalid gpio: %d\n", gpio);
> +			dev_err(dev, "invalid gpio: %d\n", gpio);
>  			return -EINVAL;
>  		}
> 
> -		ret = devm_gpio_request(host->dev, gpio, "dw-mci-bus");
> +		ret = devm_gpio_request(dev, gpio, "dw-mci-bus");
>  		if (ret) {
> -			dev_err(host->dev, "gpio [%d] request failed\n", gpio);
> +			dev_err(dev, "gpio [%d] request failed\n", gpio);
>  			return -EBUSY;
>  		}
>  	}
> @@ -1852,11 +1884,11 @@ static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
>  	host->slot[slot]->wp_gpio = -1;
>  	gpio = of_get_named_gpio(np, "wp-gpios", 0);
>  	if (!gpio_is_valid(gpio)) {
> -		dev_info(host->dev, "wp gpio not available");
> +		dev_info(dev, "wp gpio not available");
>  	} else {
> -		ret = devm_gpio_request(host->dev, gpio, "dw-mci-wp");
> +		ret = devm_gpio_request(dev, gpio, "dw-mci-wp");
>  		if (ret)
> -			dev_info(host->dev, "gpio [%d] request failed\n",
> +			dev_info(dev, "gpio [%d] request failed\n",
>  						gpio);
>  		else
>  			host->slot[slot]->wp_gpio = gpio;
> @@ -1865,11 +1897,11 @@ static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
>  	host->slot[slot]->cd_gpio = -1;
>  	gpio = of_get_named_gpio(np, "cd-gpios", 0);
>  	if (!gpio_is_valid(gpio)) {
> -		dev_info(host->dev, "cd gpio not available");
> +		dev_info(dev, "cd gpio not available");
>  	} else {
> -		ret = devm_gpio_request(host->dev, gpio, "dw-mci-cd");
> +		ret = devm_gpio_request(dev, gpio, "dw-mci-cd");
>  		if (ret)
> -			dev_err(host->dev, "gpio [%d] request failed\n", gpio);
> +			dev_err(dev, "gpio [%d] request failed\n", gpio);
>  		else
>  			host->slot[slot]->cd_gpio = gpio;
>  	}
> @@ -1893,8 +1925,9 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>  	struct mmc_host *mmc;
>  	struct dw_mci_slot *slot;
>  	int ctrl_id, ret;
> +	struct device *dev = &host->pdev->dev;
> 
> -	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
> +	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), dev);
>  	if (!mmc)
>  		return -ENOMEM;
> 
> @@ -1923,11 +1956,8 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>  	if (host->pdata->caps)
>  		mmc->caps = host->pdata->caps;
> 
> -	if (host->dev->of_node) {
> -		ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
> -		if (ctrl_id < 0)
> -			ctrl_id = 0;
> -	}
> +	ctrl_id = dw_get_platform_device_id(host);
> +
>  	if (host->drv_data->caps)
>  		mmc->caps |= host->drv_data->caps[ctrl_id];
> 
> @@ -1937,9 +1967,9 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>  	if (host->pdata->get_bus_wd) {
>  		if (host->pdata->get_bus_wd(slot->id) >= 4)
>  			mmc->caps |= MMC_CAP_4_BIT_DATA;
> -	} else if (host->dev->of_node) {
> +	} else if (dev->of_node) {
>  		unsigned int bus_width;
> -		bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id);
> +		bus_width = dw_mci_of_get_bus_wd(dev, slot->id);
>  		switch (bus_width) {
>  		case 8:
>  			mmc->caps |= MMC_CAP_8_BIT_DATA;
> @@ -2030,11 +2060,12 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
> 
>  static void dw_mci_init_dma(struct dw_mci *host)
>  {
> +	struct device *dev = &host->pdev->dev;
>  	/* Alloc memory for sg translation */
> -	host->sg_cpu = dma_alloc_coherent(host->dev, PAGE_SIZE,
> +	host->sg_cpu = dma_alloc_coherent(dev, PAGE_SIZE,
>  					  &host->sg_dma, GFP_KERNEL);
>  	if (!host->sg_cpu) {
> -		dev_err(host->dev, "%s: could not alloc DMA memory\n",
> +		dev_err(dev, "%s: could not alloc DMA memory\n",
>  			__func__);
>  		goto no_dma;
>  	}
> @@ -2050,12 +2081,12 @@ static void dw_mci_init_dma(struct dw_mci *host)
>  	if (host->dma_ops->init && host->dma_ops->start &&
>  	    host->dma_ops->stop && host->dma_ops->cleanup) {
>  		if (host->dma_ops->init(host)) {
> -			dev_err(host->dev, "%s: Unable to initialize "
> +			dev_err(dev, "%s: Unable to initialize "
>  				"DMA Controller.\n", __func__);
>  			goto no_dma;
>  		}
>  	} else {
> -		dev_err(host->dev, "DMA initialization not found.\n");
> +		dev_err(dev, "DMA initialization not found.\n");
>  		goto no_dma;
>  	}
> 
> @@ -2063,7 +2094,7 @@ static void dw_mci_init_dma(struct dw_mci *host)
>  	return;
> 
>  no_dma:
> -	dev_info(host->dev, "Using PIO mode.\n");
> +	dev_info(dev, "Using PIO mode.\n");
>  	host->use_dma = 0;
>  	return;
>  }
> @@ -2109,7 +2140,7 @@ static struct dw_mci_of_quirks {
>  static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
>  {
>  	struct dw_mci_board *pdata;
> -	struct device *dev = host->dev;
> +	struct device *dev = &host->pdev->dev;
>  	struct device_node *np = dev->of_node;
>  	u32 timing[3];
>  	int idx, cnt;
> @@ -2166,33 +2197,34 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
> 
>  int dw_mci_probe(struct dw_mci *host)
>  {
> -	int width, i, ret = 0;
> +	int width, i, ctrl_id, ret = 0;
>  	u32 fifo_size;
>  	int init_slots = 0;
> +	struct device *dev = &host->pdev->dev;
> 
>  	if (!host->pdata) {
>  		host->pdata = dw_mci_parse_dt(host);
>  		if (IS_ERR(host->pdata)) {
> -			dev_err(host->dev, "platform data not available\n");
> +			dev_err(dev, "platform data not available\n");
>  			return -EINVAL;
>  		}
>  	}
> 
>  	if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
> -		dev_err(host->dev,
> +		dev_err(dev,
>  			"Platform data must supply select_slot function\n");
>  		return -ENODEV;
>  	}
> 
> -	host->biu_clk = clk_get(host->dev, "biu");
> +	host->biu_clk = clk_get(dev, "biu");
>  	if (IS_ERR(host->biu_clk))
> -		dev_dbg(host->dev, "biu clock not available\n");
> +		dev_dbg(dev, "biu clock not available\n");
>  	else
>  		clk_prepare_enable(host->biu_clk);
> 
> -	host->ciu_clk = clk_get(host->dev, "ciu");
> +	host->ciu_clk = clk_get(dev, "ciu");
>  	if (IS_ERR(host->ciu_clk))
> -		dev_dbg(host->dev, "ciu clock not available\n");
> +		dev_dbg(dev, "ciu clock not available\n");
>  	else
>  		clk_prepare_enable(host->ciu_clk);
> 
> @@ -2202,7 +2234,7 @@ int dw_mci_probe(struct dw_mci *host)
>  		host->bus_hz = clk_get_rate(host->ciu_clk);
> 
>  	if (!host->bus_hz) {
> -		dev_err(host->dev,
> +		dev_err(dev,
>  			"Platform data must supply bus speed\n");
>  		ret = -ENODEV;
>  		goto err_clk;
> @@ -2210,6 +2242,11 @@ int dw_mci_probe(struct dw_mci *host)
> 
>  	host->quirks = host->pdata->quirks;
> 
> +	ctrl_id = dw_get_platform_device_id(host);
> +
> +	if (host->drv_data->quirks)
> +		host->quirks |= host->drv_data->quirks[ctrl_id];
> +
>  	spin_lock_init(&host->lock);
>  	INIT_LIST_HEAD(&host->queue);
> 
> @@ -2243,7 +2280,7 @@ int dw_mci_probe(struct dw_mci *host)
>  	}
> 
>  	/* Reset all blocks */
> -	if (!mci_wait_reset(host->dev, host))
> +	if (!mci_wait_reset(dev, host))
>  		return -ENODEV;
> 
>  	host->dma_ops = host->pdata->dma_ops;
> @@ -2300,15 +2337,15 @@ int dw_mci_probe(struct dw_mci *host)
>  	for (i = 0; i < host->num_slots; i++) {
>  		ret = dw_mci_init_slot(host, i);
>  		if (ret)
> -			dev_dbg(host->dev, "slot %d init failed\n", i);
> +			dev_dbg(dev, "slot %d init failed\n", i);
>  		else
>  			init_slots++;
>  	}
> 
>  	if (init_slots) {
> -		dev_info(host->dev, "%d slots initialized\n", init_slots);
> +		dev_info(dev, "%d slots initialized\n", init_slots);
>  	} else {
> -		dev_dbg(host->dev, "attempted to initialize %d slots, "
> +		dev_dbg(dev, "attempted to initialize %d slots, "
>  					"but failed on all\n", host->num_slots);
>  		goto err_init_slot;
>  	}
> @@ -2318,7 +2355,7 @@ int dw_mci_probe(struct dw_mci *host)
>  	 * Need to check the version-id and set data-offset for DATA register.
>  	 */
>  	host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
> -	dev_info(host->dev, "Version ID is %04x\n", host->verid);
> +	dev_info(dev, "Version ID is %04x\n", host->verid);
> 
>  	if (host->verid < DW_MMC_240A)
>  		host->data_offset = DATA_OFFSET;
> @@ -2335,12 +2372,12 @@ int dw_mci_probe(struct dw_mci *host)
>  		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
>  	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
> 
> -	dev_info(host->dev, "DW MMC controller at irq %d, "
> +	dev_info(dev, "DW MMC controller at irq %d, "
>  		 "%d bit host data width, "
>  		 "%u deep fifo\n",
>  		 host->irq, width, fifo_size);
>  	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
> -		dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");
> +		dev_info(dev, "Internal DMAC interrupt fix enabled.\n");
> 
>  	return 0;
> 
> @@ -2353,7 +2390,7 @@ err_workqueue:
>  err_dmaunmap:
>  	if (host->use_dma && host->dma_ops->exit)
>  		host->dma_ops->exit(host);
> -	dma_free_coherent(host->dev, PAGE_SIZE,
> +	dma_free_coherent(dev, PAGE_SIZE,
>  			  host->sg_cpu, host->sg_dma);
> 
>  	if (host->vmmc) {
> @@ -2377,23 +2414,23 @@ EXPORT_SYMBOL(dw_mci_probe);
>  void dw_mci_remove(struct dw_mci *host)
>  {
>  	int i;
> +	struct device *dev = &host->pdev->dev;
> 
>  	mci_writel(host, RINTSTS, 0xFFFFFFFF);
>  	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
> 
>  	for (i = 0; i < host->num_slots; i++) {
> -		dev_dbg(host->dev, "remove slot %d\n", i);
> +		dev_dbg(dev, "remove slot %d\n", i);
>  		if (host->slot[i])
>  			dw_mci_cleanup_slot(host->slot[i], i);
>  	}
> -
>  	/* disable clock to CIU */
>  	mci_writel(host, CLKENA, 0);
>  	mci_writel(host, CLKSRC, 0);
> 
>  	free_irq(host->irq, host);
>  	destroy_workqueue(host->card_workqueue);
> -	dma_free_coherent(host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
> +	dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
> 
>  	if (host->use_dma && host->dma_ops->exit)
>  		host->dma_ops->exit(host);
> @@ -2451,7 +2488,7 @@ int dw_mci_resume(struct dw_mci *host)
>  	if (host->vmmc)
>  		regulator_enable(host->vmmc);
> 
> -	if (!mci_wait_reset(host->dev, host)) {
> +	if (!mci_wait_reset(&host->pdev->dev, host)) {
>  		ret = -ENODEV;
>  		return ret;
>  	}
> @@ -2483,7 +2520,7 @@ EXPORT_SYMBOL(dw_mci_resume);
> 
>  static int __init dw_mci_init(void)
>  {
> -	printk(KERN_INFO "Synopsys Designware Multimedia Card Interface Driver");
> +	pr_info("Synopsys Designware Multimedia Card Interface Driver");
>  	return 0;
>  }
> 
> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
> index 6c17282..a3d684b 100644
> --- a/drivers/mmc/host/dw_mmc.h
> +++ b/drivers/mmc/host/dw_mmc.h
> @@ -203,6 +203,7 @@ extern int dw_mci_resume(struct dw_mci *host);
>  struct dw_mci_drv_data {
>  	unsigned long		ctrl_type;
>  	unsigned long		*caps;
> +	unsigned long		*quirks;
>  };
> 
>  #endif /* _DW_MMC_H_ */
> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
> index 32c778f..03c409b 100644
> --- a/include/linux/mmc/dw_mmc.h
> +++ b/include/linux/mmc/dw_mmc.h
> @@ -161,7 +161,7 @@ struct dw_mci {
>  	u32			fifoth_val;
>  	u16			verid;
>  	u16			data_offset;
> -	struct device		*dev;
> +	struct platform_device	*pdev;
>  	struct dw_mci_board	*pdata;
>  	struct dw_mci_drv_data	*drv_data;
>  	struct clk		*biu_clk;
> @@ -215,6 +215,8 @@ struct dw_mci_dma_ops {
>  #define DW_MCI_QUIRK_BROKEN_CARD_DETECTION	BIT(3)
>  /* Write Protect detection not available */
>  #define DW_MCI_QUIRK_NO_WRITE_PROTECT		BIT(4)
> +/* HCON Register's IDMAC information broken */
> +#define DW_MCI_QUIRK_NO_HCON_DMA_INFO		BIT(5)
> 
>  struct dma_pdata;
> 
> --
> 1.7.4.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Girish K S July 26, 2012, 4:34 a.m. UTC | #2
On 24 July 2012 10:48, Seungwon Jeon <tgih.jun@samsung.com> wrote:
> Hi Girish,
>
> July 23, 2012, Girish K S <girish.shivananjappa@linaro.org> wrote:
>> In some Soc'S that integrate Designware mmc host controllers, the
>> HCON register is broken. The hardware configuration is not
>> updated. One specific usecase is the IDMAC. In Exysons5 SoC
>> there exist a internal DMA, but the HCON register's DMA_INTERFACE
>> field is not set to indicate its existance.
>>
>> This quirk can be used in such case to force the existance broken
>> HCON field.
>>
>> changes in v2:
>>       -moved the implementation to quirk framework as per venkat's
>>        review comment.
>> changes in v1:
>>       -modified the caps2 field access per controller index.Reported
>>        by Jaehoon Chung <jh80.chung@samsung.com>.
>>       -replaced the pointer to device with the pointer to platform
>>        device in struct dw_mci.
> Change related to adding pointer of platform_device is needed in this patch seriously?
> I guess that the purpose is to get id of platform_device in case of non-dt.
> Although a lot of replace is done throughout dw_mmc, actual usage is only in dw_get_platform_device_id.
> You can split it into another patch if this change is needed, or it's good to use other way.
> For example, to_platform_device macro is useful to get pointer of platform_device.
I will make the necessary changes as suggested once Thomas's patches
gets accepted
>
> Best regards,
> Seungwon Jeon
>
>>       -updated driver data for all 4 mmc controllers of exynos5 SoC.
>>       -added non device-tree support for ctrl_id access.
>>
>> Signed-off-by: Girish K S <girish.shivananjappa@linaro.org>
>> ---
>>  drivers/mmc/host/dw_mmc-pltfm.c |   10 +++-
>>  drivers/mmc/host/dw_mmc.c       |  151 ++++++++++++++++++++++++---------------
>>  drivers/mmc/host/dw_mmc.h       |    1 +
>>  include/linux/mmc/dw_mmc.h      |    4 +-
>>  4 files changed, 107 insertions(+), 59 deletions(-)
>>
>> diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
>> index 900f412..7d31e90 100644
>> --- a/drivers/mmc/host/dw_mmc-pltfm.c
>> +++ b/drivers/mmc/host/dw_mmc-pltfm.c
>> @@ -35,9 +35,17 @@ static unsigned long exynos5250_dwmmc_caps[4] = {
>>       MMC_CAP_CMD23,
>>  };
>>
>> +static unsigned long exynos5250_dwmmc_quirks[4] = {
>> +     DW_MCI_QUIRK_NO_HCON_DMA_INFO,
>> +     DW_MCI_QUIRK_NO_HCON_DMA_INFO,
>> +     DW_MCI_QUIRK_NO_HCON_DMA_INFO,
>> +     DW_MCI_QUIRK_NO_HCON_DMA_INFO,
>> +};
>> +
>>  static struct dw_mci_drv_data exynos5250_drv_data = {
>>       .ctrl_type      = DW_MCI_TYPE_EXYNOS5250,
>>       .caps           = exynos5250_dwmmc_caps,
>> +     .quirks         = exynos5250_dwmmc_quirks,
>>  };
>>
>>  static const struct of_device_id dw_mci_pltfm_match[] = {
>> @@ -74,7 +82,7 @@ static int dw_mci_pltfm_probe(struct platform_device *pdev)
>>               goto err_free;
>>       }
>>
>> -     host->dev = &pdev->dev;
>> +     host->pdev = pdev;
>>       host->irq_flags = 0;
>>       host->pdata = pdev->dev.platform_data;
>>       ret = -ENOMEM;
>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>> index 000da16..b32e200 100644
>> --- a/drivers/mmc/host/dw_mmc.c
>> +++ b/drivers/mmc/host/dw_mmc.c
>> @@ -283,8 +283,10 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
>>  static void dw_mci_start_command(struct dw_mci *host,
>>                                struct mmc_command *cmd, u32 cmd_flags)
>>  {
>> +     struct device *dev = &host->pdev->dev;
>> +
>>       host->cmd = cmd;
>> -     dev_vdbg(host->dev,
>> +     dev_vdbg(dev,
>>                "start command: ARGR=0x%08x CMDR=0x%08x\n",
>>                cmd->arg, cmd_flags);
>>
>> @@ -323,10 +325,11 @@ static int dw_mci_get_dma_dir(struct mmc_data *data)
>>  static void dw_mci_dma_cleanup(struct dw_mci *host)
>>  {
>>       struct mmc_data *data = host->data;
>> +     struct device *dev = &host->pdev->dev;
>>
>>       if (data)
>>               if (!data->host_cookie)
>> -                     dma_unmap_sg(host->dev,
>> +                     dma_unmap_sg(dev,
>>                                    data->sg,
>>                                    data->sg_len,
>>                                    dw_mci_get_dma_dir(data));
>> @@ -351,8 +354,9 @@ static void dw_mci_idmac_stop_dma(struct dw_mci *host)
>>  static void dw_mci_idmac_complete_dma(struct dw_mci *host)
>>  {
>>       struct mmc_data *data = host->data;
>> +     struct device *dev = &host->pdev->dev;
>>
>> -     dev_vdbg(host->dev, "DMA complete\n");
>> +     dev_vdbg(dev, "DMA complete\n");
>>
>>       host->dma_ops->cleanup(host);
>>
>> @@ -420,10 +424,27 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
>>       mci_writel(host, PLDMND, 1);
>>  }
>>
>> +static int dw_get_platform_device_id(struct dw_mci *host)
>> +{
>> +     int ctrl_id;
>> +     struct device *dev = &host->pdev->dev;
>> +
>> +     if (dev->of_node)
>> +             ctrl_id = of_alias_get_id(dev->of_node, "mshc");
>> +     else
>> +             ctrl_id = host->pdev->id;
>> +
>> +     if (ctrl_id < 0)
>> +             ctrl_id = 0;
>> +
>> +     return ctrl_id;
>> +}
>> +
>>  static int dw_mci_idmac_init(struct dw_mci *host)
>>  {
>>       struct idmac_desc *p;
>>       int i, dma_support;
>> +     struct device *dev = &host->pdev->dev;
>>
>>       /* Number of descriptors in the ring buffer */
>>       host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
>> @@ -431,14 +452,20 @@ static int dw_mci_idmac_init(struct dw_mci *host)
>>       /* Check if Hardware Configuration Register has support for DMA */
>>       dma_support = (mci_readl(host, HCON) >> 16) & 0x3;
>>
>> -     if (!dma_support || dma_support > 2) {
>> -             dev_err(&host->dev,
>> +     /*
>> +      * In Some of the Soc's the HCON Register is broken. Even though the
>> +      * Soc's has a internal DMA the HCON register's DMA field doesnt
>> +      * show it. So additional quirk is added for such Soc's
>> +      */
>> +     if ((!dma_support || dma_support > 2) &&
>> +         !(host->quirks & DW_MCI_QUIRK_NO_HCON_DMA_INFO)) {
>> +             dev_err(dev,
>>                       "Host Controller does not support IDMA Tx.\n");
>>               host->dma_ops = NULL;
>>               return -ENODEV;
>>       }
>>
>> -     dev_info(&host->dev, "Using internal DMA controller.\n");
>> +     dev_info(dev, "Using internal DMA controller.\n");
>>
>>       /* Forward link the descriptor list */
>>       for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
>> @@ -474,6 +501,7 @@ static int dw_mci_pre_dma_transfer(struct dw_mci *host,
>>  {
>>       struct scatterlist *sg;
>>       unsigned int i, sg_len;
>> +     struct device *dev = &host->pdev->dev;
>>
>>       if (!next && data->host_cookie)
>>               return data->host_cookie;
>> @@ -494,7 +522,7 @@ static int dw_mci_pre_dma_transfer(struct dw_mci *host,
>>                       return -EINVAL;
>>       }
>>
>> -     sg_len = dma_map_sg(host->dev,
>> +     sg_len = dma_map_sg(dev,
>>                           data->sg,
>>                           data->sg_len,
>>                           dw_mci_get_dma_dir(data));
>> @@ -532,12 +560,13 @@ static void dw_mci_post_req(struct mmc_host *mmc,
>>  {
>>       struct dw_mci_slot *slot = mmc_priv(mmc);
>>       struct mmc_data *data = mrq->data;
>> +     struct device *dev = &slot->host->pdev->dev;
>>
>>       if (!slot->host->use_dma || !data)
>>               return;
>>
>>       if (data->host_cookie)
>> -             dma_unmap_sg(slot->host->dev,
>> +             dma_unmap_sg(dev,
>>                            data->sg,
>>                            data->sg_len,
>>                            dw_mci_get_dma_dir(data));
>> @@ -548,6 +577,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
>>  {
>>       int sg_len;
>>       u32 temp;
>> +     struct device *dev = &host->pdev->dev;
>>
>>       host->using_dma = 0;
>>
>> @@ -563,7 +593,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
>>
>>       host->using_dma = 1;
>>
>> -     dev_vdbg(host->dev,
>> +     dev_vdbg(dev,
>>                "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
>>                (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
>>                sg_len);
>> @@ -928,6 +958,7 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
>>  {
>>       struct dw_mci_slot *slot;
>>       struct mmc_host *prev_mmc = host->cur_slot->mmc;
>> +     struct device *dev = &host->pdev->dev;
>>
>>       WARN_ON(host->cmd || host->data);
>>
>> @@ -937,12 +968,12 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
>>               slot = list_entry(host->queue.next,
>>                                 struct dw_mci_slot, queue_node);
>>               list_del(&slot->queue_node);
>> -             dev_vdbg(host->dev, "list not empty: %s is next\n",
>> +             dev_vdbg(dev, "list not empty: %s is next\n",
>>                        mmc_hostname(slot->mmc));
>>               host->state = STATE_SENDING_CMD;
>>               dw_mci_start_request(host, slot);
>>       } else {
>> -             dev_vdbg(host->dev, "list empty\n");
>> +             dev_vdbg(dev, "list empty\n");
>>               host->state = STATE_IDLE;
>>       }
>>
>> @@ -1081,7 +1112,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
>>                                       data->bytes_xfered = 0;
>>                                       data->error = -ETIMEDOUT;
>>                               } else {
>> -                                     dev_err(host->dev,
>> +                                     dev_err(&host->pdev->dev,
>>                                               "data FIFO error "
>>                                               "(status=%08x)\n",
>>                                               status);
>> @@ -1829,7 +1860,8 @@ static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
>>
>>  static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
>>  {
>> -     struct device_node *np = dw_mci_of_find_slot_node(host->dev, slot);
>> +     struct device *dev = &host->pdev->dev;
>> +     struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
>>       int idx, gpio, ret;
>>
>>       if (!np)
>> @@ -1838,13 +1870,13 @@ static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
>>       for (idx = 0; idx < NUM_PINS(bus_wd); idx++) {
>>               gpio = of_get_gpio(np, idx);
>>               if (!gpio_is_valid(gpio)) {
>> -                     dev_err(host->dev, "invalid gpio: %d\n", gpio);
>> +                     dev_err(dev, "invalid gpio: %d\n", gpio);
>>                       return -EINVAL;
>>               }
>>
>> -             ret = devm_gpio_request(host->dev, gpio, "dw-mci-bus");
>> +             ret = devm_gpio_request(dev, gpio, "dw-mci-bus");
>>               if (ret) {
>> -                     dev_err(host->dev, "gpio [%d] request failed\n", gpio);
>> +                     dev_err(dev, "gpio [%d] request failed\n", gpio);
>>                       return -EBUSY;
>>               }
>>       }
>> @@ -1852,11 +1884,11 @@ static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
>>       host->slot[slot]->wp_gpio = -1;
>>       gpio = of_get_named_gpio(np, "wp-gpios", 0);
>>       if (!gpio_is_valid(gpio)) {
>> -             dev_info(host->dev, "wp gpio not available");
>> +             dev_info(dev, "wp gpio not available");
>>       } else {
>> -             ret = devm_gpio_request(host->dev, gpio, "dw-mci-wp");
>> +             ret = devm_gpio_request(dev, gpio, "dw-mci-wp");
>>               if (ret)
>> -                     dev_info(host->dev, "gpio [%d] request failed\n",
>> +                     dev_info(dev, "gpio [%d] request failed\n",
>>                                               gpio);
>>               else
>>                       host->slot[slot]->wp_gpio = gpio;
>> @@ -1865,11 +1897,11 @@ static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
>>       host->slot[slot]->cd_gpio = -1;
>>       gpio = of_get_named_gpio(np, "cd-gpios", 0);
>>       if (!gpio_is_valid(gpio)) {
>> -             dev_info(host->dev, "cd gpio not available");
>> +             dev_info(dev, "cd gpio not available");
>>       } else {
>> -             ret = devm_gpio_request(host->dev, gpio, "dw-mci-cd");
>> +             ret = devm_gpio_request(dev, gpio, "dw-mci-cd");
>>               if (ret)
>> -                     dev_err(host->dev, "gpio [%d] request failed\n", gpio);
>> +                     dev_err(dev, "gpio [%d] request failed\n", gpio);
>>               else
>>                       host->slot[slot]->cd_gpio = gpio;
>>       }
>> @@ -1893,8 +1925,9 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>>       struct mmc_host *mmc;
>>       struct dw_mci_slot *slot;
>>       int ctrl_id, ret;
>> +     struct device *dev = &host->pdev->dev;
>>
>> -     mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
>> +     mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), dev);
>>       if (!mmc)
>>               return -ENOMEM;
>>
>> @@ -1923,11 +1956,8 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>>       if (host->pdata->caps)
>>               mmc->caps = host->pdata->caps;
>>
>> -     if (host->dev->of_node) {
>> -             ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
>> -             if (ctrl_id < 0)
>> -                     ctrl_id = 0;
>> -     }
>> +     ctrl_id = dw_get_platform_device_id(host);
>> +
>>       if (host->drv_data->caps)
>>               mmc->caps |= host->drv_data->caps[ctrl_id];
>>
>> @@ -1937,9 +1967,9 @@ static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>>       if (host->pdata->get_bus_wd) {
>>               if (host->pdata->get_bus_wd(slot->id) >= 4)
>>                       mmc->caps |= MMC_CAP_4_BIT_DATA;
>> -     } else if (host->dev->of_node) {
>> +     } else if (dev->of_node) {
>>               unsigned int bus_width;
>> -             bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id);
>> +             bus_width = dw_mci_of_get_bus_wd(dev, slot->id);
>>               switch (bus_width) {
>>               case 8:
>>                       mmc->caps |= MMC_CAP_8_BIT_DATA;
>> @@ -2030,11 +2060,12 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
>>
>>  static void dw_mci_init_dma(struct dw_mci *host)
>>  {
>> +     struct device *dev = &host->pdev->dev;
>>       /* Alloc memory for sg translation */
>> -     host->sg_cpu = dma_alloc_coherent(host->dev, PAGE_SIZE,
>> +     host->sg_cpu = dma_alloc_coherent(dev, PAGE_SIZE,
>>                                         &host->sg_dma, GFP_KERNEL);
>>       if (!host->sg_cpu) {
>> -             dev_err(host->dev, "%s: could not alloc DMA memory\n",
>> +             dev_err(dev, "%s: could not alloc DMA memory\n",
>>                       __func__);
>>               goto no_dma;
>>       }
>> @@ -2050,12 +2081,12 @@ static void dw_mci_init_dma(struct dw_mci *host)
>>       if (host->dma_ops->init && host->dma_ops->start &&
>>           host->dma_ops->stop && host->dma_ops->cleanup) {
>>               if (host->dma_ops->init(host)) {
>> -                     dev_err(host->dev, "%s: Unable to initialize "
>> +                     dev_err(dev, "%s: Unable to initialize "
>>                               "DMA Controller.\n", __func__);
>>                       goto no_dma;
>>               }
>>       } else {
>> -             dev_err(host->dev, "DMA initialization not found.\n");
>> +             dev_err(dev, "DMA initialization not found.\n");
>>               goto no_dma;
>>       }
>>
>> @@ -2063,7 +2094,7 @@ static void dw_mci_init_dma(struct dw_mci *host)
>>       return;
>>
>>  no_dma:
>> -     dev_info(host->dev, "Using PIO mode.\n");
>> +     dev_info(dev, "Using PIO mode.\n");
>>       host->use_dma = 0;
>>       return;
>>  }
>> @@ -2109,7 +2140,7 @@ static struct dw_mci_of_quirks {
>>  static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
>>  {
>>       struct dw_mci_board *pdata;
>> -     struct device *dev = host->dev;
>> +     struct device *dev = &host->pdev->dev;
>>       struct device_node *np = dev->of_node;
>>       u32 timing[3];
>>       int idx, cnt;
>> @@ -2166,33 +2197,34 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
>>
>>  int dw_mci_probe(struct dw_mci *host)
>>  {
>> -     int width, i, ret = 0;
>> +     int width, i, ctrl_id, ret = 0;
>>       u32 fifo_size;
>>       int init_slots = 0;
>> +     struct device *dev = &host->pdev->dev;
>>
>>       if (!host->pdata) {
>>               host->pdata = dw_mci_parse_dt(host);
>>               if (IS_ERR(host->pdata)) {
>> -                     dev_err(host->dev, "platform data not available\n");
>> +                     dev_err(dev, "platform data not available\n");
>>                       return -EINVAL;
>>               }
>>       }
>>
>>       if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
>> -             dev_err(host->dev,
>> +             dev_err(dev,
>>                       "Platform data must supply select_slot function\n");
>>               return -ENODEV;
>>       }
>>
>> -     host->biu_clk = clk_get(host->dev, "biu");
>> +     host->biu_clk = clk_get(dev, "biu");
>>       if (IS_ERR(host->biu_clk))
>> -             dev_dbg(host->dev, "biu clock not available\n");
>> +             dev_dbg(dev, "biu clock not available\n");
>>       else
>>               clk_prepare_enable(host->biu_clk);
>>
>> -     host->ciu_clk = clk_get(host->dev, "ciu");
>> +     host->ciu_clk = clk_get(dev, "ciu");
>>       if (IS_ERR(host->ciu_clk))
>> -             dev_dbg(host->dev, "ciu clock not available\n");
>> +             dev_dbg(dev, "ciu clock not available\n");
>>       else
>>               clk_prepare_enable(host->ciu_clk);
>>
>> @@ -2202,7 +2234,7 @@ int dw_mci_probe(struct dw_mci *host)
>>               host->bus_hz = clk_get_rate(host->ciu_clk);
>>
>>       if (!host->bus_hz) {
>> -             dev_err(host->dev,
>> +             dev_err(dev,
>>                       "Platform data must supply bus speed\n");
>>               ret = -ENODEV;
>>               goto err_clk;
>> @@ -2210,6 +2242,11 @@ int dw_mci_probe(struct dw_mci *host)
>>
>>       host->quirks = host->pdata->quirks;
>>
>> +     ctrl_id = dw_get_platform_device_id(host);
>> +
>> +     if (host->drv_data->quirks)
>> +             host->quirks |= host->drv_data->quirks[ctrl_id];
>> +
>>       spin_lock_init(&host->lock);
>>       INIT_LIST_HEAD(&host->queue);
>>
>> @@ -2243,7 +2280,7 @@ int dw_mci_probe(struct dw_mci *host)
>>       }
>>
>>       /* Reset all blocks */
>> -     if (!mci_wait_reset(host->dev, host))
>> +     if (!mci_wait_reset(dev, host))
>>               return -ENODEV;
>>
>>       host->dma_ops = host->pdata->dma_ops;
>> @@ -2300,15 +2337,15 @@ int dw_mci_probe(struct dw_mci *host)
>>       for (i = 0; i < host->num_slots; i++) {
>>               ret = dw_mci_init_slot(host, i);
>>               if (ret)
>> -                     dev_dbg(host->dev, "slot %d init failed\n", i);
>> +                     dev_dbg(dev, "slot %d init failed\n", i);
>>               else
>>                       init_slots++;
>>       }
>>
>>       if (init_slots) {
>> -             dev_info(host->dev, "%d slots initialized\n", init_slots);
>> +             dev_info(dev, "%d slots initialized\n", init_slots);
>>       } else {
>> -             dev_dbg(host->dev, "attempted to initialize %d slots, "
>> +             dev_dbg(dev, "attempted to initialize %d slots, "
>>                                       "but failed on all\n", host->num_slots);
>>               goto err_init_slot;
>>       }
>> @@ -2318,7 +2355,7 @@ int dw_mci_probe(struct dw_mci *host)
>>        * Need to check the version-id and set data-offset for DATA register.
>>        */
>>       host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
>> -     dev_info(host->dev, "Version ID is %04x\n", host->verid);
>> +     dev_info(dev, "Version ID is %04x\n", host->verid);
>>
>>       if (host->verid < DW_MMC_240A)
>>               host->data_offset = DATA_OFFSET;
>> @@ -2335,12 +2372,12 @@ int dw_mci_probe(struct dw_mci *host)
>>                  DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
>>       mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
>>
>> -     dev_info(host->dev, "DW MMC controller at irq %d, "
>> +     dev_info(dev, "DW MMC controller at irq %d, "
>>                "%d bit host data width, "
>>                "%u deep fifo\n",
>>                host->irq, width, fifo_size);
>>       if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
>> -             dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");
>> +             dev_info(dev, "Internal DMAC interrupt fix enabled.\n");
>>
>>       return 0;
>>
>> @@ -2353,7 +2390,7 @@ err_workqueue:
>>  err_dmaunmap:
>>       if (host->use_dma && host->dma_ops->exit)
>>               host->dma_ops->exit(host);
>> -     dma_free_coherent(host->dev, PAGE_SIZE,
>> +     dma_free_coherent(dev, PAGE_SIZE,
>>                         host->sg_cpu, host->sg_dma);
>>
>>       if (host->vmmc) {
>> @@ -2377,23 +2414,23 @@ EXPORT_SYMBOL(dw_mci_probe);
>>  void dw_mci_remove(struct dw_mci *host)
>>  {
>>       int i;
>> +     struct device *dev = &host->pdev->dev;
>>
>>       mci_writel(host, RINTSTS, 0xFFFFFFFF);
>>       mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
>>
>>       for (i = 0; i < host->num_slots; i++) {
>> -             dev_dbg(host->dev, "remove slot %d\n", i);
>> +             dev_dbg(dev, "remove slot %d\n", i);
>>               if (host->slot[i])
>>                       dw_mci_cleanup_slot(host->slot[i], i);
>>       }
>> -
>>       /* disable clock to CIU */
>>       mci_writel(host, CLKENA, 0);
>>       mci_writel(host, CLKSRC, 0);
>>
>>       free_irq(host->irq, host);
>>       destroy_workqueue(host->card_workqueue);
>> -     dma_free_coherent(host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
>> +     dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
>>
>>       if (host->use_dma && host->dma_ops->exit)
>>               host->dma_ops->exit(host);
>> @@ -2451,7 +2488,7 @@ int dw_mci_resume(struct dw_mci *host)
>>       if (host->vmmc)
>>               regulator_enable(host->vmmc);
>>
>> -     if (!mci_wait_reset(host->dev, host)) {
>> +     if (!mci_wait_reset(&host->pdev->dev, host)) {
>>               ret = -ENODEV;
>>               return ret;
>>       }
>> @@ -2483,7 +2520,7 @@ EXPORT_SYMBOL(dw_mci_resume);
>>
>>  static int __init dw_mci_init(void)
>>  {
>> -     printk(KERN_INFO "Synopsys Designware Multimedia Card Interface Driver");
>> +     pr_info("Synopsys Designware Multimedia Card Interface Driver");
>>       return 0;
>>  }
>>
>> diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
>> index 6c17282..a3d684b 100644
>> --- a/drivers/mmc/host/dw_mmc.h
>> +++ b/drivers/mmc/host/dw_mmc.h
>> @@ -203,6 +203,7 @@ extern int dw_mci_resume(struct dw_mci *host);
>>  struct dw_mci_drv_data {
>>       unsigned long           ctrl_type;
>>       unsigned long           *caps;
>> +     unsigned long           *quirks;
>>  };
>>
>>  #endif /* _DW_MMC_H_ */
>> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
>> index 32c778f..03c409b 100644
>> --- a/include/linux/mmc/dw_mmc.h
>> +++ b/include/linux/mmc/dw_mmc.h
>> @@ -161,7 +161,7 @@ struct dw_mci {
>>       u32                     fifoth_val;
>>       u16                     verid;
>>       u16                     data_offset;
>> -     struct device           *dev;
>> +     struct platform_device  *pdev;
>>       struct dw_mci_board     *pdata;
>>       struct dw_mci_drv_data  *drv_data;
>>       struct clk              *biu_clk;
>> @@ -215,6 +215,8 @@ struct dw_mci_dma_ops {
>>  #define DW_MCI_QUIRK_BROKEN_CARD_DETECTION   BIT(3)
>>  /* Write Protect detection not available */
>>  #define DW_MCI_QUIRK_NO_WRITE_PROTECT                BIT(4)
>> +/* HCON Register's IDMAC information broken */
>> +#define DW_MCI_QUIRK_NO_HCON_DMA_INFO                BIT(5)
>>
>>  struct dma_pdata;
>>
>> --
>> 1.7.4.1
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 900f412..7d31e90 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -35,9 +35,17 @@  static unsigned long exynos5250_dwmmc_caps[4] = {
 	MMC_CAP_CMD23,
 };
 
+static unsigned long exynos5250_dwmmc_quirks[4] = {
+	DW_MCI_QUIRK_NO_HCON_DMA_INFO,
+	DW_MCI_QUIRK_NO_HCON_DMA_INFO,
+	DW_MCI_QUIRK_NO_HCON_DMA_INFO,
+	DW_MCI_QUIRK_NO_HCON_DMA_INFO,
+};
+
 static struct dw_mci_drv_data exynos5250_drv_data = {
 	.ctrl_type	= DW_MCI_TYPE_EXYNOS5250,
 	.caps		= exynos5250_dwmmc_caps,
+	.quirks		= exynos5250_dwmmc_quirks,
 };
 
 static const struct of_device_id dw_mci_pltfm_match[] = {
@@ -74,7 +82,7 @@  static int dw_mci_pltfm_probe(struct platform_device *pdev)
 		goto err_free;
 	}
 
-	host->dev = &pdev->dev;
+	host->pdev = pdev;
 	host->irq_flags = 0;
 	host->pdata = pdev->dev.platform_data;
 	ret = -ENOMEM;
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 000da16..b32e200 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -283,8 +283,10 @@  static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
 static void dw_mci_start_command(struct dw_mci *host,
 				 struct mmc_command *cmd, u32 cmd_flags)
 {
+	struct device *dev = &host->pdev->dev;
+
 	host->cmd = cmd;
-	dev_vdbg(host->dev,
+	dev_vdbg(dev,
 		 "start command: ARGR=0x%08x CMDR=0x%08x\n",
 		 cmd->arg, cmd_flags);
 
@@ -323,10 +325,11 @@  static int dw_mci_get_dma_dir(struct mmc_data *data)
 static void dw_mci_dma_cleanup(struct dw_mci *host)
 {
 	struct mmc_data *data = host->data;
+	struct device *dev = &host->pdev->dev;
 
 	if (data)
 		if (!data->host_cookie)
-			dma_unmap_sg(host->dev,
+			dma_unmap_sg(dev,
 				     data->sg,
 				     data->sg_len,
 				     dw_mci_get_dma_dir(data));
@@ -351,8 +354,9 @@  static void dw_mci_idmac_stop_dma(struct dw_mci *host)
 static void dw_mci_idmac_complete_dma(struct dw_mci *host)
 {
 	struct mmc_data *data = host->data;
+	struct device *dev = &host->pdev->dev;
 
-	dev_vdbg(host->dev, "DMA complete\n");
+	dev_vdbg(dev, "DMA complete\n");
 
 	host->dma_ops->cleanup(host);
 
@@ -420,10 +424,27 @@  static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
 	mci_writel(host, PLDMND, 1);
 }
 
+static int dw_get_platform_device_id(struct dw_mci *host)
+{
+	int ctrl_id;
+	struct device *dev = &host->pdev->dev;
+
+	if (dev->of_node)
+		ctrl_id = of_alias_get_id(dev->of_node, "mshc");
+	else
+		ctrl_id = host->pdev->id;
+
+	if (ctrl_id < 0)
+		ctrl_id = 0;
+
+	return ctrl_id;
+}
+
 static int dw_mci_idmac_init(struct dw_mci *host)
 {
 	struct idmac_desc *p;
 	int i, dma_support;
+	struct device *dev = &host->pdev->dev;
 
 	/* Number of descriptors in the ring buffer */
 	host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
@@ -431,14 +452,20 @@  static int dw_mci_idmac_init(struct dw_mci *host)
 	/* Check if Hardware Configuration Register has support for DMA */
 	dma_support = (mci_readl(host, HCON) >> 16) & 0x3;
 
-	if (!dma_support || dma_support > 2) {
-		dev_err(&host->dev,
+	/*
+	 * In Some of the Soc's the HCON Register is broken. Even though the
+	 * Soc's has a internal DMA the HCON register's DMA field doesnt
+	 * show it. So additional quirk is added for such Soc's
+	 */
+	if ((!dma_support || dma_support > 2) &&
+	    !(host->quirks & DW_MCI_QUIRK_NO_HCON_DMA_INFO)) {
+		dev_err(dev,
 			"Host Controller does not support IDMA Tx.\n");
 		host->dma_ops = NULL;
 		return -ENODEV;
 	}
 
-	dev_info(&host->dev, "Using internal DMA controller.\n");
+	dev_info(dev, "Using internal DMA controller.\n");
 
 	/* Forward link the descriptor list */
 	for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
@@ -474,6 +501,7 @@  static int dw_mci_pre_dma_transfer(struct dw_mci *host,
 {
 	struct scatterlist *sg;
 	unsigned int i, sg_len;
+	struct device *dev = &host->pdev->dev;
 
 	if (!next && data->host_cookie)
 		return data->host_cookie;
@@ -494,7 +522,7 @@  static int dw_mci_pre_dma_transfer(struct dw_mci *host,
 			return -EINVAL;
 	}
 
-	sg_len = dma_map_sg(host->dev,
+	sg_len = dma_map_sg(dev,
 			    data->sg,
 			    data->sg_len,
 			    dw_mci_get_dma_dir(data));
@@ -532,12 +560,13 @@  static void dw_mci_post_req(struct mmc_host *mmc,
 {
 	struct dw_mci_slot *slot = mmc_priv(mmc);
 	struct mmc_data *data = mrq->data;
+	struct device *dev = &slot->host->pdev->dev;
 
 	if (!slot->host->use_dma || !data)
 		return;
 
 	if (data->host_cookie)
-		dma_unmap_sg(slot->host->dev,
+		dma_unmap_sg(dev,
 			     data->sg,
 			     data->sg_len,
 			     dw_mci_get_dma_dir(data));
@@ -548,6 +577,7 @@  static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
 {
 	int sg_len;
 	u32 temp;
+	struct device *dev = &host->pdev->dev;
 
 	host->using_dma = 0;
 
@@ -563,7 +593,7 @@  static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
 
 	host->using_dma = 1;
 
-	dev_vdbg(host->dev,
+	dev_vdbg(dev,
 		 "sd sg_cpu: %#lx sg_dma: %#lx sg_len: %d\n",
 		 (unsigned long)host->sg_cpu, (unsigned long)host->sg_dma,
 		 sg_len);
@@ -928,6 +958,7 @@  static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
 {
 	struct dw_mci_slot *slot;
 	struct mmc_host	*prev_mmc = host->cur_slot->mmc;
+	struct device *dev = &host->pdev->dev;
 
 	WARN_ON(host->cmd || host->data);
 
@@ -937,12 +968,12 @@  static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
 		slot = list_entry(host->queue.next,
 				  struct dw_mci_slot, queue_node);
 		list_del(&slot->queue_node);
-		dev_vdbg(host->dev, "list not empty: %s is next\n",
+		dev_vdbg(dev, "list not empty: %s is next\n",
 			 mmc_hostname(slot->mmc));
 		host->state = STATE_SENDING_CMD;
 		dw_mci_start_request(host, slot);
 	} else {
-		dev_vdbg(host->dev, "list empty\n");
+		dev_vdbg(dev, "list empty\n");
 		host->state = STATE_IDLE;
 	}
 
@@ -1081,7 +1112,7 @@  static void dw_mci_tasklet_func(unsigned long priv)
 					data->bytes_xfered = 0;
 					data->error = -ETIMEDOUT;
 				} else {
-					dev_err(host->dev,
+					dev_err(&host->pdev->dev,
 						"data FIFO error "
 						"(status=%08x)\n",
 						status);
@@ -1829,7 +1860,8 @@  static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
 
 static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
 {
-	struct device_node *np = dw_mci_of_find_slot_node(host->dev, slot);
+	struct device *dev = &host->pdev->dev;
+	struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
 	int idx, gpio, ret;
 
 	if (!np)
@@ -1838,13 +1870,13 @@  static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
 	for (idx = 0; idx < NUM_PINS(bus_wd); idx++) {
 		gpio = of_get_gpio(np, idx);
 		if (!gpio_is_valid(gpio)) {
-			dev_err(host->dev, "invalid gpio: %d\n", gpio);
+			dev_err(dev, "invalid gpio: %d\n", gpio);
 			return -EINVAL;
 		}
 
-		ret = devm_gpio_request(host->dev, gpio, "dw-mci-bus");
+		ret = devm_gpio_request(dev, gpio, "dw-mci-bus");
 		if (ret) {
-			dev_err(host->dev, "gpio [%d] request failed\n", gpio);
+			dev_err(dev, "gpio [%d] request failed\n", gpio);
 			return -EBUSY;
 		}
 	}
@@ -1852,11 +1884,11 @@  static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
 	host->slot[slot]->wp_gpio = -1;
 	gpio = of_get_named_gpio(np, "wp-gpios", 0);
 	if (!gpio_is_valid(gpio)) {
-		dev_info(host->dev, "wp gpio not available");
+		dev_info(dev, "wp gpio not available");
 	} else {
-		ret = devm_gpio_request(host->dev, gpio, "dw-mci-wp");
+		ret = devm_gpio_request(dev, gpio, "dw-mci-wp");
 		if (ret)
-			dev_info(host->dev, "gpio [%d] request failed\n",
+			dev_info(dev, "gpio [%d] request failed\n",
 						gpio);
 		else
 			host->slot[slot]->wp_gpio = gpio;
@@ -1865,11 +1897,11 @@  static int dw_mci_of_setup_bus(struct dw_mci *host, u8 slot, u32 bus_wd)
 	host->slot[slot]->cd_gpio = -1;
 	gpio = of_get_named_gpio(np, "cd-gpios", 0);
 	if (!gpio_is_valid(gpio)) {
-		dev_info(host->dev, "cd gpio not available");
+		dev_info(dev, "cd gpio not available");
 	} else {
-		ret = devm_gpio_request(host->dev, gpio, "dw-mci-cd");
+		ret = devm_gpio_request(dev, gpio, "dw-mci-cd");
 		if (ret)
-			dev_err(host->dev, "gpio [%d] request failed\n", gpio);
+			dev_err(dev, "gpio [%d] request failed\n", gpio);
 		else
 			host->slot[slot]->cd_gpio = gpio;
 	}
@@ -1893,8 +1925,9 @@  static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	struct mmc_host *mmc;
 	struct dw_mci_slot *slot;
 	int ctrl_id, ret;
+	struct device *dev = &host->pdev->dev;
 
-	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
+	mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), dev);
 	if (!mmc)
 		return -ENOMEM;
 
@@ -1923,11 +1956,8 @@  static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	if (host->pdata->caps)
 		mmc->caps = host->pdata->caps;
 
-	if (host->dev->of_node) {
-		ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
-		if (ctrl_id < 0)
-			ctrl_id = 0;
-	}
+	ctrl_id = dw_get_platform_device_id(host);
+
 	if (host->drv_data->caps)
 		mmc->caps |= host->drv_data->caps[ctrl_id];
 
@@ -1937,9 +1967,9 @@  static int __init dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 	if (host->pdata->get_bus_wd) {
 		if (host->pdata->get_bus_wd(slot->id) >= 4)
 			mmc->caps |= MMC_CAP_4_BIT_DATA;
-	} else if (host->dev->of_node) {
+	} else if (dev->of_node) {
 		unsigned int bus_width;
-		bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id);
+		bus_width = dw_mci_of_get_bus_wd(dev, slot->id);
 		switch (bus_width) {
 		case 8:
 			mmc->caps |= MMC_CAP_8_BIT_DATA;
@@ -2030,11 +2060,12 @@  static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
 
 static void dw_mci_init_dma(struct dw_mci *host)
 {
+	struct device *dev = &host->pdev->dev;
 	/* Alloc memory for sg translation */
-	host->sg_cpu = dma_alloc_coherent(host->dev, PAGE_SIZE,
+	host->sg_cpu = dma_alloc_coherent(dev, PAGE_SIZE,
 					  &host->sg_dma, GFP_KERNEL);
 	if (!host->sg_cpu) {
-		dev_err(host->dev, "%s: could not alloc DMA memory\n",
+		dev_err(dev, "%s: could not alloc DMA memory\n",
 			__func__);
 		goto no_dma;
 	}
@@ -2050,12 +2081,12 @@  static void dw_mci_init_dma(struct dw_mci *host)
 	if (host->dma_ops->init && host->dma_ops->start &&
 	    host->dma_ops->stop && host->dma_ops->cleanup) {
 		if (host->dma_ops->init(host)) {
-			dev_err(host->dev, "%s: Unable to initialize "
+			dev_err(dev, "%s: Unable to initialize "
 				"DMA Controller.\n", __func__);
 			goto no_dma;
 		}
 	} else {
-		dev_err(host->dev, "DMA initialization not found.\n");
+		dev_err(dev, "DMA initialization not found.\n");
 		goto no_dma;
 	}
 
@@ -2063,7 +2094,7 @@  static void dw_mci_init_dma(struct dw_mci *host)
 	return;
 
 no_dma:
-	dev_info(host->dev, "Using PIO mode.\n");
+	dev_info(dev, "Using PIO mode.\n");
 	host->use_dma = 0;
 	return;
 }
@@ -2109,7 +2140,7 @@  static struct dw_mci_of_quirks {
 static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
 {
 	struct dw_mci_board *pdata;
-	struct device *dev = host->dev;
+	struct device *dev = &host->pdev->dev;
 	struct device_node *np = dev->of_node;
 	u32 timing[3];
 	int idx, cnt;
@@ -2166,33 +2197,34 @@  static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
 
 int dw_mci_probe(struct dw_mci *host)
 {
-	int width, i, ret = 0;
+	int width, i, ctrl_id, ret = 0;
 	u32 fifo_size;
 	int init_slots = 0;
+	struct device *dev = &host->pdev->dev;
 
 	if (!host->pdata) {
 		host->pdata = dw_mci_parse_dt(host);
 		if (IS_ERR(host->pdata)) {
-			dev_err(host->dev, "platform data not available\n");
+			dev_err(dev, "platform data not available\n");
 			return -EINVAL;
 		}
 	}
 
 	if (!host->pdata->select_slot && host->pdata->num_slots > 1) {
-		dev_err(host->dev,
+		dev_err(dev,
 			"Platform data must supply select_slot function\n");
 		return -ENODEV;
 	}
 
-	host->biu_clk = clk_get(host->dev, "biu");
+	host->biu_clk = clk_get(dev, "biu");
 	if (IS_ERR(host->biu_clk))
-		dev_dbg(host->dev, "biu clock not available\n");
+		dev_dbg(dev, "biu clock not available\n");
 	else
 		clk_prepare_enable(host->biu_clk);
 
-	host->ciu_clk = clk_get(host->dev, "ciu");
+	host->ciu_clk = clk_get(dev, "ciu");
 	if (IS_ERR(host->ciu_clk))
-		dev_dbg(host->dev, "ciu clock not available\n");
+		dev_dbg(dev, "ciu clock not available\n");
 	else
 		clk_prepare_enable(host->ciu_clk);
 
@@ -2202,7 +2234,7 @@  int dw_mci_probe(struct dw_mci *host)
 		host->bus_hz = clk_get_rate(host->ciu_clk);
 
 	if (!host->bus_hz) {
-		dev_err(host->dev,
+		dev_err(dev,
 			"Platform data must supply bus speed\n");
 		ret = -ENODEV;
 		goto err_clk;
@@ -2210,6 +2242,11 @@  int dw_mci_probe(struct dw_mci *host)
 
 	host->quirks = host->pdata->quirks;
 
+	ctrl_id = dw_get_platform_device_id(host);
+
+	if (host->drv_data->quirks)
+		host->quirks |= host->drv_data->quirks[ctrl_id];
+
 	spin_lock_init(&host->lock);
 	INIT_LIST_HEAD(&host->queue);
 
@@ -2243,7 +2280,7 @@  int dw_mci_probe(struct dw_mci *host)
 	}
 
 	/* Reset all blocks */
-	if (!mci_wait_reset(host->dev, host))
+	if (!mci_wait_reset(dev, host))
 		return -ENODEV;
 
 	host->dma_ops = host->pdata->dma_ops;
@@ -2300,15 +2337,15 @@  int dw_mci_probe(struct dw_mci *host)
 	for (i = 0; i < host->num_slots; i++) {
 		ret = dw_mci_init_slot(host, i);
 		if (ret)
-			dev_dbg(host->dev, "slot %d init failed\n", i);
+			dev_dbg(dev, "slot %d init failed\n", i);
 		else
 			init_slots++;
 	}
 
 	if (init_slots) {
-		dev_info(host->dev, "%d slots initialized\n", init_slots);
+		dev_info(dev, "%d slots initialized\n", init_slots);
 	} else {
-		dev_dbg(host->dev, "attempted to initialize %d slots, "
+		dev_dbg(dev, "attempted to initialize %d slots, "
 					"but failed on all\n", host->num_slots);
 		goto err_init_slot;
 	}
@@ -2318,7 +2355,7 @@  int dw_mci_probe(struct dw_mci *host)
 	 * Need to check the version-id and set data-offset for DATA register.
 	 */
 	host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
-	dev_info(host->dev, "Version ID is %04x\n", host->verid);
+	dev_info(dev, "Version ID is %04x\n", host->verid);
 
 	if (host->verid < DW_MMC_240A)
 		host->data_offset = DATA_OFFSET;
@@ -2335,12 +2372,12 @@  int dw_mci_probe(struct dw_mci *host)
 		   DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
 	mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
 
-	dev_info(host->dev, "DW MMC controller at irq %d, "
+	dev_info(dev, "DW MMC controller at irq %d, "
 		 "%d bit host data width, "
 		 "%u deep fifo\n",
 		 host->irq, width, fifo_size);
 	if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
-		dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");
+		dev_info(dev, "Internal DMAC interrupt fix enabled.\n");
 
 	return 0;
 
@@ -2353,7 +2390,7 @@  err_workqueue:
 err_dmaunmap:
 	if (host->use_dma && host->dma_ops->exit)
 		host->dma_ops->exit(host);
-	dma_free_coherent(host->dev, PAGE_SIZE,
+	dma_free_coherent(dev, PAGE_SIZE,
 			  host->sg_cpu, host->sg_dma);
 
 	if (host->vmmc) {
@@ -2377,23 +2414,23 @@  EXPORT_SYMBOL(dw_mci_probe);
 void dw_mci_remove(struct dw_mci *host)
 {
 	int i;
+	struct device *dev = &host->pdev->dev;
 
 	mci_writel(host, RINTSTS, 0xFFFFFFFF);
 	mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
 
 	for (i = 0; i < host->num_slots; i++) {
-		dev_dbg(host->dev, "remove slot %d\n", i);
+		dev_dbg(dev, "remove slot %d\n", i);
 		if (host->slot[i])
 			dw_mci_cleanup_slot(host->slot[i], i);
 	}
-
 	/* disable clock to CIU */
 	mci_writel(host, CLKENA, 0);
 	mci_writel(host, CLKSRC, 0);
 
 	free_irq(host->irq, host);
 	destroy_workqueue(host->card_workqueue);
-	dma_free_coherent(host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
+	dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
 
 	if (host->use_dma && host->dma_ops->exit)
 		host->dma_ops->exit(host);
@@ -2451,7 +2488,7 @@  int dw_mci_resume(struct dw_mci *host)
 	if (host->vmmc)
 		regulator_enable(host->vmmc);
 
-	if (!mci_wait_reset(host->dev, host)) {
+	if (!mci_wait_reset(&host->pdev->dev, host)) {
 		ret = -ENODEV;
 		return ret;
 	}
@@ -2483,7 +2520,7 @@  EXPORT_SYMBOL(dw_mci_resume);
 
 static int __init dw_mci_init(void)
 {
-	printk(KERN_INFO "Synopsys Designware Multimedia Card Interface Driver");
+	pr_info("Synopsys Designware Multimedia Card Interface Driver");
 	return 0;
 }
 
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 6c17282..a3d684b 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -203,6 +203,7 @@  extern int dw_mci_resume(struct dw_mci *host);
 struct dw_mci_drv_data {
 	unsigned long		ctrl_type;
 	unsigned long		*caps;
+	unsigned long		*quirks;
 };
 
 #endif /* _DW_MMC_H_ */
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 32c778f..03c409b 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -161,7 +161,7 @@  struct dw_mci {
 	u32			fifoth_val;
 	u16			verid;
 	u16			data_offset;
-	struct device		*dev;
+	struct platform_device	*pdev;
 	struct dw_mci_board	*pdata;
 	struct dw_mci_drv_data	*drv_data;
 	struct clk		*biu_clk;
@@ -215,6 +215,8 @@  struct dw_mci_dma_ops {
 #define DW_MCI_QUIRK_BROKEN_CARD_DETECTION	BIT(3)
 /* Write Protect detection not available */
 #define DW_MCI_QUIRK_NO_WRITE_PROTECT		BIT(4)
+/* HCON Register's IDMAC information broken */
+#define DW_MCI_QUIRK_NO_HCON_DMA_INFO		BIT(5)
 
 struct dma_pdata;