diff options
Diffstat (limited to 'drivers/mmc/host/dw_mmc.c')
| -rw-r--r-- | drivers/mmc/host/dw_mmc.c | 86 | 
1 files changed, 41 insertions, 45 deletions
| diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index c0667c8af2bd..323c5022c2ca 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -232,7 +232,7 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)  {  	struct mmc_data	*data;  	struct dw_mci_slot *slot = mmc_priv(mmc); -	struct dw_mci_drv_data *drv_data = slot->host->drv_data; +	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;  	u32 cmdr;  	cmd->error = -EINPROGRESS; @@ -617,13 +617,13 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)  		cmd, arg, cmd_status);  } -static void dw_mci_setup_bus(struct dw_mci_slot *slot) +static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)  {  	struct dw_mci *host = slot->host;  	u32 div;  	u32 clk_en_a; -	if (slot->clock != host->current_speed) { +	if (slot->clock != host->current_speed || force_clkinit) {  		div = host->bus_hz / slot->clock;  		if (host->bus_hz % slot->clock && host->bus_hz > slot->clock)  			/* @@ -683,9 +683,6 @@ static void __dw_mci_start_request(struct dw_mci *host,  	if (host->pdata->select_slot)  		host->pdata->select_slot(slot->id); -	/* Slot specific timing and width adjustment */ -	dw_mci_setup_bus(slot); -  	host->cur_slot = slot;  	host->mrq = mrq; @@ -773,22 +770,19 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)  static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)  {  	struct dw_mci_slot *slot = mmc_priv(mmc); -	struct dw_mci_drv_data *drv_data = slot->host->drv_data; +	const struct dw_mci_drv_data *drv_data = slot->host->drv_data;  	u32 regs; -	/* set default 1 bit mode */ -	slot->ctype = SDMMC_CTYPE_1BIT; -  	switch (ios->bus_width) { -	case MMC_BUS_WIDTH_1: -		slot->ctype = SDMMC_CTYPE_1BIT; -		break;  	case MMC_BUS_WIDTH_4:  		slot->ctype = SDMMC_CTYPE_4BIT;  		break;  	case MMC_BUS_WIDTH_8:  		slot->ctype = SDMMC_CTYPE_8BIT;  		break; +	default: +		/* set default 1 bit mode */ +		slot->ctype = SDMMC_CTYPE_1BIT;  	}  	regs = mci_readl(slot->host, UHS_REG); @@ -812,6 +806,9 @@ 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); +  	switch (ios->power_mode) {  	case MMC_POWER_UP:  		set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); @@ -1817,7 +1814,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)  {  	struct mmc_host *mmc;  	struct dw_mci_slot *slot; -	struct dw_mci_drv_data *drv_data = host->drv_data; +	const struct dw_mci_drv_data *drv_data = host->drv_data;  	int ctrl_id, ret;  	u8 bus_width; @@ -1850,6 +1847,9 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)  	if (host->pdata->caps)  		mmc->caps = host->pdata->caps; +	if (host->pdata->pm_caps) +		mmc->pm_caps = host->pdata->pm_caps; +  	if (host->dev->of_node) {  		ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");  		if (ctrl_id < 0) @@ -1911,7 +1911,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)  #endif /* CONFIG_MMC_DW_IDMAC */  	} -	host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); +	host->vmmc = devm_regulator_get(mmc_dev(mmc), "vmmc");  	if (IS_ERR(host->vmmc)) {  		pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));  		host->vmmc = NULL; @@ -1960,7 +1960,7 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)  static void dw_mci_init_dma(struct dw_mci *host)  {  	/* Alloc memory for sg translation */ -	host->sg_cpu = dma_alloc_coherent(host->dev, PAGE_SIZE, +	host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,  					  &host->sg_dma, GFP_KERNEL);  	if (!host->sg_cpu) {  		dev_err(host->dev, "%s: could not alloc DMA memory\n", @@ -2038,7 +2038,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)  	struct dw_mci_board *pdata;  	struct device *dev = host->dev;  	struct device_node *np = dev->of_node; -	struct dw_mci_drv_data *drv_data = host->drv_data; +	const struct dw_mci_drv_data *drv_data = host->drv_data;  	int idx, ret;  	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); @@ -2072,6 +2072,12 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)  			return ERR_PTR(ret);  	} +	if (of_find_property(np, "keep-power-in-suspend", NULL)) +		pdata->pm_caps |= MMC_PM_KEEP_POWER; + +	if (of_find_property(np, "enable-sdio-wakeup", NULL)) +		pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; +  	return pdata;  } @@ -2084,7 +2090,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)  int dw_mci_probe(struct dw_mci *host)  { -	struct dw_mci_drv_data *drv_data = host->drv_data; +	const struct dw_mci_drv_data *drv_data = host->drv_data;  	int width, i, ret = 0;  	u32 fifo_size;  	int init_slots = 0; @@ -2103,26 +2109,24 @@ int dw_mci_probe(struct dw_mci *host)  		return -ENODEV;  	} -	host->biu_clk = clk_get(host->dev, "biu"); +	host->biu_clk = devm_clk_get(host->dev, "biu");  	if (IS_ERR(host->biu_clk)) {  		dev_dbg(host->dev, "biu clock not available\n");  	} else {  		ret = clk_prepare_enable(host->biu_clk);  		if (ret) {  			dev_err(host->dev, "failed to enable biu clock\n"); -			clk_put(host->biu_clk);  			return ret;  		}  	} -	host->ciu_clk = clk_get(host->dev, "ciu"); +	host->ciu_clk = devm_clk_get(host->dev, "ciu");  	if (IS_ERR(host->ciu_clk)) {  		dev_dbg(host->dev, "ciu clock not available\n");  	} else {  		ret = clk_prepare_enable(host->ciu_clk);  		if (ret) {  			dev_err(host->dev, "failed to enable ciu clock\n"); -			clk_put(host->ciu_clk);  			goto err_clk_biu;  		}  	} @@ -2224,7 +2228,8 @@ int dw_mci_probe(struct dw_mci *host)  	if (!host->card_workqueue)  		goto err_dmaunmap;  	INIT_WORK(&host->card_work, dw_mci_work_routine_card); -	ret = request_irq(host->irq, dw_mci_interrupt, host->irq_flags, "dw-mci", host); +	ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt, +			       host->irq_flags, "dw-mci", host);  	if (ret)  		goto err_workqueue; @@ -2262,7 +2267,7 @@ int dw_mci_probe(struct dw_mci *host)  	} else {  		dev_dbg(host->dev, "attempted to initialize %d slots, "  					"but failed on all\n", host->num_slots); -		goto err_init_slot; +		goto err_workqueue;  	}  	/* @@ -2282,33 +2287,24 @@ int dw_mci_probe(struct dw_mci *host)  	return 0; -err_init_slot: -	free_irq(host->irq, host); -  err_workqueue:  	destroy_workqueue(host->card_workqueue);  err_dmaunmap:  	if (host->use_dma && host->dma_ops->exit)  		host->dma_ops->exit(host); -	dma_free_coherent(host->dev, PAGE_SIZE, -			  host->sg_cpu, host->sg_dma); -	if (host->vmmc) { +	if (host->vmmc)  		regulator_disable(host->vmmc); -		regulator_put(host->vmmc); -	}  err_clk_ciu: -	if (!IS_ERR(host->ciu_clk)) { +	if (!IS_ERR(host->ciu_clk))  		clk_disable_unprepare(host->ciu_clk); -		clk_put(host->ciu_clk); -	} +  err_clk_biu: -	if (!IS_ERR(host->biu_clk)) { +	if (!IS_ERR(host->biu_clk))  		clk_disable_unprepare(host->biu_clk); -		clk_put(host->biu_clk); -	} +  	return ret;  }  EXPORT_SYMBOL(dw_mci_probe); @@ -2330,24 +2326,19 @@ void dw_mci_remove(struct dw_mci *host)  	mci_writel(host, CLKENA, 0);  	mci_writel(host, CLKSRC, 0); -	free_irq(host->irq, host);  	destroy_workqueue(host->card_workqueue); -	dma_free_coherent(host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);  	if (host->use_dma && host->dma_ops->exit)  		host->dma_ops->exit(host); -	if (host->vmmc) { +	if (host->vmmc)  		regulator_disable(host->vmmc); -		regulator_put(host->vmmc); -	}  	if (!IS_ERR(host->ciu_clk))  		clk_disable_unprepare(host->ciu_clk); +  	if (!IS_ERR(host->biu_clk))  		clk_disable_unprepare(host->biu_clk); -	clk_put(host->ciu_clk); -	clk_put(host->biu_clk);  }  EXPORT_SYMBOL(dw_mci_remove); @@ -2411,6 +2402,11 @@ int dw_mci_resume(struct dw_mci *host)  		struct dw_mci_slot *slot = host->slot[i];  		if (!slot)  			continue; +		if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) { +			dw_mci_set_ios(slot->mmc, &slot->mmc->ios); +			dw_mci_setup_bus(slot, true); +		} +  		ret = mmc_resume_host(host->slot[i]->mmc);  		if (ret < 0)  			return ret; |