From 88ac2a2c30468bb9f750170d92f7dd1ab91ddcbb Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 11 Feb 2016 13:59:53 +0100 Subject: mmc: sh_mmcif: Make sure the device stays active when needed in ->probe() While accessing the device, make sure it stays active by increasing the runtime PM usage count for it. Let's also defer to enable runtime PM until we really need access to the device. This also enables the error path in ->probe() to become simpler. Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index d9a655f..ee59786 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1519,23 +1519,23 @@ static int sh_mmcif_probe(struct platform_device *pdev) platform_set_drvdata(pdev, host); - pm_runtime_enable(dev); - host->power = false; - host->clk = devm_clk_get(dev, NULL); if (IS_ERR(host->clk)) { ret = PTR_ERR(host->clk); dev_err(dev, "cannot get clock: %d\n", ret); - goto err_pm; + goto err_host; } ret = clk_prepare_enable(host->clk); if (ret < 0) - goto err_pm; + goto err_host; sh_mmcif_clk_setup(host); - ret = pm_runtime_resume(dev); + pm_runtime_enable(dev); + host->power = false; + + ret = pm_runtime_get_sync(dev); if (ret < 0) goto err_clk; @@ -1579,12 +1579,13 @@ static int sh_mmcif_probe(struct platform_device *pdev) sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0xffff, clk_get_rate(host->clk) / 1000000UL); + pm_runtime_put(dev); clk_disable_unprepare(host->clk); return ret; err_clk: clk_disable_unprepare(host->clk); -err_pm: + pm_runtime_put_sync(dev); pm_runtime_disable(dev); err_host: mmc_free_host(mmc); -- cgit v0.10.2 From 4caf653a55210dfc1c024d88e5148148f64802ad Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 11 Feb 2016 13:59:54 +0100 Subject: mmc: sh_mmcif: Restructure ->set_ios() Both from a runtime PM and clock management point of view, the ->set_ios() code is unnecessary complex. A suboptimal path is also executed when the mmc core requests a clock rate of zero. As that happens during the card initialization phase, trying to save power by decreasing the runtime PM usage count and gating the clock via clk_disable_unprepare() is just superfluous. Moreover, from a runtime PM point of view the core will anyway keep the device active during the entire card initialization phase. Restructure the code to rely on the ios->power_mode to understand when the runtime PM usage count needs to be increased. Let's also deal with clock rate changes by simply applying the rate. Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index ee59786..cdefb01 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -248,7 +248,6 @@ struct sh_mmcif_host { int sg_idx; int sg_blkidx; bool power; - bool card_present; bool ccs_enable; /* Command Completion Signal support */ bool clk_ctrl2_enable; struct mutex thread_lock; @@ -1091,42 +1090,30 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->state = STATE_IOS; spin_unlock_irqrestore(&host->lock, flags); - if (ios->power_mode == MMC_POWER_UP) { - if (!host->card_present) { - /* See if we also get DMA */ + switch (ios->power_mode) { + case MMC_POWER_UP: + sh_mmcif_set_power(host, ios); + if (!host->power) { + clk_prepare_enable(host->clk); + pm_runtime_get_sync(dev); + sh_mmcif_sync_reset(host); sh_mmcif_request_dma(host); - host->card_present = true; + host->power = true; } + break; + case MMC_POWER_OFF: sh_mmcif_set_power(host, ios); - } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) { - /* clock stop */ - sh_mmcif_clock_control(host, 0); - if (ios->power_mode == MMC_POWER_OFF) { - if (host->card_present) { - sh_mmcif_release_dma(host); - host->card_present = false; - } - } if (host->power) { - pm_runtime_put_sync(dev); + sh_mmcif_clock_control(host, 0); + sh_mmcif_release_dma(host); + pm_runtime_put(dev); clk_disable_unprepare(host->clk); host->power = false; - if (ios->power_mode == MMC_POWER_OFF) - sh_mmcif_set_power(host, ios); - } - host->state = STATE_IDLE; - return; - } - - if (ios->clock) { - if (!host->power) { - clk_prepare_enable(host->clk); - - pm_runtime_get_sync(dev); - host->power = true; - sh_mmcif_sync_reset(host); } + break; + case MMC_POWER_ON: sh_mmcif_clock_control(host, ios->clock); + break; } host->timing = ios->timing; -- cgit v0.10.2 From 33a31ceaf064cd62bf08e437b5849684da2ffe71 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 11 Feb 2016 13:59:55 +0100 Subject: mmc: sh_mmci: Get rid of wrapper function for regulators As there are two callers of sh_mmcif_set_power() and because its only additional action is to check for a valid regulator, let's just remove it. Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index cdefb01..dd64b86 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1063,16 +1063,6 @@ static void sh_mmcif_clk_setup(struct sh_mmcif_host *host) host->mmc->f_max, host->mmc->f_min); } -static void sh_mmcif_set_power(struct sh_mmcif_host *host, struct mmc_ios *ios) -{ - struct mmc_host *mmc = host->mmc; - - if (!IS_ERR(mmc->supply.vmmc)) - /* Errors ignored... */ - mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, - ios->power_mode ? ios->vdd : 0); -} - static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct sh_mmcif_host *host = mmc_priv(mmc); @@ -1092,7 +1082,8 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) switch (ios->power_mode) { case MMC_POWER_UP: - sh_mmcif_set_power(host, ios); + if (!IS_ERR(mmc->supply.vmmc)) + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); if (!host->power) { clk_prepare_enable(host->clk); pm_runtime_get_sync(dev); @@ -1102,7 +1093,8 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } break; case MMC_POWER_OFF: - sh_mmcif_set_power(host, ios); + if (!IS_ERR(mmc->supply.vmmc)) + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); if (host->power) { sh_mmcif_clock_control(host, 0); sh_mmcif_release_dma(host); -- cgit v0.10.2 From 0a4d7236c5852f1643dad3ea89002ab2620302c6 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 16 Mar 2016 22:45:31 -0500 Subject: mmc: davinci_mmc: Use dma_request_chan() to requesting DMA channel With the new dma_request_chan() the client driver does not need to look for the DMA resource and it does not need to pass filter_fn anymore. By switching to the new API the driver can now support deferred probing against DMA. Signed-off-by: Peter Ujfalusi Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 693144e..eb3ca9e 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -32,12 +32,10 @@ #include #include #include -#include #include #include #include -#include #include /* @@ -202,7 +200,6 @@ struct mmc_davinci_host { u32 buffer_bytes_left; u32 bytes_left; - u32 rxdma, txdma; struct dma_chan *dma_tx; struct dma_chan *dma_rx; bool use_dma; @@ -513,35 +510,20 @@ davinci_release_dma_channels(struct mmc_davinci_host *host) static int __init davinci_acquire_dma_channels(struct mmc_davinci_host *host) { - int r; - dma_cap_mask_t mask; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - host->dma_tx = - dma_request_slave_channel_compat(mask, edma_filter_fn, - &host->txdma, mmc_dev(host->mmc), "tx"); - if (!host->dma_tx) { + host->dma_tx = dma_request_chan(mmc_dev(host->mmc), "tx"); + if (IS_ERR(host->dma_tx)) { dev_err(mmc_dev(host->mmc), "Can't get dma_tx channel\n"); - return -ENODEV; + return PTR_ERR(host->dma_tx); } - host->dma_rx = - dma_request_slave_channel_compat(mask, edma_filter_fn, - &host->rxdma, mmc_dev(host->mmc), "rx"); - if (!host->dma_rx) { + host->dma_rx = dma_request_chan(mmc_dev(host->mmc), "rx"); + if (IS_ERR(host->dma_rx)) { dev_err(mmc_dev(host->mmc), "Can't get dma_rx channel\n"); - r = -ENODEV; - goto free_master_write; + dma_release_channel(host->dma_tx); + return PTR_ERR(host->dma_rx); } return 0; - -free_master_write: - dma_release_channel(host->dma_tx); - - return r; } /*----------------------------------------------------------------------*/ @@ -1253,18 +1235,6 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) host = mmc_priv(mmc); host->mmc = mmc; /* Important */ - r = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!r) - dev_warn(&pdev->dev, "RX DMA resource not specified\n"); - else - host->rxdma = r->start; - - r = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (!r) - dev_warn(&pdev->dev, "TX DMA resource not specified\n"); - else - host->txdma = r->start; - host->mem_res = mem; host->base = ioremap(mem->start, mem_size); if (!host->base) @@ -1291,8 +1261,13 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) host->mmc_irq = irq; host->sdio_irq = platform_get_irq(pdev, 1); - if (host->use_dma && davinci_acquire_dma_channels(host) != 0) - host->use_dma = 0; + if (host->use_dma) { + ret = davinci_acquire_dma_channels(host); + if (ret == -EPROBE_DEFER) + goto out; + else if (ret) + host->use_dma = 0; + } /* REVISIT: someday, support IRQ-driven card detection. */ mmc->caps |= MMC_CAP_NEEDS_POLL; -- cgit v0.10.2 From 673267f0bd606057bbc897aa7691e1eede8d3a58 Mon Sep 17 00:00:00 2001 From: David Lechner Date: Wed, 16 Mar 2016 22:45:32 -0500 Subject: mmc: davinci: remove matching string The string "MMCSDCLK" is not actually used for clock lookup, so can be removed. Signed-off-by: David Lechner Acked-by: Sekhar Nori Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index eb3ca9e..498c42d 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1241,7 +1241,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) goto out; ret = -ENXIO; - host->clk = clk_get(&pdev->dev, "MMCSDCLK"); + host->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(host->clk)) { ret = PTR_ERR(host->clk); goto out; -- cgit v0.10.2 From 1ca4d3596e419d65bbc6a1276b3f569c6c83510c Mon Sep 17 00:00:00 2001 From: Andreas Fenkart Date: Mon, 21 Mar 2016 00:58:08 +0100 Subject: mmc: omap_hsmmc: pass omap_hsmmc_host pointer directly unnecessary indirection via 'struct device' back to omap_hsmmc_host Signed-off-by: Andreas Fenkart Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index f9ac3bb..bcb02a6 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -351,15 +351,14 @@ static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on, return 0; } -static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) +static int omap_hsmmc_set_power(struct omap_hsmmc_host *host, int power_on, + int vdd) { - struct omap_hsmmc_host *host = - platform_get_drvdata(to_platform_device(dev)); struct mmc_host *mmc = host->mmc; int ret = 0; if (mmc_pdata(host)->set_power) - return mmc_pdata(host)->set_power(dev, power_on, vdd); + return mmc_pdata(host)->set_power(host->dev, power_on, vdd); /* * If we don't see a Vcc regulator, assume it's a fixed @@ -369,7 +368,7 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) return 0; if (mmc_pdata(host)->before_set_reg) - mmc_pdata(host)->before_set_reg(dev, power_on, vdd); + mmc_pdata(host)->before_set_reg(host->dev, power_on, vdd); ret = omap_hsmmc_set_pbias(host, false, 0); if (ret) @@ -403,7 +402,7 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) } if (mmc_pdata(host)->after_set_reg) - mmc_pdata(host)->after_set_reg(dev, power_on, vdd); + mmc_pdata(host)->after_set_reg(host->dev, power_on, vdd); return 0; @@ -1255,11 +1254,11 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) clk_disable_unprepare(host->dbclk); /* Turn the power off */ - ret = omap_hsmmc_set_power(host->dev, 0, 0); + ret = omap_hsmmc_set_power(host, 0, 0); /* Turn the power ON with given VDD 1.8 or 3.0v */ if (!ret) - ret = omap_hsmmc_set_power(host->dev, 1, vdd); + ret = omap_hsmmc_set_power(host, 1, vdd); pm_runtime_get_sync(host->dev); if (host->dbclk) clk_prepare_enable(host->dbclk); @@ -1658,10 +1657,10 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (ios->power_mode != host->power_mode) { switch (ios->power_mode) { case MMC_POWER_OFF: - omap_hsmmc_set_power(host->dev, 0, 0); + omap_hsmmc_set_power(host, 0, 0); break; case MMC_POWER_UP: - omap_hsmmc_set_power(host->dev, 1, ios->vdd); + omap_hsmmc_set_power(host, 1, ios->vdd); break; case MMC_POWER_ON: do_send_init_stream = 1; -- cgit v0.10.2 From 7962fc376f603547b130c0fd7932ac6e9df4ee8b Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Thu, 31 Mar 2016 11:16:27 +0800 Subject: mmc: core: Provide tracepoints for request processing This patch provides some tracepoints for the lifecycle of a mmc request from starting to completion to help with performance analysis of MMC subsystem. Signed-off-by: Baolin Wang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 41b1e76..f80b3ab 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -36,6 +36,9 @@ #include #include +#define CREATE_TRACE_POINTS +#include + #include "core.h" #include "bus.h" #include "host.h" @@ -140,6 +143,8 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) cmd->retries = 0; } + trace_mmc_request_done(host, mrq); + if (err && cmd->retries && !mmc_card_removed(host->card)) { /* * Request starter must handle retries - see @@ -215,6 +220,8 @@ static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq) } } + trace_mmc_request_start(host, mrq); + host->ops->request(host, mrq); } diff --git a/include/trace/events/mmc.h b/include/trace/events/mmc.h new file mode 100644 index 0000000..a72f9b9 --- /dev/null +++ b/include/trace/events/mmc.h @@ -0,0 +1,182 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mmc + +#if !defined(_TRACE_MMC_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_MMC_H + +#include +#include +#include +#include + +TRACE_EVENT(mmc_request_start, + + TP_PROTO(struct mmc_host *host, struct mmc_request *mrq), + + TP_ARGS(host, mrq), + + TP_STRUCT__entry( + __field(u32, cmd_opcode) + __field(u32, cmd_arg) + __field(unsigned int, cmd_flags) + __field(unsigned int, cmd_retries) + __field(u32, stop_opcode) + __field(u32, stop_arg) + __field(unsigned int, stop_flags) + __field(unsigned int, stop_retries) + __field(u32, sbc_opcode) + __field(u32, sbc_arg) + __field(unsigned int, sbc_flags) + __field(unsigned int, sbc_retries) + __field(unsigned int, blocks) + __field(unsigned int, blksz) + __field(unsigned int, data_flags) + __field(unsigned int, can_retune) + __field(unsigned int, doing_retune) + __field(unsigned int, retune_now) + __field(int, need_retune) + __field(int, hold_retune) + __field(unsigned int, retune_period) + __field(struct mmc_request *, mrq) + __string(name, mmc_hostname(host)) + ), + + TP_fast_assign( + __entry->cmd_opcode = mrq->cmd->opcode; + __entry->cmd_arg = mrq->cmd->arg; + __entry->cmd_flags = mrq->cmd->flags; + __entry->cmd_retries = mrq->cmd->retries; + __entry->stop_opcode = mrq->stop ? mrq->stop->opcode : 0; + __entry->stop_arg = mrq->stop ? mrq->stop->arg : 0; + __entry->stop_flags = mrq->stop ? mrq->stop->flags : 0; + __entry->stop_retries = mrq->stop ? mrq->stop->retries : 0; + __entry->sbc_opcode = mrq->sbc ? mrq->sbc->opcode : 0; + __entry->sbc_arg = mrq->sbc ? mrq->sbc->arg : 0; + __entry->sbc_flags = mrq->sbc ? mrq->sbc->flags : 0; + __entry->sbc_retries = mrq->sbc ? mrq->sbc->retries : 0; + __entry->blksz = mrq->data ? mrq->data->blksz : 0; + __entry->blocks = mrq->data ? mrq->data->blocks : 0; + __entry->data_flags = mrq->data ? mrq->data->flags : 0; + __entry->can_retune = host->can_retune; + __entry->doing_retune = host->doing_retune; + __entry->retune_now = host->retune_now; + __entry->need_retune = host->need_retune; + __entry->hold_retune = host->hold_retune; + __entry->retune_period = host->retune_period; + __assign_str(name, mmc_hostname(host)); + __entry->mrq = mrq; + ), + + TP_printk("%s: start struct mmc_request[%p]: " + "cmd_opcode=%u cmd_arg=0x%x cmd_flags=0x%x cmd_retries=%u " + "stop_opcode=%u stop_arg=0x%x stop_flags=0x%x stop_retries=%u " + "sbc_opcode=%u sbc_arg=0x%x sbc_flags=0x%x sbc_retires=%u " + "blocks=%u block_size=%u data_flags=0x%x " + "can_retune=%u doing_retune=%u retune_now=%u " + "need_retune=%d hold_retune=%d retune_period=%u", + __get_str(name), __entry->mrq, + __entry->cmd_opcode, __entry->cmd_arg, + __entry->cmd_flags, __entry->cmd_retries, + __entry->stop_opcode, __entry->stop_arg, + __entry->stop_flags, __entry->stop_retries, + __entry->sbc_opcode, __entry->sbc_arg, + __entry->sbc_flags, __entry->sbc_retries, + __entry->blocks, __entry->blksz, __entry->data_flags, + __entry->can_retune, __entry->doing_retune, + __entry->retune_now, __entry->need_retune, + __entry->hold_retune, __entry->retune_period) +); + +TRACE_EVENT(mmc_request_done, + + TP_PROTO(struct mmc_host *host, struct mmc_request *mrq), + + TP_ARGS(host, mrq), + + TP_STRUCT__entry( + __field(u32, cmd_opcode) + __field(int, cmd_err) + __array(u32, cmd_resp, 4) + __field(unsigned int, cmd_retries) + __field(u32, stop_opcode) + __field(int, stop_err) + __array(u32, stop_resp, 4) + __field(unsigned int, stop_retries) + __field(u32, sbc_opcode) + __field(int, sbc_err) + __array(u32, sbc_resp, 4) + __field(unsigned int, sbc_retries) + __field(unsigned int, bytes_xfered) + __field(int, data_err) + __field(unsigned int, can_retune) + __field(unsigned int, doing_retune) + __field(unsigned int, retune_now) + __field(int, need_retune) + __field(int, hold_retune) + __field(unsigned int, retune_period) + __field(struct mmc_request *, mrq) + __string(name, mmc_hostname(host)) + ), + + TP_fast_assign( + __entry->cmd_opcode = mrq->cmd->opcode; + __entry->cmd_err = mrq->cmd->error; + memcpy(__entry->cmd_resp, mrq->cmd->resp, 4); + __entry->cmd_retries = mrq->cmd->retries; + __entry->stop_opcode = mrq->stop ? mrq->stop->opcode : 0; + __entry->stop_err = mrq->stop ? mrq->stop->error : 0; + __entry->stop_resp[0] = mrq->stop ? mrq->stop->resp[0] : 0; + __entry->stop_resp[1] = mrq->stop ? mrq->stop->resp[1] : 0; + __entry->stop_resp[2] = mrq->stop ? mrq->stop->resp[2] : 0; + __entry->stop_resp[3] = mrq->stop ? mrq->stop->resp[3] : 0; + __entry->stop_retries = mrq->stop ? mrq->stop->retries : 0; + __entry->sbc_opcode = mrq->sbc ? mrq->sbc->opcode : 0; + __entry->sbc_err = mrq->sbc ? mrq->sbc->error : 0; + __entry->sbc_resp[0] = mrq->sbc ? mrq->sbc->resp[0] : 0; + __entry->sbc_resp[1] = mrq->sbc ? mrq->sbc->resp[1] : 0; + __entry->sbc_resp[2] = mrq->sbc ? mrq->sbc->resp[2] : 0; + __entry->sbc_resp[3] = mrq->sbc ? mrq->sbc->resp[3] : 0; + __entry->sbc_retries = mrq->sbc ? mrq->sbc->retries : 0; + __entry->bytes_xfered = mrq->data ? mrq->data->bytes_xfered : 0; + __entry->data_err = mrq->data ? mrq->data->error : 0; + __entry->can_retune = host->can_retune; + __entry->doing_retune = host->doing_retune; + __entry->retune_now = host->retune_now; + __entry->need_retune = host->need_retune; + __entry->hold_retune = host->hold_retune; + __entry->retune_period = host->retune_period; + __assign_str(name, mmc_hostname(host)); + __entry->mrq = mrq; + ), + + TP_printk("%s: end struct mmc_request[%p]: " + "cmd_opcode=%u cmd_err=%d cmd_resp=0x%x 0x%x 0x%x 0x%x " + "cmd_retries=%u stop_opcode=%u stop_err=%d " + "stop_resp=0x%x 0x%x 0x%x 0x%x stop_retries=%u " + "sbc_opcode=%u sbc_err=%d sbc_resp=0x%x 0x%x 0x%x 0x%x " + "sbc_retries=%u bytes_xfered=%u data_err=%d " + "can_retune=%u doing_retune=%u retune_now=%u need_retune=%d " + "hold_retune=%d retune_period=%u", + __get_str(name), __entry->mrq, + __entry->cmd_opcode, __entry->cmd_err, + __entry->cmd_resp[0], __entry->cmd_resp[1], + __entry->cmd_resp[2], __entry->cmd_resp[3], + __entry->cmd_retries, + __entry->stop_opcode, __entry->stop_err, + __entry->stop_resp[0], __entry->stop_resp[1], + __entry->stop_resp[2], __entry->stop_resp[3], + __entry->stop_retries, + __entry->sbc_opcode, __entry->sbc_err, + __entry->sbc_resp[0], __entry->sbc_resp[1], + __entry->sbc_resp[2], __entry->sbc_resp[3], + __entry->sbc_retries, + __entry->bytes_xfered, __entry->data_err, + __entry->can_retune, __entry->doing_retune, + __entry->retune_now, __entry->need_retune, + __entry->hold_retune, __entry->retune_period) +); + +#endif /* _TRACE_MMC_H */ + +/* This part must be outside protection */ +#include -- cgit v0.10.2 From 0ea28210c15680bbabc3d6079f771f1a1e69509a Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 1 Apr 2016 17:44:31 +0200 Subject: mmc: tmio, sh_mobile_sdhi: Pass tmio_mmc_host ptr to clk_{enable, disable} ops Change the clk_enable operation to take a pointer to the struct tmio_mmc_host and have it set f_max. For consistency, also change the clk_disable operation to take a pointer to struct tmio_mmc_host. Signed-off-by: Ben Hutchings Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 9aa1479..5584935 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -131,16 +131,15 @@ static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) sd_ctrl_write16(host, EXT_ACC, val); } -static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int *f) +static int sh_mobile_sdhi_clk_enable(struct tmio_mmc_host *host) { - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct tmio_mmc_host *host = mmc_priv(mmc); + struct mmc_host *mmc = host->mmc; struct sh_mobile_sdhi *priv = host_to_priv(host); int ret = clk_prepare_enable(priv->clk); if (ret < 0) return ret; - *f = clk_get_rate(priv->clk); + mmc->f_max = clk_get_rate(priv->clk); /* enable 16bit data access on SDBUF as default */ sh_mobile_sdhi_sdbuf_width(host, 16); @@ -148,11 +147,10 @@ static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int return 0; } -static void sh_mobile_sdhi_clk_disable(struct platform_device *pdev) +static void sh_mobile_sdhi_clk_disable(struct tmio_mmc_host *host) { - struct mmc_host *mmc = platform_get_drvdata(pdev); - struct tmio_mmc_host *host = mmc_priv(mmc); struct sh_mobile_sdhi *priv = host_to_priv(host); + clk_disable_unprepare(priv->clk); } diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 4a597f5a..68fd8d7 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -95,8 +95,8 @@ struct tmio_mmc_host { bool sdio_irq_enabled; int (*write16_hook)(struct tmio_mmc_host *host, int addr); - int (*clk_enable)(struct platform_device *pdev, unsigned int *f); - void (*clk_disable)(struct platform_device *pdev); + int (*clk_enable)(struct tmio_mmc_host *host); + void (*clk_disable)(struct tmio_mmc_host *host); int (*multi_io_quirk)(struct mmc_card *card, unsigned int direction, int blk_size); }; diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 0521b46..e1e5759 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -845,7 +845,7 @@ static int tmio_mmc_clk_update(struct tmio_mmc_host *host) if (!host->clk_enable) return -ENOTSUPP; - ret = host->clk_enable(host->pdev, &mmc->f_max); + ret = host->clk_enable(host); if (!ret) mmc->f_min = mmc->f_max / 512; @@ -1251,7 +1251,7 @@ int tmio_mmc_host_runtime_suspend(struct device *dev) tmio_mmc_clk_stop(host); if (host->clk_disable) - host->clk_disable(host->pdev); + host->clk_disable(host); return 0; } -- cgit v0.10.2 From 2fb55956ce4db259a5d6ce41cc32368b5055575e Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 1 Apr 2016 17:44:32 +0200 Subject: mmc: tmio, sh_mobile_sdhi: Add support for variable input clock frequency Currently tmio_mmc assumes that the input clock frequency is fixed and only its own clock divider can be changed. This is not true in the case of sh_mobile_sdhi; we can use the clock API to change it. In tmio_mmc: - Delegate setting of f_min from tmio to the clk_enable operation (if implemented), as it can be smaller than f_max / 512 - Add an optional clk_update operation called from tmio_mmc_set_clock() that updates the input clock frequency - Rename tmio_mmc_clk_update() to tmio_mmc_clk_enable(), to avoid confusion with the clk_update operation In sh_mobile_sdhi: - Make the setting of f_max conditional; it should be set through the max-frequency property in the device tree in future - Set f_min based on the input clock's minimum frequency - Implement the clk_update operation, selecting the best input clock frequency for the bus frequency that's wanted sh_mobile_sdhi_clk_update() is loosely based on Kuninori Morimoto's work in sh_mmcif. Signed-off-by: Ben Hutchings Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 5584935..8fd1d6b2 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -139,7 +139,20 @@ static int sh_mobile_sdhi_clk_enable(struct tmio_mmc_host *host) if (ret < 0) return ret; - mmc->f_max = clk_get_rate(priv->clk); + /* + * The clock driver may not know what maximum frequency + * actually works, so it should be set with the max-frequency + * property which will already have been read to f_max. If it + * was missing, assume the current frequency is the maximum. + */ + if (!mmc->f_max) + mmc->f_max = clk_get_rate(priv->clk); + + /* + * Minimum frequency is the minimum input clock frequency + * divided by our maximum divider. + */ + mmc->f_min = max(clk_round_rate(priv->clk, 1) / 512, 1L); /* enable 16bit data access on SDBUF as default */ sh_mobile_sdhi_sdbuf_width(host, 16); @@ -147,6 +160,44 @@ static int sh_mobile_sdhi_clk_enable(struct tmio_mmc_host *host) return 0; } +static unsigned int sh_mobile_sdhi_clk_update(struct tmio_mmc_host *host, + unsigned int new_clock) +{ + struct sh_mobile_sdhi *priv = host_to_priv(host); + unsigned int freq, best_freq, diff_min, diff; + int i; + + diff_min = ~0; + best_freq = 0; + + /* + * We want the bus clock to be as close as possible to, but no + * greater than, new_clock. As we can divide by 1 << i for + * any i in [0, 9] we want the input clock to be as close as + * possible, but no greater than, new_clock << i. + */ + for (i = min(9, ilog2(UINT_MAX / new_clock)); i >= 0; i--) { + freq = clk_round_rate(priv->clk, new_clock << i); + if (freq > (new_clock << i)) { + /* Too fast; look for a slightly slower option */ + freq = clk_round_rate(priv->clk, + (new_clock << i) / 4 * 3); + if (freq > (new_clock << i)) + continue; + } + + diff = new_clock - (freq >> i); + if (diff <= diff_min) { + best_freq = freq; + diff_min = diff; + } + } + + clk_set_rate(priv->clk, best_freq); + + return best_freq; +} + static void sh_mobile_sdhi_clk_disable(struct tmio_mmc_host *host) { struct sh_mobile_sdhi *priv = host_to_priv(host); @@ -265,6 +316,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) host->dma = dma_priv; host->write16_hook = sh_mobile_sdhi_write16_hook; host->clk_enable = sh_mobile_sdhi_clk_enable; + host->clk_update = sh_mobile_sdhi_clk_update; host->clk_disable = sh_mobile_sdhi_clk_disable; host->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk; @@ -362,7 +414,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) } } - dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n", + dev_info(&pdev->dev, "%s base at 0x%08lx max clock rate %u MHz\n", mmc_hostname(host->mmc), (unsigned long) (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start), host->mmc->f_max / 1000000); diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 68fd8d7..b44b589 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -96,6 +96,8 @@ struct tmio_mmc_host { int (*write16_hook)(struct tmio_mmc_host *host, int addr); int (*clk_enable)(struct tmio_mmc_host *host); + unsigned int (*clk_update)(struct tmio_mmc_host *host, + unsigned int new_clock); void (*clk_disable)(struct tmio_mmc_host *host); int (*multi_io_quirk)(struct mmc_card *card, unsigned int direction, int blk_size); diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index e1e5759..ecc16a3 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -160,9 +160,12 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, u32 clk = 0, clock; if (new_clock) { - for (clock = host->mmc->f_min, clk = 0x80000080; - new_clock >= (clock << 1); - clk >>= 1) + if (host->clk_update) + clock = host->clk_update(host, new_clock) / 512; + else + clock = host->mmc->f_min; + + for (clk = 0x80000080; new_clock >= (clock << 1); clk >>= 1) clock <<= 1; /* 1/1 clock is option */ @@ -837,19 +840,12 @@ fail: pm_runtime_put_autosuspend(mmc_dev(mmc)); } -static int tmio_mmc_clk_update(struct tmio_mmc_host *host) +static int tmio_mmc_clk_enable(struct tmio_mmc_host *host) { - struct mmc_host *mmc = host->mmc; - int ret; - if (!host->clk_enable) return -ENOTSUPP; - ret = host->clk_enable(host); - if (!ret) - mmc->f_min = mmc->f_max / 512; - - return ret; + return host->clk_enable(host); } static void tmio_mmc_power_on(struct tmio_mmc_host *host, unsigned short vdd) @@ -1135,7 +1131,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host, mmc->caps & MMC_CAP_NONREMOVABLE || mmc->slot.cd_irq >= 0); - if (tmio_mmc_clk_update(_host) < 0) { + if (tmio_mmc_clk_enable(_host) < 0) { mmc->f_max = pdata->hclk; mmc->f_min = mmc->f_max / 512; } @@ -1263,7 +1259,7 @@ int tmio_mmc_host_runtime_resume(struct device *dev) struct tmio_mmc_host *host = mmc_priv(mmc); tmio_mmc_reset(host); - tmio_mmc_clk_update(host); + tmio_mmc_clk_enable(host); if (host->clk_cache) { tmio_mmc_set_clock(host, host->clk_cache); -- cgit v0.10.2 From 452e5eef6d311e52f657b34d999758107ec3dd4a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 1 Apr 2016 17:44:33 +0200 Subject: mmc: tmio: Add UHS-I mode support Based on work by Shinobu Uehara and Ben Dooks. This adds the voltage switch operation needed for all UHS-I modes, but not the tuning needed for SDR-104 which will come later. Signed-off-by: Ben Hutchings Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index b44b589..b1819c7 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -101,6 +101,8 @@ struct tmio_mmc_host { void (*clk_disable)(struct tmio_mmc_host *host); int (*multi_io_quirk)(struct mmc_card *card, unsigned int direction, int blk_size); + int (*start_signal_voltage_switch)(struct mmc_host *mmc, + struct mmc_ios *ios); }; struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev); diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index ecc16a3..6727198 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -1012,12 +1012,20 @@ static int tmio_multi_io_quirk(struct mmc_card *card, return blk_size; } -static const struct mmc_host_ops tmio_mmc_ops = { +static int tmio_mmc_card_busy(struct mmc_host *mmc) +{ + struct tmio_mmc_host *host = mmc_priv(mmc); + + return !(sd_ctrl_read32(host, CTL_STATUS2) & TMIO_STATUS2_DAT0); +} + +static struct mmc_host_ops tmio_mmc_ops = { .request = tmio_mmc_request, .set_ios = tmio_mmc_set_ios, .get_ro = tmio_mmc_get_ro, .get_cd = mmc_gpio_get_cd, .enable_sdio_irq = tmio_mmc_enable_sdio_irq, + .card_busy = tmio_mmc_card_busy, .multi_io_quirk = tmio_multi_io_quirk, }; @@ -1116,7 +1124,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host, goto host_free; } + tmio_mmc_ops.start_signal_voltage_switch = _host->start_signal_voltage_switch; mmc->ops = &tmio_mmc_ops; + mmc->caps |= MMC_CAP_4_BIT_DATA | pdata->capabilities; mmc->caps2 |= pdata->capabilities2; mmc->max_segs = 32; diff --git a/include/linux/mmc/tmio.h b/include/linux/mmc/tmio.h index 5f5cd80..b2f28e9 100644 --- a/include/linux/mmc/tmio.h +++ b/include/linux/mmc/tmio.h @@ -63,6 +63,8 @@ #define TMIO_STAT_CMD_BUSY 0x40000000 #define TMIO_STAT_ILL_ACCESS 0x80000000 +#define TMIO_STATUS2_DAT0 BIT(7) + #define CLK_CTL_DIV_MASK 0xff #define CLK_CTL_SCLKEN BIT(8) -- cgit v0.10.2 From 7fbc030da800d07193da4a4355ca2e197cf00cfb Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 1 Apr 2016 17:44:34 +0200 Subject: mmc: tmio: always start clock after frequency calculation Starting the clock is always done after frequency change anyhow, so we can do it directly after the clock calculation and remove the specific calls. This is the first part of doing proper clock de-/activation at calculation time. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 6727198..79a4a79 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -154,6 +154,18 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) } } +static void tmio_mmc_clk_start(struct tmio_mmc_host *host) +{ + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | + sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); + msleep(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG ? 1 : 10); + + if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) { + sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100); + msleep(10); + } +} + static void tmio_mmc_set_clock(struct tmio_mmc_host *host, unsigned int new_clock) { @@ -182,6 +194,8 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK); if (!(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG)) msleep(10); + + tmio_mmc_clk_start(host); } static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) @@ -196,18 +210,6 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) msleep(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG ? 5 : 10); } -static void tmio_mmc_clk_start(struct tmio_mmc_host *host) -{ - sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | - sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); - msleep(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG ? 1 : 10); - - if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) { - sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100); - msleep(10); - } -} - static void tmio_mmc_reset(struct tmio_mmc_host *host) { /* FIXME - should we set stop clock reg here */ @@ -955,14 +957,12 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) tmio_mmc_clk_stop(host); break; case MMC_POWER_UP: - tmio_mmc_set_clock(host, ios->clock); tmio_mmc_power_on(host, ios->vdd); - tmio_mmc_clk_start(host); + tmio_mmc_set_clock(host, ios->clock); tmio_mmc_set_bus_width(host, ios->bus_width); break; case MMC_POWER_ON: tmio_mmc_set_clock(host, ios->clock); - tmio_mmc_clk_start(host); tmio_mmc_set_bus_width(host, ios->bus_width); break; } @@ -1271,10 +1271,8 @@ int tmio_mmc_host_runtime_resume(struct device *dev) tmio_mmc_reset(host); tmio_mmc_clk_enable(host); - if (host->clk_cache) { + if (host->clk_cache) tmio_mmc_set_clock(host, host->clk_cache); - tmio_mmc_clk_start(host); - } tmio_mmc_enable_dma(host, true); -- cgit v0.10.2 From 148634d24d4a7dc82a49efcf1a215e1d0695f62c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 1 Apr 2016 17:44:35 +0200 Subject: mmc: tmio: stop clock when 0Hz is requested Setting frequency to 0 is not enough, the clock explicitly has to be disabled. Otherwise voltage switching (which needs SDCLK to be quiet) fails for various cards. Because we now do the 'new_clock == 0' check right at the beginning, the indentation level of the rest of the code can be decreased a little. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 79a4a79..8290f98 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -166,25 +166,39 @@ static void tmio_mmc_clk_start(struct tmio_mmc_host *host) } } +static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) +{ + if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) { + sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000); + msleep(10); + } + + sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & + sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); + msleep(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG ? 5 : 10); +} + static void tmio_mmc_set_clock(struct tmio_mmc_host *host, unsigned int new_clock) { u32 clk = 0, clock; - if (new_clock) { - if (host->clk_update) - clock = host->clk_update(host, new_clock) / 512; - else - clock = host->mmc->f_min; + if (new_clock == 0) { + tmio_mmc_clk_stop(host); + return; + } - for (clk = 0x80000080; new_clock >= (clock << 1); clk >>= 1) - clock <<= 1; + if (host->clk_update) + clock = host->clk_update(host, new_clock) / 512; + else + clock = host->mmc->f_min; - /* 1/1 clock is option */ - if ((host->pdata->flags & TMIO_MMC_CLK_ACTUAL) && - ((clk >> 22) & 0x1)) - clk |= 0xff; - } + for (clk = 0x80000080; new_clock >= (clock << 1); clk >>= 1) + clock <<= 1; + + /* 1/1 clock is option */ + if ((host->pdata->flags & TMIO_MMC_CLK_ACTUAL) && ((clk >> 22) & 0x1)) + clk |= 0xff; if (host->set_clk_div) host->set_clk_div(host->pdev, (clk >> 22) & 1); @@ -198,18 +212,6 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, tmio_mmc_clk_start(host); } -static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) -{ - if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) { - sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0000); - msleep(10); - } - - sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & - sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); - msleep(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG ? 5 : 10); -} - static void tmio_mmc_reset(struct tmio_mmc_host *host) { /* FIXME - should we set stop clock reg here */ -- cgit v0.10.2 From 93b6911ac1ffc1fc9aba92c9e19063d47e7cf236 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 1 Apr 2016 17:44:36 +0200 Subject: mmc: host: add note that set_ios needs to handle 0Hz properly While here, refactor the comments so that they are before the declaration they are referring to. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 8dd4d29..85800b4 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -93,28 +93,39 @@ struct mmc_host_ops { void (*pre_req)(struct mmc_host *host, struct mmc_request *req, bool is_first_req); void (*request)(struct mmc_host *host, struct mmc_request *req); + + /* + * Avoid calling the next three functions too often or in a "fast + * path", since underlaying controller might implement them in an + * expensive and/or slow way. Also note that these functions might + * sleep, so don't call them in the atomic contexts! + */ + + /* + * Notes to the set_ios callback: + * ios->clock might be 0. For some controllers, setting 0Hz + * as any other frequency works. However, some controllers + * explicitly need to disable the clock. Otherwise e.g. voltage + * switching might fail because the SDCLK is not really quiet. + */ + void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios); + /* - * Avoid calling these three functions too often or in a "fast path", - * since underlaying controller might implement them in an expensive - * and/or slow way. - * - * Also note that these functions might sleep, so don't call them - * in the atomic contexts! - * * Return values for the get_ro callback should be: * 0 for a read/write card * 1 for a read-only card * -ENOSYS when not supported (equal to NULL callback) * or a negative errno value when something bad happened - * + */ + int (*get_ro)(struct mmc_host *host); + + /* * Return values for the get_cd callback should be: * 0 for a absent card * 1 for a present card * -ENOSYS when not supported (equal to NULL callback) * or a negative errno value when something bad happened */ - void (*set_ios)(struct mmc_host *host, struct mmc_ios *ios); - int (*get_ro)(struct mmc_host *host); int (*get_cd)(struct mmc_host *host); void (*enable_sdio_irq)(struct mmc_host *host, int enable); -- cgit v0.10.2 From 057a4592e6dbad0e571628968f3e20a3706e4701 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 1 Apr 2016 17:44:37 +0200 Subject: mmc: sh_mobile_sdhi: Add UHS-I mode support Implement voltage switch, supporting modes up to SDR-50. Based on work by Shinobu Uehara, Rob Taylor, William Towle and Ian Molton. Signed-off-by: Ben Hutchings Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt index 7fb746d..0f610d4 100644 --- a/Documentation/devicetree/bindings/mmc/tmio_mmc.txt +++ b/Documentation/devicetree/bindings/mmc/tmio_mmc.txt @@ -26,3 +26,6 @@ Required properties: Optional properties: - toshiba,mmc-wrprotect-disable: write-protect detection is unavailable +- pinctrl-names: should be "default", "state_uhs" +- pinctrl-0: should contain default/high speed pin ctrl +- pinctrl-1: should contain uhs mode pin ctrl diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 8fd1d6b2..3c23027 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -32,6 +32,9 @@ #include #include #include +#include +#include +#include #include "tmio_mmc.h" @@ -97,6 +100,8 @@ struct sh_mobile_sdhi { struct clk *clk; struct tmio_mmc_data mmc_data; struct tmio_mmc_dma dma_priv; + struct pinctrl *pinctrl; + struct pinctrl_state *pins_default, *pins_uhs; }; static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width) @@ -205,6 +210,44 @@ static void sh_mobile_sdhi_clk_disable(struct tmio_mmc_host *host) clk_disable_unprepare(priv->clk); } +static int sh_mobile_sdhi_start_signal_voltage_switch(struct mmc_host *mmc, + struct mmc_ios *ios) +{ + struct tmio_mmc_host *host = mmc_priv(mmc); + struct sh_mobile_sdhi *priv = host_to_priv(host); + struct pinctrl_state *pin_state; + int ret; + + switch (ios->signal_voltage) { + case MMC_SIGNAL_VOLTAGE_330: + pin_state = priv->pins_default; + break; + case MMC_SIGNAL_VOLTAGE_180: + pin_state = priv->pins_uhs; + break; + default: + return -EINVAL; + } + + /* + * If anything is missing, assume signal voltage is fixed at + * 3.3V and succeed/fail accordingly. + */ + if (IS_ERR(priv->pinctrl) || IS_ERR(pin_state)) + return ios->signal_voltage == + MMC_SIGNAL_VOLTAGE_330 ? 0 : -EINVAL; + + ret = mmc_regulator_set_vqmmc(host->mmc, ios); + if (ret) + return ret; + + ret = pinctrl_select_state(priv->pinctrl, pin_state); + if (ret) + return ret; + + return 0; +} + static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host) { int timeout = 1000; @@ -296,6 +339,14 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) goto eprobe; } + priv->pinctrl = devm_pinctrl_get(&pdev->dev); + if (!IS_ERR(priv->pinctrl)) { + priv->pins_default = pinctrl_lookup_state(priv->pinctrl, + PINCTRL_STATE_DEFAULT); + priv->pins_uhs = pinctrl_lookup_state(priv->pinctrl, + "state_uhs"); + } + host = tmio_mmc_host_alloc(pdev); if (!host) { ret = -ENOMEM; @@ -319,6 +370,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) host->clk_update = sh_mobile_sdhi_clk_update; host->clk_disable = sh_mobile_sdhi_clk_disable; host->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk; + host->start_signal_voltage_switch = sh_mobile_sdhi_start_signal_voltage_switch; /* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */ if (!host->bus_shift && resource_size(res) > 0x100) /* old way to determine the shift */ -- cgit v0.10.2 From 31fa83539fd7a8411b9bc9da77826835d2502886 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 3 Feb 2016 11:26:44 +0800 Subject: mmc: dw_mmc-rockchip: remove dw_mci_rockchip_pmops dw_mci_rockchip_pmops just copy-paste what dw_mci_pltfm_pmops have done. Let's remove it. Signed-off-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index 84e50f3..536d7c2 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -269,33 +269,13 @@ static int dw_mci_rockchip_probe(struct platform_device *pdev) return dw_mci_pltfm_register(pdev, drv_data); } -#ifdef CONFIG_PM_SLEEP -static int dw_mci_rockchip_suspend(struct device *dev) -{ - struct dw_mci *host = dev_get_drvdata(dev); - - return dw_mci_suspend(host); -} - -static int dw_mci_rockchip_resume(struct device *dev) -{ - struct dw_mci *host = dev_get_drvdata(dev); - - return dw_mci_resume(host); -} -#endif /* CONFIG_PM_SLEEP */ - -static SIMPLE_DEV_PM_OPS(dw_mci_rockchip_pmops, - dw_mci_rockchip_suspend, - dw_mci_rockchip_resume); - static struct platform_driver dw_mci_rockchip_pltfm_driver = { .probe = dw_mci_rockchip_probe, .remove = dw_mci_pltfm_remove, .driver = { .name = "dwmmc_rockchip", .of_match_table = dw_mci_rockchip_match, - .pm = &dw_mci_rockchip_pmops, + .pm = &dw_mci_pltfm_pmops, }, }; -- cgit v0.10.2 From c6a9bf99dd458147241ef93817d18e92c3650530 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Tue, 1 Mar 2016 15:12:53 +0800 Subject: mmc: dw_mmc-rockchip: fix failing to mount partition with "discard" Without MMC_CAP_ERASE support, we fail to mount partition with "discard" option since mmc_queue_setup_discard is limited for checking mmc_can_erase. Without doing mmc_queue_setup_discard, blk_queue_discard fails to test QUEUE_FLAG_DISCARD flag, so we get the following log from f2fs(actually similar to other file system): mounting with "discard" option, but the device does not support discard Signed-off-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index 536d7c2..6ce49a5 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -234,11 +234,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_ERASE, + MMC_CAP_ERASE, + MMC_CAP_ERASE, + MMC_CAP_ERASE, +}; + static const struct dw_mci_drv_data rk2928_drv_data = { .init = dw_mci_rockchip_init, }; static const struct dw_mci_drv_data rk3288_drv_data = { + .caps = dw_mci_rk3288_dwmmc_caps, .set_ios = dw_mci_rk3288_set_ios, .execute_tuning = dw_mci_rk3288_execute_tuning, .parse_dt = dw_mci_rk3288_parse_dt, -- cgit v0.10.2 From 49b17858c19b94d46e3d872f85eccba45fff21f4 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 9 Mar 2016 10:33:55 +0800 Subject: mmc: dw_mmc: fix warning reported by kernel-doc Try to fix the warning reported by: scripts/kernel-doc -man -v include/linux/mmc/dw_mmc.h > /dev/null warning: No description found for parameter 'irq_lock' warning: No description found for parameter 'stop_abort' warning: No description found for parameter 'prev_blksz' warning: No description found for parameter 'timing' warning: No description found for parameter 'ring_size' warning: No description found for parameter 'dms' warning: No description found for parameter 'phy_regs' warning: No description found for parameter 'fifoth_val' warning: No description found for parameter 'vqmmc_enabled' warning: No description found for parameter 'cmd11_timer' warning: Excess struct/union/enum/typedef member 'card_tasklet' description in 'dw_mci' Signed-off-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h index 7b41c6d..c8b6a4d 100644 --- a/include/linux/mmc/dw_mmc.h +++ b/include/linux/mmc/dw_mmc.h @@ -55,6 +55,7 @@ struct dw_mci_dma_slave { /** * struct dw_mci - MMC controller state shared between all slots * @lock: Spinlock protecting the queue and associated data. + * @irq_lock: Spinlock protecting the INTMASK setting. * @regs: Pointer to MMIO registers. * @fifo_reg: Pointer to MMIO registers for data FIFO * @sg: Scatterlist entry currently being processed by PIO code, if any. @@ -65,6 +66,9 @@ struct dw_mci_dma_slave { * @cmd: The command currently being sent to the card, or NULL. * @data: The data currently being transferred, or NULL if no data * transfer is in progress. + * @stop_abort: The command currently prepared for stoping transfer. + * @prev_blksz: The former transfer blksz record. + * @timing: Record of current ios timing. * @use_dma: Whether DMA channel is initialized or not. * @using_dma: Whether DMA is in use for the current transfer. * @dma_64bit_address: Whether DMA supports 64-bit address mode or not. @@ -72,7 +76,10 @@ struct dw_mci_dma_slave { * @sg_cpu: Virtual address of DMA buffer. * @dma_ops: Pointer to platform-specific DMA callbacks. * @cmd_status: Snapshot of SR taken upon completion of the current + * @ring_size: Buffer size for idma descriptors. * command. Only valid when EVENT_CMD_COMPLETE is pending. + * @dms: structure of slave-dma private data. + * @phy_regs: physical address of controller's register map * @data_status: Snapshot of SR taken upon completion of the current * data transfer. Only valid when EVENT_DATA_COMPLETE or * EVENT_DATA_ERROR is pending. @@ -80,7 +87,6 @@ struct dw_mci_dma_slave { * to be sent. * @dir_status: Direction of current transfer. * @tasklet: Tasklet running the request state machine. - * @card_tasklet: Tasklet handling card detect. * @pending_events: Bitmask of events flagged by the interrupt handler * to be processed by the tasklet. * @completed_events: Bitmask of events which the state machine has @@ -91,6 +97,7 @@ struct dw_mci_dma_slave { * rate and timeout calculations. * @current_speed: Configured rate of the controller. * @num_slots: Number of slots available. + * @fifoth_val: The value of FIFOTH register. * @verid: Denote Version ID. * @dev: Device associated with the MMC controller. * @pdata: Platform data associated with the MMC controller. @@ -107,9 +114,11 @@ struct dw_mci_dma_slave { * @push_data: Pointer to FIFO push function. * @pull_data: Pointer to FIFO pull function. * @quirks: Set of quirks that apply to specific versions of the IP. + * @vqmmc_enabled: Status of vqmmc, should be true or false. * @irq_flags: The flags to be passed to request_irq. * @irq: The irq value to be passed to request_irq. * @sdio_id0: Number of slot0 in the SDIO interrupt registers. + * @cmd11_timer: Timer for SD3.0 voltage switch over scheme. * @dto_timer: Timer for broken data transfer over scheme. * * Locking -- cgit v0.10.2 From ab925a315eb3c6cd9fe25ff0ca5babb94a98b55c Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 9 Mar 2016 10:34:46 +0800 Subject: mmc: dw_mmc: avoid using dmaengine_terminate_all dmaengine_terminate_all is deprecated and should be replaced by more explicit synchronous and asynchronous terminate functions. This change is based on the commit b36f09c3c441 ("dmaengine: Add transfer termination synchronization support"). Currently dw_mci_stop_dma may be called under the spinlock, let's migrate dmaengine_terminate_all to async terminate. This could avoid the race condition of use-after-free resouce of dmaengine once slave-dma driver implement the synchronize method. Signed-off-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 242f9a0..45a406f 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -680,7 +680,7 @@ static const struct dw_mci_dma_ops dw_mci_idmac_ops = { static void dw_mci_edmac_stop_dma(struct dw_mci *host) { - dmaengine_terminate_all(host->dms->ch); + dmaengine_terminate_async(host->dms->ch); } static int dw_mci_edmac_start_dma(struct dw_mci *host, -- cgit v0.10.2 From 6929eeec2a7c5fe29d8d5cd0873089fc733943b0 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 3 Feb 2016 11:26:04 +0800 Subject: mmc: dw_mmc: remove unused EVENT_XFER_ERROR EVENT_XFER_ERROR isn't been used now, so it can be removed. Signed-off-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h index c8b6a4d..f7ed271 100644 --- a/include/linux/mmc/dw_mmc.h +++ b/include/linux/mmc/dw_mmc.h @@ -36,7 +36,6 @@ enum { EVENT_XFER_COMPLETE, EVENT_DATA_COMPLETE, EVENT_DATA_ERROR, - EVENT_XFER_ERROR }; struct mmc_data; -- cgit v0.10.2 From 5659eeaddd47982d03a19c651384456cc3164acc Mon Sep 17 00:00:00 2001 From: Jaehoon Chung Date: Thu, 31 Mar 2016 14:53:18 +0900 Subject: mmc: dw_mmc: exynos: add the function for controlling SMU Some of Exynos has the Security management Unit(SMU). This patch adds the function for controlling SMU. In future, if exynos needs to control SMU, it can be implemented in "config_smu" function, not "init" function. Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 8790f2a..0e989eb 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -91,10 +91,14 @@ static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host) return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1; } -static int dw_mci_exynos_priv_init(struct dw_mci *host) +static void dw_mci_exynos_config_smu(struct dw_mci *host) { struct dw_mci_exynos_priv_data *priv = host->priv; + /* + * If Exynos is provided the Security management, + * set for non-ecryption mode at this time. + */ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU || priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) { mci_writel(host, MPSBEGIN0, 0); @@ -104,6 +108,13 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host) SDMMC_MPSCTRL_VALID | SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT); } +} + +static int dw_mci_exynos_priv_init(struct dw_mci *host) +{ + struct dw_mci_exynos_priv_data *priv = host->priv; + + dw_mci_exynos_config_smu(host); if (priv->ctrl_type >= DW_MCI_TYPE_EXYNOS5420) { priv->saved_strobe_ctrl = mci_readl(host, HS400_DLINE_CTRL); @@ -169,7 +180,7 @@ static int dw_mci_exynos_resume(struct device *dev) { struct dw_mci *host = dev_get_drvdata(dev); - dw_mci_exynos_priv_init(host); + dw_mci_exynos_config_smu(host); return dw_mci_resume(host); } -- cgit v0.10.2 From 1975676080c9fe225015f42801a6c8d5e1e5f97b Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 31 Mar 2016 15:33:53 +0800 Subject: mmc: dw_mmc-rockchip: remove setup_clock for rockchip We remove setup_clock hook and combine it into init hook to simplify the code Signed-off-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c index 6ce49a5..8c20b81 100644 --- a/drivers/mmc/host/dw_mmc-rockchip.c +++ b/drivers/mmc/host/dw_mmc-rockchip.c @@ -26,13 +26,6 @@ struct dw_mci_rockchip_priv_data { int default_sample_phase; }; -static int dw_mci_rk3288_setup_clock(struct dw_mci *host) -{ - host->bus_hz /= RK3288_CLKGEN_DIV; - - return 0; -} - static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios) { struct dw_mci_rockchip_priv_data *priv = host->priv; @@ -231,6 +224,10 @@ static int dw_mci_rockchip_init(struct dw_mci *host) /* It needs this quirk on all Rockchip SoCs */ host->pdata->quirks |= DW_MCI_QUIRK_BROKEN_DTO; + if (of_device_is_compatible(host->dev->of_node, + "rockchip,rk3288-dw-mshc")) + host->bus_hz /= RK3288_CLKGEN_DIV; + return 0; } @@ -251,7 +248,6 @@ static const struct dw_mci_drv_data rk3288_drv_data = { .set_ios = dw_mci_rk3288_set_ios, .execute_tuning = dw_mci_rk3288_execute_tuning, .parse_dt = dw_mci_rk3288_parse_dt, - .setup_clock = dw_mci_rk3288_setup_clock, .init = dw_mci_rockchip_init, }; -- cgit v0.10.2 From 7c2c2cc8f909f76965c0d79b04a111ee2b01d63f Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 31 Mar 2016 15:34:02 +0800 Subject: mmc: dw_mmc-exynos: remove dw_mci_exynos_setup_clock We combine what dw_mci_exynos_setup_clock does with init hook to simplify the code Signed-off-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 0e989eb..7e3a324 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -126,13 +126,6 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host) DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl); } - return 0; -} - -static int dw_mci_exynos_setup_clock(struct dw_mci *host) -{ - struct dw_mci_exynos_priv_data *priv = host->priv; - host->bus_hz /= (priv->ciu_div + 1); return 0; @@ -500,7 +493,6 @@ static unsigned long exynos_dwmmc_caps[4] = { static const struct dw_mci_drv_data exynos_drv_data = { .caps = exynos_dwmmc_caps, .init = dw_mci_exynos_priv_init, - .setup_clock = dw_mci_exynos_setup_clock, .set_ios = dw_mci_exynos_set_ios, .parse_dt = dw_mci_exynos_parse_dt, .execute_tuning = dw_mci_exynos_execute_tuning, -- cgit v0.10.2 From 2edeb8540bc21247906e13ad2a08317d6fa410e7 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 31 Mar 2016 15:34:10 +0800 Subject: mmc: dw_mmc: remove setup_clock callback Now, no dw_mmc variant drivers use this callback, let's remove it. Signed-off-by: Shawn Lin Signed-off-by: Jaehoon Chung Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 45a406f..9dd1bd3 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -3003,15 +3003,6 @@ int dw_mci_probe(struct dw_mci *host) } } - if (drv_data && drv_data->setup_clock) { - ret = drv_data->setup_clock(host); - if (ret) { - dev_err(host->dev, - "implementation specific clock setup failed\n"); - goto err_clk_ciu; - } - } - setup_timer(&host->cmd11_timer, dw_mci_cmd11_timer, (unsigned long)host); diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 68d5da2..1e8d838 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -277,7 +277,6 @@ struct dw_mci_slot { * dw_mci driver data - dw-mshc implementation specific driver data. * @caps: mmc subsystem specified capabilities of the controller(s). * @init: early implementation specific initialization. - * @setup_clock: implementation specific clock configuration. * @set_ios: handle bus specific extensions. * @parse_dt: parse implementation specific device tree properties. * @execute_tuning: implementation specific tuning procedure. @@ -289,7 +288,6 @@ struct dw_mci_slot { struct dw_mci_drv_data { unsigned long *caps; int (*init)(struct dw_mci *host); - int (*setup_clock)(struct dw_mci *host); 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, u32 opcode); -- cgit v0.10.2 From 62ac52b2fbcc8036d1fd4860b232fef2d554fa4d Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 5 Apr 2016 12:31:49 -0500 Subject: mmc: davinci: fix unwinding in probe Unwiding from an error in davinci_mmcsd_probe was a mess. Some errors were not handled and not all paths unwound correctly. Also using devm_ where possible to simplify things. Signed-off-by: David Lechner Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 498c42d..8503214 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1205,7 +1205,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) struct mmc_davinci_host *host = NULL; struct mmc_host *mmc = NULL; struct resource *r, *mem = NULL; - int ret = 0, irq = 0; + int ret, irq; size_t mem_size; const struct platform_device_id *id_entry; @@ -1215,38 +1215,40 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) return -ENOENT; } - ret = -ENODEV; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_irq(pdev, 0); if (!r || irq == NO_IRQ) - goto out; + return -ENODEV; - ret = -EBUSY; mem_size = resource_size(r); - mem = request_mem_region(r->start, mem_size, pdev->name); + mem = devm_request_mem_region(&pdev->dev, r->start, mem_size, + pdev->name); if (!mem) - goto out; + return -EBUSY; - ret = -ENOMEM; mmc = mmc_alloc_host(sizeof(struct mmc_davinci_host), &pdev->dev); if (!mmc) - goto out; + return -ENOMEM; host = mmc_priv(mmc); host->mmc = mmc; /* Important */ host->mem_res = mem; - host->base = ioremap(mem->start, mem_size); - if (!host->base) - goto out; + host->base = devm_ioremap(&pdev->dev, mem->start, mem_size); + if (!host->base) { + ret = -ENOMEM; + goto ioremap_fail; + } - ret = -ENXIO; - host->clk = clk_get(&pdev->dev, NULL); + host->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(host->clk)) { ret = PTR_ERR(host->clk); - goto out; + goto clk_get_fail; } - clk_enable(host->clk); + ret = clk_enable(host->clk); + if (ret) + goto clk_enable_fail; + host->mmc_input_clk = clk_get_rate(host->clk); init_mmcsd_host(host); @@ -1264,7 +1266,7 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) if (host->use_dma) { ret = davinci_acquire_dma_channels(host); if (ret == -EPROBE_DEFER) - goto out; + goto dma_probe_defer; else if (ret) host->use_dma = 0; } @@ -1321,15 +1323,17 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) ret = mmc_add_host(mmc); if (ret < 0) - goto out; + goto mmc_add_host_fail; - ret = request_irq(irq, mmc_davinci_irq, 0, mmc_hostname(mmc), host); + ret = devm_request_irq(&pdev->dev, irq, mmc_davinci_irq, 0, + mmc_hostname(mmc), host); if (ret) - goto out; + goto request_irq_fail; if (host->sdio_irq >= 0) { - ret = request_irq(host->sdio_irq, mmc_davinci_sdio_irq, 0, - mmc_hostname(mmc), host); + ret = devm_request_irq(&pdev->dev, host->sdio_irq, + mmc_davinci_sdio_irq, 0, + mmc_hostname(mmc), host); if (!ret) mmc->caps |= MMC_CAP_SDIO_IRQ; } @@ -1342,28 +1346,18 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) return 0; -out: +request_irq_fail: + mmc_remove_host(mmc); +mmc_add_host_fail: mmc_davinci_cpufreq_deregister(host); cpu_freq_fail: - if (host) { - davinci_release_dma_channels(host); - - if (host->clk) { - clk_disable(host->clk); - clk_put(host->clk); - } - - if (host->base) - iounmap(host->base); - } - - if (mmc) - mmc_free_host(mmc); - - if (mem) - release_resource(mem); - - dev_dbg(&pdev->dev, "probe err %d\n", ret); + davinci_release_dma_channels(host); +dma_probe_defer: + clk_disable(host->clk); +clk_enable_fail: +clk_get_fail: +ioremap_fail: + mmc_free_host(mmc); return ret; } @@ -1372,25 +1366,11 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev) { struct mmc_davinci_host *host = platform_get_drvdata(pdev); - if (host) { - mmc_davinci_cpufreq_deregister(host); - - mmc_remove_host(host->mmc); - free_irq(host->mmc_irq, host); - if (host->mmc->caps & MMC_CAP_SDIO_IRQ) - free_irq(host->sdio_irq, host); - - davinci_release_dma_channels(host); - - clk_disable(host->clk); - clk_put(host->clk); - - iounmap(host->base); - - release_resource(host->mem_res); - - mmc_free_host(host->mmc); - } + mmc_remove_host(host->mmc); + mmc_davinci_cpufreq_deregister(host); + davinci_release_dma_channels(host); + clk_disable(host->clk); + mmc_free_host(host->mmc); return 0; } -- cgit v0.10.2 From e2f3bfbdc9f4929d767bc0d8033322a72d51193e Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 5 Apr 2016 12:31:50 -0500 Subject: mmc: davinci: prepare clock When trying to use this driver with the common clock framework, enabling the clock fails because it was not prepared. This fixes the problem by calling clk_prepare and clk_enable in a single function. Ditto for clk_disable_unprepare. Signed-off-by: David Lechner Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index 8503214..a56373c 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1245,9 +1245,9 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) ret = PTR_ERR(host->clk); goto clk_get_fail; } - ret = clk_enable(host->clk); + ret = clk_prepare_enable(host->clk); if (ret) - goto clk_enable_fail; + goto clk_prepare_enable_fail; host->mmc_input_clk = clk_get_rate(host->clk); @@ -1353,8 +1353,8 @@ mmc_add_host_fail: cpu_freq_fail: davinci_release_dma_channels(host); dma_probe_defer: - clk_disable(host->clk); -clk_enable_fail: + clk_disable_unprepare(host->clk); +clk_prepare_enable_fail: clk_get_fail: ioremap_fail: mmc_free_host(mmc); @@ -1369,7 +1369,7 @@ static int __exit davinci_mmcsd_remove(struct platform_device *pdev) mmc_remove_host(host->mmc); mmc_davinci_cpufreq_deregister(host); davinci_release_dma_channels(host); - clk_disable(host->clk); + clk_disable_unprepare(host->clk); mmc_free_host(host->mmc); return 0; -- cgit v0.10.2 From d0071281cfb7195af3fa087815cdee26ddfb4b7f Mon Sep 17 00:00:00 2001 From: David Lechner Date: Tue, 5 Apr 2016 12:31:51 -0500 Subject: ARM: davinci: remove mmc dma resources The davinci_mmc driver no longer uses platform resources for getting dma channels. Instead lookup is now done using dma_slave_map. Signed-off-by: David Lechner Acked-by: Sekhar Nori Signed-off-by: Ulf Hansson diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index 725e693..add3771 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -751,16 +751,6 @@ static struct resource da8xx_mmcsd0_resources[] = { .end = IRQ_DA8XX_MMCSDINT0, .flags = IORESOURCE_IRQ, }, - { /* DMA RX */ - .start = DA8XX_DMA_MMCSD0_RX, - .end = DA8XX_DMA_MMCSD0_RX, - .flags = IORESOURCE_DMA, - }, - { /* DMA TX */ - .start = DA8XX_DMA_MMCSD0_TX, - .end = DA8XX_DMA_MMCSD0_TX, - .flags = IORESOURCE_DMA, - }, }; static struct platform_device da8xx_mmcsd0_device = { @@ -788,16 +778,6 @@ static struct resource da850_mmcsd1_resources[] = { .end = IRQ_DA850_MMCSDINT0_1, .flags = IORESOURCE_IRQ, }, - { /* DMA RX */ - .start = DA850_DMA_MMCSD1_RX, - .end = DA850_DMA_MMCSD1_RX, - .flags = IORESOURCE_DMA, - }, - { /* DMA TX */ - .start = DA850_DMA_MMCSD1_TX, - .end = DA850_DMA_MMCSD1_TX, - .flags = IORESOURCE_DMA, - }, }; static struct platform_device da850_mmcsd1_device = { diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c index 6257aa4..67d26c5 100644 --- a/arch/arm/mach-davinci/devices.c +++ b/arch/arm/mach-davinci/devices.c @@ -144,14 +144,6 @@ static struct resource mmcsd0_resources[] = { .start = IRQ_SDIOINT, .flags = IORESOURCE_IRQ, }, - /* DMA channels: RX, then TX */ - { - .start = EDMA_CTLR_CHAN(0, DAVINCI_DMA_MMCRXEVT), - .flags = IORESOURCE_DMA, - }, { - .start = EDMA_CTLR_CHAN(0, DAVINCI_DMA_MMCTXEVT), - .flags = IORESOURCE_DMA, - }, }; static struct platform_device davinci_mmcsd0_device = { @@ -181,14 +173,6 @@ static struct resource mmcsd1_resources[] = { .start = IRQ_DM355_SDIOINT1, .flags = IORESOURCE_IRQ, }, - /* DMA channels: RX, then TX */ - { - .start = EDMA_CTLR_CHAN(0, 30), /* rx */ - .flags = IORESOURCE_DMA, - }, { - .start = EDMA_CTLR_CHAN(0, 31), /* tx */ - .flags = IORESOURCE_DMA, - }, }; static struct platform_device davinci_mmcsd1_device = { -- cgit v0.10.2 From bc94440d4e1c26cf5a147f0193d824c752faebd6 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 21 Mar 2016 14:09:07 +0100 Subject: mmc: atmel-mci: Remove redundant runtime PM calls Commit 9250aea76bfc ("mmc: core: Enable runtime PM management of host devices"), made some calls to the runtime PM API from the driver redundant. Especially those which deals with runtime PM reference counting, so let's remove them. Cc: Ludovic Desroches Signed-off-by: Ulf Hansson Acked-by: Ludovic Desroches Tested-by: Ludovic Desroches diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 9268c41..0ad8ef5 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -1410,8 +1410,6 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq) WARN_ON(slot->mrq); dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode); - pm_runtime_get_sync(&host->pdev->dev); - /* * We may "know" the card is gone even though there's still an * electrical connection. If so, we really need to communicate @@ -1442,8 +1440,6 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct atmel_mci *host = slot->host; unsigned int i; - pm_runtime_get_sync(&host->pdev->dev); - slot->sdc_reg &= ~ATMCI_SDCBUS_MASK; switch (ios->bus_width) { case MMC_BUS_WIDTH_1: @@ -1576,8 +1572,6 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) break; } - pm_runtime_mark_last_busy(&host->pdev->dev); - pm_runtime_put_autosuspend(&host->pdev->dev); } static int atmci_get_ro(struct mmc_host *mmc) @@ -1669,9 +1663,6 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq) spin_unlock(&host->lock); mmc_request_done(prev_mmc, mrq); spin_lock(&host->lock); - - pm_runtime_mark_last_busy(&host->pdev->dev); - pm_runtime_put_autosuspend(&host->pdev->dev); } static void atmci_command_complete(struct atmel_mci *host, -- cgit v0.10.2 From d8b7d6b7f956eac49e9753ac6786ac4e53e075c3 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 21 Mar 2016 14:17:00 +0100 Subject: mmc: mmci: Remove redundant runtime PM calls Commit 9250aea76bfc ("mmc: core: Enable runtime PM management of host devices"), made some calls to the runtime PM API from the driver redundant. Especially those which deals with runtime PM reference counting, so let's remove them. Cc: Russell King Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 2e6c968..df990bb 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -226,16 +226,11 @@ static int mmci_card_busy(struct mmc_host *mmc) unsigned long flags; int busy = 0; - pm_runtime_get_sync(mmc_dev(mmc)); - spin_lock_irqsave(&host->lock, flags); if (readl(host->base + MMCISTATUS) & MCI_ST_CARDBUSY) busy = 1; spin_unlock_irqrestore(&host->lock, flags); - pm_runtime_mark_last_busy(mmc_dev(mmc)); - pm_runtime_put_autosuspend(mmc_dev(mmc)); - return busy; } @@ -381,9 +376,6 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) host->cmd = NULL; mmc_request_done(host->mmc, mrq); - - pm_runtime_mark_last_busy(mmc_dev(host->mmc)); - pm_runtime_put_autosuspend(mmc_dev(host->mmc)); } static void mmci_set_mask1(struct mmci_host *host, unsigned int mask) @@ -1290,8 +1282,6 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) return; } - pm_runtime_get_sync(mmc_dev(mmc)); - spin_lock_irqsave(&host->lock, flags); host->mrq = mrq; @@ -1318,8 +1308,6 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) unsigned long flags; int ret; - pm_runtime_get_sync(mmc_dev(mmc)); - if (host->plat->ios_handler && host->plat->ios_handler(mmc_dev(mmc), ios)) dev_err(mmc_dev(mmc), "platform ios_handler failed\n"); @@ -1414,9 +1402,6 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) mmci_reg_delay(host); spin_unlock_irqrestore(&host->lock, flags); - - pm_runtime_mark_last_busy(mmc_dev(mmc)); - pm_runtime_put_autosuspend(mmc_dev(mmc)); } static int mmci_get_cd(struct mmc_host *mmc) @@ -1440,8 +1425,6 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) if (!IS_ERR(mmc->supply.vqmmc)) { - pm_runtime_get_sync(mmc_dev(mmc)); - switch (ios->signal_voltage) { case MMC_SIGNAL_VOLTAGE_330: ret = regulator_set_voltage(mmc->supply.vqmmc, @@ -1459,9 +1442,6 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) if (ret) dev_warn(mmc_dev(mmc), "Voltage switch failed\n"); - - pm_runtime_mark_last_busy(mmc_dev(mmc)); - pm_runtime_put_autosuspend(mmc_dev(mmc)); } return ret; -- cgit v0.10.2 From 567979fba16ab3b9803f456a653bfe19e891cd3c Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 21 Mar 2016 14:21:25 +0100 Subject: mmc: mediatek: Remove redundant runtime PM calls Commit 9250aea76bfc ("mmc: core: Enable runtime PM management of host devices"), made some calls to the runtime PM API from the driver redundant. Especially those which deals with runtime PM reference counting, so let's remove them. Cc: Chaotian Jing Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index b17f30d..5642f71 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -736,9 +736,6 @@ static void msdc_request_done(struct msdc_host *host, struct mmc_request *mrq) if (mrq->data) msdc_unprepare_data(host, mrq); mmc_request_done(host->mmc, mrq); - - pm_runtime_mark_last_busy(host->dev); - pm_runtime_put_autosuspend(host->dev); } /* returns true if command is fully handled; returns false otherwise */ @@ -886,8 +883,6 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq) WARN_ON(host->mrq); host->mrq = mrq; - pm_runtime_get_sync(host->dev); - if (mrq->data) msdc_prepare_data(host, mrq); @@ -1201,8 +1196,6 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct msdc_host *host = mmc_priv(mmc); int ret; - pm_runtime_get_sync(host->dev); - msdc_set_buswidth(host, ios->bus_width); /* Suspend/Resume will do power off/on */ @@ -1214,7 +1207,7 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ios->vdd); if (ret) { dev_err(host->dev, "Failed to set vmmc power!\n"); - goto end; + return; } } break; @@ -1242,10 +1235,6 @@ static void msdc_ops_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (host->mclk != ios->clock || host->timing != ios->timing) msdc_set_mclk(host, ios->timing, ios->clock); - -end: - pm_runtime_mark_last_busy(host->dev); - pm_runtime_put_autosuspend(host->dev); } static u32 test_delay_bit(u32 delay, u32 bit) @@ -1408,19 +1397,15 @@ static int msdc_execute_tuning(struct mmc_host *mmc, u32 opcode) struct msdc_host *host = mmc_priv(mmc); int ret; - pm_runtime_get_sync(host->dev); ret = msdc_tune_response(mmc, opcode); if (ret == -EIO) { dev_err(host->dev, "Tune response fail!\n"); - goto out; + return ret; } ret = msdc_tune_data(mmc, opcode); if (ret == -EIO) dev_err(host->dev, "Tune data fail!\n"); -out: - pm_runtime_mark_last_busy(host->dev); - pm_runtime_put_autosuspend(host->dev); return ret; } -- cgit v0.10.2 From 5d7435f5cc2a3a214f3b9c4fb8bbd3cae9304e4c Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 21 Mar 2016 14:28:36 +0100 Subject: mmc: omap_hsmmc: Remove redundant runtime PM calls Commit 9250aea76bfc ("mmc: core: Enable runtime PM management of host devices"), made some calls to the runtime PM API from the driver redundant. Especially those which deals with runtime PM reference counting, so let's remove them. Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index bcb02a6..e9d75c6 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -967,8 +967,6 @@ 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); } /* @@ -1249,7 +1247,6 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) int ret; /* Disable the clocks */ - pm_runtime_put_sync(host->dev); if (host->dbclk) clk_disable_unprepare(host->dbclk); @@ -1259,7 +1256,6 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd) /* Turn the power ON with given VDD 1.8 or 3.0v */ if (!ret) ret = omap_hsmmc_set_power(host, 1, vdd); - pm_runtime_get_sync(host->dev); if (host->dbclk) clk_prepare_enable(host->dbclk); @@ -1367,8 +1363,6 @@ 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); } } @@ -1601,7 +1595,6 @@ 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) { /* @@ -1618,8 +1611,6 @@ 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; @@ -1633,8 +1624,6 @@ 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)) { @@ -1652,8 +1641,6 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct omap_hsmmc_host *host = mmc_priv(mmc); int do_send_init_stream = 0; - pm_runtime_get_sync(host->dev); - if (ios->power_mode != host->power_mode) { switch (ios->power_mode) { case MMC_POWER_OFF: @@ -1697,8 +1684,6 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) send_init_stream(host); omap_hsmmc_set_bus_mode(host); - - pm_runtime_put_autosuspend(host->dev); } static int omap_hsmmc_get_cd(struct mmc_host *mmc) -- cgit v0.10.2 From 4d56e9ae6b0cb227e1064be514b47ea477a38108 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 21 Mar 2016 14:33:35 +0100 Subject: mmc: sdhci-acpi: Remove redundant runtime PM calls Commit 9250aea76bfc ("mmc: core: Enable runtime PM management of host devices"), made some calls to the runtime PM API from the driver redundant. Especially those which deals with runtime PM reference counting, so let's remove them. Cc: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index bed6a49..2a0cda5 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -200,8 +200,6 @@ static int bxt_get_cd(struct mmc_host *mmc) if (!gpio_cd) return 0; - pm_runtime_get_sync(mmc->parent); - spin_lock_irqsave(&host->lock, flags); if (host->flags & SDHCI_DEVICE_DEAD) @@ -211,9 +209,6 @@ static int bxt_get_cd(struct mmc_host *mmc) out: spin_unlock_irqrestore(&host->lock, flags); - pm_runtime_mark_last_busy(mmc->parent); - pm_runtime_put_autosuspend(mmc->parent); - return ret; } -- cgit v0.10.2 From c8037e799b412562e906a2e95feaf177ba8c5df2 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 21 Mar 2016 14:40:07 +0100 Subject: mmc: sdhci-pci: Remove redundant runtime PM calls Commit 9250aea76bfc ("mmc: core: Enable runtime PM management of host devices"), made some calls to the runtime PM API from the driver redundant. Especially those which deals with runtime PM reference counting, so let's remove them. Cc: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 79e1901..e5c6a49 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -340,8 +340,6 @@ static int bxt_get_cd(struct mmc_host *mmc) if (!gpio_cd) return 0; - pm_runtime_get_sync(mmc->parent); - spin_lock_irqsave(&host->lock, flags); if (host->flags & SDHCI_DEVICE_DEAD) @@ -351,9 +349,6 @@ static int bxt_get_cd(struct mmc_host *mmc) out: spin_unlock_irqrestore(&host->lock, flags); - pm_runtime_mark_last_busy(mmc->parent); - pm_runtime_put_autosuspend(mmc->parent); - return ret; } -- cgit v0.10.2 From 6aef2eecc4d4c9edb8c8d3e3a7f6af3cee42b2ec Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 21 Mar 2016 15:43:41 +0100 Subject: mmc: tmio: Remove redundant runtime PM calls Commit 9250aea76bfc ("mmc: core: Enable runtime PM management of host devices"), made some calls to the runtime PM API from the driver redundant. Especially those which deals with runtime PM reference counting, so let's remove them. Cc: Ian Molton Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 8290f98..1dd1c04 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -271,9 +271,6 @@ static void tmio_mmc_reset_work(struct work_struct *work) tmio_mmc_abort_dma(host); mmc_request_done(host->mmc, mrq); - - pm_runtime_mark_last_busy(mmc_dev(host->mmc)); - pm_runtime_put_autosuspend(mmc_dev(host->mmc)); } /* called with host->lock held, interrupts disabled */ @@ -303,9 +300,6 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host) tmio_mmc_abort_dma(host); mmc_request_done(host->mmc, mrq); - - pm_runtime_mark_last_busy(mmc_dev(host->mmc)); - pm_runtime_put_autosuspend(mmc_dev(host->mmc)); } static void tmio_mmc_done_work(struct work_struct *work) @@ -819,8 +813,6 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) spin_unlock_irqrestore(&host->lock, flags); - pm_runtime_get_sync(mmc_dev(mmc)); - if (mrq->data) { ret = tmio_mmc_start_data(host, mrq->data); if (ret) @@ -839,9 +831,6 @@ fail: host->mrq = NULL; mrq->cmd->error = ret; mmc_request_done(mmc, mrq); - - pm_runtime_mark_last_busy(mmc_dev(mmc)); - pm_runtime_put_autosuspend(mmc_dev(mmc)); } static int tmio_mmc_clk_enable(struct tmio_mmc_host *host) @@ -925,8 +914,6 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct device *dev = &host->pdev->dev; unsigned long flags; - pm_runtime_get_sync(mmc_dev(mmc)); - mutex_lock(&host->ios_lock); spin_lock_irqsave(&host->lock, flags); @@ -981,9 +968,6 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->clk_cache = ios->clock; mutex_unlock(&host->ios_lock); - - pm_runtime_mark_last_busy(mmc_dev(mmc)); - pm_runtime_put_autosuspend(mmc_dev(mmc)); } static int tmio_mmc_get_ro(struct mmc_host *mmc) @@ -994,11 +978,8 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc) if (ret >= 0) return ret; - pm_runtime_get_sync(mmc_dev(mmc)); ret = !((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) || (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)); - pm_runtime_mark_last_busy(mmc_dev(mmc)); - pm_runtime_put_autosuspend(mmc_dev(mmc)); return ret; } -- cgit v0.10.2 From 4e6c71788d6bb0e5438fc9211fa6e52dcca01474 Mon Sep 17 00:00:00 2001 From: Gwendal Grignou Date: Fri, 1 Apr 2016 16:04:22 -0700 Subject: mmc: core: Do regular power cycle when lacking eMMC HW reset support The eMMC HW reset may be implemented either via the host ops ->hw_reset() callback or through DT and the eMMC pwrseq. Additionally some eMMC cards don't support HW reset. To allow a reset to be done for the different combinations of mmc hosts and eMMC/MMC cards, let's implement a fallback via trying a regular power cycle. This improves the mmc block layer retry mechanism of failing I/O requests. Signed-off-by: Gwendal Grignou [Ulf: Rewrote changelog] Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index f80b3ab..99275e4 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2456,8 +2456,9 @@ int mmc_hw_reset(struct mmc_host *host) ret = host->bus_ops->reset(host); mmc_bus_put(host); - if (ret != -EOPNOTSUPP) - pr_warn("%s: tried to reset card\n", mmc_hostname(host)); + if (ret) + pr_warn("%s: tried to reset card, got error %d\n", + mmc_hostname(host), ret); return ret; } diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 4dbe3df..b8aa12c 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1957,19 +1957,17 @@ static int mmc_reset(struct mmc_host *host) { struct mmc_card *card = host->card; - if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) - return -EOPNOTSUPP; - - if (!mmc_can_reset(card)) - return -EOPNOTSUPP; - - mmc_set_clock(host, host->f_init); - - host->ops->hw_reset(host); - - /* Set initial state and call mmc_set_ios */ - mmc_set_initial_state(host); - + if ((host->caps & MMC_CAP_HW_RESET) && host->ops->hw_reset && + mmc_can_reset(card)) { + /* If the card accept RST_n signal, send it. */ + mmc_set_clock(host, host->f_init); + host->ops->hw_reset(host); + /* Set initial state and call mmc_set_ios */ + mmc_set_initial_state(host); + } else { + /* Do a brute force power cycle */ + mmc_power_cycle(host, card->ocr); + } return mmc_init_card(host, card->ocr, card); } -- cgit v0.10.2 From 15e82076a0edbebedbe12652b4ad8f1d93bcb7fe Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 7 Apr 2016 10:56:39 +0200 Subject: mmc: sdhci: Remove redundant runtime PM calls Commit 9250aea76bfc ("mmc: core: Enable runtime PM management of host devices"), made some calls to the runtime PM API from the driver redundant. Especially those which deals with runtime PM reference counting, so let's remove them. Moreover as SDHCI have its own wrapper functions for runtime PM these becomes superfluous, so let's remove them as well. Signed-off-by: Ulf Hansson Acked-by: Adrian Hunter diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 6bd3d17..8e74e75 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -56,19 +56,9 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); static int sdhci_do_get_cd(struct sdhci_host *host); #ifdef CONFIG_PM -static int sdhci_runtime_pm_get(struct sdhci_host *host); -static int sdhci_runtime_pm_put(struct sdhci_host *host); static void sdhci_runtime_pm_bus_on(struct sdhci_host *host); static void sdhci_runtime_pm_bus_off(struct sdhci_host *host); #else -static inline int sdhci_runtime_pm_get(struct sdhci_host *host) -{ - return 0; -} -static inline int sdhci_runtime_pm_put(struct sdhci_host *host) -{ - return 0; -} static void sdhci_runtime_pm_bus_on(struct sdhci_host *host) { } @@ -1319,8 +1309,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) host = mmc_priv(mmc); - sdhci_runtime_pm_get(host); - /* Firstly check card presence */ present = mmc->ops->get_cd(mmc); @@ -1567,9 +1555,7 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct sdhci_host *host = mmc_priv(mmc); - sdhci_runtime_pm_get(host); sdhci_do_set_ios(host, ios); - sdhci_runtime_pm_put(host); } static int sdhci_do_get_cd(struct sdhci_host *host) @@ -1601,12 +1587,8 @@ static int sdhci_do_get_cd(struct sdhci_host *host) static int sdhci_get_cd(struct mmc_host *mmc) { struct sdhci_host *host = mmc_priv(mmc); - int ret; - sdhci_runtime_pm_get(host); - ret = sdhci_do_get_cd(host); - sdhci_runtime_pm_put(host); - return ret; + return sdhci_do_get_cd(host); } static int sdhci_check_ro(struct sdhci_host *host) @@ -1662,12 +1644,8 @@ static void sdhci_hw_reset(struct mmc_host *mmc) static int sdhci_get_ro(struct mmc_host *mmc) { struct sdhci_host *host = mmc_priv(mmc); - int ret; - sdhci_runtime_pm_get(host); - ret = sdhci_do_get_ro(host); - sdhci_runtime_pm_put(host); - return ret; + return sdhci_do_get_ro(host); } static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable) @@ -1689,8 +1667,6 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) struct sdhci_host *host = mmc_priv(mmc); unsigned long flags; - sdhci_runtime_pm_get(host); - spin_lock_irqsave(&host->lock, flags); if (enable) host->flags |= SDHCI_SDIO_IRQ_ENABLED; @@ -1699,8 +1675,6 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) sdhci_enable_sdio_irq_nolock(host, enable); spin_unlock_irqrestore(&host->lock, flags); - - sdhci_runtime_pm_put(host); } static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, @@ -1798,14 +1772,11 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios) { struct sdhci_host *host = mmc_priv(mmc); - int err; if (host->version < SDHCI_SPEC_300) return 0; - sdhci_runtime_pm_get(host); - err = sdhci_do_start_signal_voltage_switch(host, ios); - sdhci_runtime_pm_put(host); - return err; + + return sdhci_do_start_signal_voltage_switch(host, ios); } static int sdhci_card_busy(struct mmc_host *mmc) @@ -1813,10 +1784,8 @@ static int sdhci_card_busy(struct mmc_host *mmc) struct sdhci_host *host = mmc_priv(mmc); u32 present_state; - sdhci_runtime_pm_get(host); /* Check whether DAT[3:0] is 0000 */ present_state = sdhci_readl(host, SDHCI_PRESENT_STATE); - sdhci_runtime_pm_put(host); return !(present_state & SDHCI_DATA_LVL_MASK); } @@ -1843,7 +1812,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) unsigned int tuning_count = 0; bool hs400_tuning; - sdhci_runtime_pm_get(host); spin_lock_irqsave(&host->lock, flags); hs400_tuning = host->flags & SDHCI_HS400_TUNING; @@ -1891,7 +1859,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) if (host->ops->platform_execute_tuning) { spin_unlock_irqrestore(&host->lock, flags); err = host->ops->platform_execute_tuning(host, opcode); - sdhci_runtime_pm_put(host); return err; } @@ -2023,8 +1990,6 @@ out: sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); out_unlock: spin_unlock_irqrestore(&host->lock, flags); - sdhci_runtime_pm_put(host); - return err; } @@ -2222,7 +2187,6 @@ static void sdhci_tasklet_finish(unsigned long param) spin_unlock_irqrestore(&host->lock, flags); mmc_request_done(host->mmc, mrq); - sdhci_runtime_pm_put(host); } static void sdhci_timeout_timer(unsigned long data) @@ -2703,17 +2667,6 @@ int sdhci_resume_host(struct sdhci_host *host) EXPORT_SYMBOL_GPL(sdhci_resume_host); -static int sdhci_runtime_pm_get(struct sdhci_host *host) -{ - return pm_runtime_get_sync(host->mmc->parent); -} - -static int sdhci_runtime_pm_put(struct sdhci_host *host) -{ - pm_runtime_mark_last_busy(host->mmc->parent); - return pm_runtime_put_autosuspend(host->mmc->parent); -} - static void sdhci_runtime_pm_bus_on(struct sdhci_host *host) { if (host->bus_on) -- cgit v0.10.2 From dc4c90fa6510ab8d5eb5e06fd7546c9cb00932c5 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 8 Apr 2016 14:22:37 +0900 Subject: mmc: sdhci-pic32: remove owner assignment A platform_driver does not need to set an owner, it will be populated by the driver core. Signed-off-by: Masahiro Yamada Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-pic32.c b/drivers/mmc/host/sdhci-pic32.c index 059df70..72c13b6 100644 --- a/drivers/mmc/host/sdhci-pic32.c +++ b/drivers/mmc/host/sdhci-pic32.c @@ -243,7 +243,6 @@ MODULE_DEVICE_TABLE(of, pic32_sdhci_id_table); static struct platform_driver pic32_sdhci_driver = { .driver = { .name = "pic32-sdhci", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(pic32_sdhci_id_table), }, .probe = pic32_sdhci_probe, -- cgit v0.10.2 From 02d0b68524c0848f5de89a0ecd1e97790018d7d3 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 11 Apr 2016 15:32:41 +0200 Subject: mmc: sdhci: Move sdhci_runtime_pm_bus_off|on() to avoid pre-definition There are no need to have two versions of sdhci_runtime_pm_bus_off|on(), depending on whether CONFIG_PM is set or unset. Thus it's easy to move the implementation of these functions a bit earlier to avoid the unnecessary pre-definition of them, so let's do that. Signed-off-by: Ulf Hansson Acked-by: Adrian Hunter diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 8e74e75..c6dbe65 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -55,18 +55,6 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); static int sdhci_do_get_cd(struct sdhci_host *host); -#ifdef CONFIG_PM -static void sdhci_runtime_pm_bus_on(struct sdhci_host *host); -static void sdhci_runtime_pm_bus_off(struct sdhci_host *host); -#else -static void sdhci_runtime_pm_bus_on(struct sdhci_host *host) -{ -} -static void sdhci_runtime_pm_bus_off(struct sdhci_host *host) -{ -} -#endif - static void sdhci_dumpregs(struct sdhci_host *host) { pr_debug(DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", @@ -161,6 +149,22 @@ static void sdhci_disable_card_detection(struct sdhci_host *host) sdhci_set_card_detection(host, false); } +static void sdhci_runtime_pm_bus_on(struct sdhci_host *host) +{ + if (host->bus_on) + return; + host->bus_on = true; + pm_runtime_get_noresume(host->mmc->parent); +} + +static void sdhci_runtime_pm_bus_off(struct sdhci_host *host) +{ + if (!host->bus_on) + return; + host->bus_on = false; + pm_runtime_put_noidle(host->mmc->parent); +} + void sdhci_reset(struct sdhci_host *host, u8 mask) { unsigned long timeout; @@ -2667,22 +2671,6 @@ int sdhci_resume_host(struct sdhci_host *host) EXPORT_SYMBOL_GPL(sdhci_resume_host); -static void sdhci_runtime_pm_bus_on(struct sdhci_host *host) -{ - if (host->bus_on) - return; - host->bus_on = true; - pm_runtime_get_noresume(host->mmc->parent); -} - -static void sdhci_runtime_pm_bus_off(struct sdhci_host *host) -{ - if (!host->bus_on) - return; - host->bus_on = false; - pm_runtime_put_noidle(host->mmc->parent); -} - int sdhci_runtime_suspend_host(struct sdhci_host *host) { unsigned long flags; -- cgit v0.10.2 From fb9ee04779cf34a10ef7afaabf4e8055688777c4 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 7 Apr 2016 11:13:08 +0200 Subject: mmc: sdhci: Introduce sdhci_calc_clk() In order to remove the SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST and to reduce code duplication, put the code relative to the SD clock configuration in a function which can be used by hosts for the implementation of the ->set_clock() callback. Signed-off-by: Ludovic Desroches Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index c6dbe65..aaf535a 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1085,23 +1085,14 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host) return preset; } -void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) +u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock, + unsigned int *actual_clock) { int div = 0; /* Initialized for compiler warning */ int real_div = div, clk_mul = 1; u16 clk = 0; - unsigned long timeout; bool switch_base_clk = false; - host->mmc->actual_clock = 0; - - sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); - if (host->quirks2 & SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST) - mdelay(1); - - if (clock == 0) - return; - if (host->version >= SDHCI_SPEC_300) { if (host->preset_enabled) { u16 pre_val; @@ -1178,10 +1169,31 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) clock_set: if (real_div) - host->mmc->actual_clock = (host->max_clk * clk_mul) / real_div; + *actual_clock = (host->max_clk * clk_mul) / real_div; clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) << SDHCI_DIVIDER_HI_SHIFT; + + return clk; +} +EXPORT_SYMBOL_GPL(sdhci_calc_clk); + +void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) +{ + u16 clk; + unsigned long timeout; + + host->mmc->actual_clock = 0; + + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + if (host->quirks2 & SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST) + mdelay(1); + + if (clock == 0) + return; + + clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); + clk |= SDHCI_CLOCK_INT_EN; sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 0f39f4f..9db5090 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -661,6 +661,8 @@ static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host) return !!(host->flags & SDHCI_SDIO_IRQ_ENABLED); } +u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock, + unsigned int *actual_clock); void sdhci_set_clock(struct sdhci_host *host, unsigned int clock); void sdhci_set_power(struct sdhci_host *host, unsigned char mode, unsigned short vdd); -- cgit v0.10.2 From 4e289a7d2f55253c1f86bfab5d9187ea97daee44 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 7 Apr 2016 11:13:09 +0200 Subject: mmc: sdhci-of-at91: Implement specific ->set_clock() function Disabling the internal clock while configuring the SD card clock can lead to internal clock stabilization issue and/or unexpected switch to the base clock when using presets. A quirk SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST was introduced to fix these bugs. The cause was assumed to be a too long internal re-synchronisation but it seems in some cases the delay (even if longer) doesn't fix this bug. The safest workaround is to not disable/enable the internal clock during the SD card clock configuration. Signed-off-by: Ludovic Desroches Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index 2703aa9..c1923c0 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -15,6 +15,7 @@ */ #include +#include #include #include #include @@ -37,8 +38,52 @@ struct sdhci_at91_priv { struct clk *mainck; }; +static void sdhci_at91_set_clock(struct sdhci_host *host, unsigned int clock) +{ + u16 clk; + unsigned long timeout; + + host->mmc->actual_clock = 0; + + /* + * There is no requirement to disable the internal clock before + * changing the SD clock configuration. Moreover, disabling the + * internal clock, changing the configuration and re-enabling the + * internal clock causes some bugs. It can prevent to get the internal + * clock stable flag ready and an unexpected switch to the base clock + * when using presets. + */ + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + clk &= SDHCI_CLOCK_INT_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + + if (clock == 0) + return; + + clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); + + clk |= SDHCI_CLOCK_INT_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); + + /* Wait max 20 ms */ + timeout = 20; + while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL)) + & SDHCI_CLOCK_INT_STABLE)) { + if (timeout == 0) { + pr_err("%s: Internal clock never stabilised.\n", + mmc_hostname(host->mmc)); + return; + } + timeout--; + mdelay(1); + } + + clk |= SDHCI_CLOCK_CARD_EN; + sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); +} + static const struct sdhci_ops sdhci_at91_sama5d2_ops = { - .set_clock = sdhci_set_clock, + .set_clock = sdhci_at91_set_clock, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, @@ -46,7 +91,6 @@ static const struct sdhci_ops sdhci_at91_sama5d2_ops = { static const struct sdhci_pltfm_data soc_data_sama5d2 = { .ops = &sdhci_at91_sama5d2_ops, - .quirks2 = SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST, }; static const struct of_device_id sdhci_at91_dt_match[] = { -- cgit v0.10.2 From 7758229135e30d3f58378969eefb41aecc620a9d Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 7 Apr 2016 11:13:10 +0200 Subject: mmc: sdhci: Remove SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST quirk is not used anymore so remove it. Signed-off-by: Ludovic Desroches Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index aaf535a..dd1efed 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1186,8 +1186,6 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) host->mmc->actual_clock = 0; sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); - if (host->quirks2 & SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST) - mdelay(1); if (clock == 0) return; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 9db5090..0decc85 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -417,11 +417,6 @@ struct sdhci_host { #define SDHCI_QUIRK2_ACMD23_BROKEN (1<<14) /* Broken Clock divider zero in controller */ #define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1<<15) -/* - * When internal clock is disabled, a delay is needed before modifying the - * SD clock frequency or enabling back the internal clock. - */ -#define SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST (1<<16) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ -- cgit v0.10.2 From e8ef51763106dc40037c9ae207acf505bb4b71b1 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 12 Apr 2016 14:25:05 +0300 Subject: mmc: sdhci-pci: Set MMC_CAP_AGGRESSIVE_PM for Broxton controllers Set MMC_CAP_AGGRESSIVE_PM for Broxton host controllers. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index e5c6a49..97d4eeb 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -386,8 +386,10 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) slot->cd_override_level = true; if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BXT_SD || slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BXTM_SD || - slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_APL_SD) + slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_APL_SD) { slot->host->mmc_host_ops.get_cd = bxt_get_cd; + slot->host->mmc->caps |= MMC_CAP_AGGRESSIVE_PM; + } return 0; } -- cgit v0.10.2 From 706e86e9de7cfd5220784f6329d92f65de883d71 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 12 Apr 2016 14:25:06 +0300 Subject: mmc: sdhci-acpi: Set MMC_CAP_AGGRESSIVE_PM for Broxton controllers Set MMC_CAP_AGGRESSIVE_PM for Broxton host controllers. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 2a0cda5..b2d70ba 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -262,8 +262,10 @@ static int sdhci_acpi_sd_probe_slot(struct platform_device *pdev, /* Platform specific code during sd probe slot goes here */ - if (hid && !strcmp(hid, "80865ACA")) + if (hid && !strcmp(hid, "80865ACA")) { host->mmc_host_ops.get_cd = bxt_get_cd; + host->mmc->caps |= MMC_CAP_AGGRESSIVE_PM; + } return 0; } -- cgit v0.10.2 From d310ae4936ccf1186851692c511483c794dd7701 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 12 Apr 2016 14:25:07 +0300 Subject: mmc: sdhci: Remove redundant condition The logic '!mmc.f_max || (mmc.f_max && mmc.f_max > max_clk)' is equivalent to '!mmc.f_max || mmc.f_max > max_clk'. Reported-by: David Binderman Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index dd1efed..73edf44 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3002,7 +3002,7 @@ int sdhci_add_host(struct sdhci_host *host) } else mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200; - if (!mmc->f_max || (mmc->f_max && (mmc->f_max > max_clk))) + if (!mmc->f_max || mmc->f_max > max_clk) mmc->f_max = max_clk; if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) { -- cgit v0.10.2 From eb5c20de351867120c8dfb6d523d5795a3125b02 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 12 Apr 2016 14:25:08 +0300 Subject: mmc: sdhci: Fix error paths in sdhci_add_host() Some error paths in sdhci_add_host() simply returned without cleaning up. Also the return value from mmc_add_host() was not being checked. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 73edf44..734f377 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2965,7 +2965,8 @@ int sdhci_add_host(struct sdhci_host *host) if (!host->ops->get_max_clock) { pr_err("%s: Hardware doesn't specify base clock frequency.\n", mmc_hostname(mmc)); - return -ENODEV; + ret = -ENODEV; + goto undma; } host->max_clk = host->ops->get_max_clock(host); } @@ -3015,7 +3016,8 @@ int sdhci_add_host(struct sdhci_host *host) } else { pr_err("%s: Hardware doesn't specify timeout clock frequency.\n", mmc_hostname(mmc)); - return -ENODEV; + ret = -ENODEV; + goto undma; } } @@ -3069,8 +3071,9 @@ int sdhci_add_host(struct sdhci_host *host) mmc->caps |= MMC_CAP_NEEDS_POLL; /* If there are external regulators, get them */ - if (mmc_regulator_get_supply(mmc) == -EPROBE_DEFER) - return -EPROBE_DEFER; + ret = mmc_regulator_get_supply(mmc); + if (ret == -EPROBE_DEFER) + goto undma; /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ if (!IS_ERR(mmc->supply.vqmmc)) { @@ -3227,7 +3230,8 @@ int sdhci_add_host(struct sdhci_host *host) if (mmc->ocr_avail == 0) { pr_err("%s: Hardware doesn't report any support voltages.\n", mmc_hostname(mmc)); - return -ENODEV; + ret = -ENODEV; + goto unreg; } spin_lock_init(&host->lock); @@ -3323,13 +3327,15 @@ int sdhci_add_host(struct sdhci_host *host) if (ret) { pr_err("%s: Failed to register LED device: %d\n", mmc_hostname(mmc), ret); - goto reset; + goto unirq; } #endif mmiowb(); - mmc_add_host(mmc); + ret = mmc_add_host(mmc); + if (ret) + goto unled; pr_info("%s: SDHCI controller on %s [%s] using %s\n", mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)), @@ -3341,15 +3347,27 @@ int sdhci_add_host(struct sdhci_host *host) return 0; +unled: #ifdef SDHCI_USE_LEDS_CLASS -reset: + led_classdev_unregister(&host->led); +unirq: +#endif sdhci_do_reset(host, SDHCI_RESET_ALL); sdhci_writel(host, 0, SDHCI_INT_ENABLE); sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE); free_irq(host->irq, host); -#endif untasklet: tasklet_kill(&host->finish_tasklet); +unreg: + if (!IS_ERR(mmc->supply.vqmmc)) + regulator_disable(mmc->supply.vqmmc); +undma: + if (host->align_buffer) + dma_free_coherent(mmc_dev(mmc), host->align_buffer_sz + + host->adma_table_sz, host->align_buffer, + host->align_addr); + host->adma_table = NULL; + host->align_buffer = NULL; return ret; } -- cgit v0.10.2 From 061d17a6664ec3e8c358e086c5c1ef26c943bff6 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 12 Apr 2016 14:25:09 +0300 Subject: mmc: sdhci: Tidy together LED code ifdef's make the code more complicated and harder to read. Move all the LED code together to reduce the ifdef's to one place. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 734f377..b284924 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -38,11 +38,6 @@ #define DBG(f, x...) \ pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x) -#if defined(CONFIG_LEDS_CLASS) || (defined(CONFIG_LEDS_CLASS_MODULE) && \ - defined(CONFIG_MMC_SDHCI_MODULE)) -#define SDHCI_USE_LEDS_CLASS -#endif - #define MAX_TUNING_LOOP 40 static unsigned int debug_quirks = 0; @@ -246,7 +241,7 @@ static void sdhci_reinit(struct sdhci_host *host) sdhci_enable_card_detection(host); } -static void sdhci_activate_led(struct sdhci_host *host) +static void __sdhci_led_activate(struct sdhci_host *host) { u8 ctrl; @@ -255,7 +250,7 @@ static void sdhci_activate_led(struct sdhci_host *host) sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); } -static void sdhci_deactivate_led(struct sdhci_host *host) +static void __sdhci_led_deactivate(struct sdhci_host *host) { u8 ctrl; @@ -264,9 +259,11 @@ static void sdhci_deactivate_led(struct sdhci_host *host) sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); } -#ifdef SDHCI_USE_LEDS_CLASS +#if defined(CONFIG_LEDS_CLASS) || (defined(CONFIG_LEDS_CLASS_MODULE) && \ + defined(CONFIG_MMC_SDHCI_MODULE)) + static void sdhci_led_control(struct led_classdev *led, - enum led_brightness brightness) + enum led_brightness brightness) { struct sdhci_host *host = container_of(led, struct sdhci_host, led); unsigned long flags; @@ -277,12 +274,62 @@ static void sdhci_led_control(struct led_classdev *led, goto out; if (brightness == LED_OFF) - sdhci_deactivate_led(host); + __sdhci_led_deactivate(host); else - sdhci_activate_led(host); + __sdhci_led_activate(host); out: spin_unlock_irqrestore(&host->lock, flags); } + +static int sdhci_led_register(struct sdhci_host *host) +{ + struct mmc_host *mmc = host->mmc; + + snprintf(host->led_name, sizeof(host->led_name), + "%s::", mmc_hostname(mmc)); + + host->led.name = host->led_name; + host->led.brightness = LED_OFF; + host->led.default_trigger = mmc_hostname(mmc); + host->led.brightness_set = sdhci_led_control; + + return led_classdev_register(mmc_dev(mmc), &host->led); +} + +static void sdhci_led_unregister(struct sdhci_host *host) +{ + led_classdev_unregister(&host->led); +} + +static inline void sdhci_led_activate(struct sdhci_host *host) +{ +} + +static inline void sdhci_led_deactivate(struct sdhci_host *host) +{ +} + +#else + +static inline int sdhci_led_register(struct sdhci_host *host) +{ + return 0; +} + +static inline void sdhci_led_unregister(struct sdhci_host *host) +{ +} + +static inline void sdhci_led_activate(struct sdhci_host *host) +{ + __sdhci_led_activate(host); +} + +static inline void sdhci_led_deactivate(struct sdhci_host *host) +{ + __sdhci_led_deactivate(host); +} + #endif /*****************************************************************************\ @@ -1330,9 +1377,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) WARN_ON(host->mrq != NULL); -#ifndef SDHCI_USE_LEDS_CLASS - sdhci_activate_led(host); -#endif + sdhci_led_activate(host); /* * Ensure we don't send the STOP for non-SET_BLOCK_COUNTED @@ -2193,9 +2238,7 @@ static void sdhci_tasklet_finish(unsigned long param) host->cmd = NULL; host->data = NULL; -#ifndef SDHCI_USE_LEDS_CLASS - sdhci_deactivate_led(host); -#endif + sdhci_led_deactivate(host); mmiowb(); spin_unlock_irqrestore(&host->lock, flags); @@ -3315,21 +3358,12 @@ int sdhci_add_host(struct sdhci_host *host) sdhci_dumpregs(host); #endif -#ifdef SDHCI_USE_LEDS_CLASS - snprintf(host->led_name, sizeof(host->led_name), - "%s::", mmc_hostname(mmc)); - host->led.name = host->led_name; - host->led.brightness = LED_OFF; - host->led.default_trigger = mmc_hostname(mmc); - host->led.brightness_set = sdhci_led_control; - - ret = led_classdev_register(mmc_dev(mmc), &host->led); + ret = sdhci_led_register(host); if (ret) { pr_err("%s: Failed to register LED device: %d\n", mmc_hostname(mmc), ret); goto unirq; } -#endif mmiowb(); @@ -3348,10 +3382,8 @@ int sdhci_add_host(struct sdhci_host *host) return 0; unled: -#ifdef SDHCI_USE_LEDS_CLASS - led_classdev_unregister(&host->led); + sdhci_led_unregister(host); unirq: -#endif sdhci_do_reset(host, SDHCI_RESET_ALL); sdhci_writel(host, 0, SDHCI_INT_ENABLE); sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE); @@ -3399,9 +3431,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) mmc_remove_host(mmc); -#ifdef SDHCI_USE_LEDS_CLASS - led_classdev_unregister(&host->led); -#endif + sdhci_led_unregister(host); if (!dead) sdhci_do_reset(host, SDHCI_RESET_ALL); -- cgit v0.10.2 From 5b96fea730ab79bdf6f8071cadf8208296bf5e8d Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 14 Apr 2016 14:02:14 +0100 Subject: mmc: pwrseq_simple: add to_pwrseq_simple() macro This patch adds to_pwrseq_simple() macro to make the code more readable. Signed-off-by: Srinivas Kandagatla Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c index bc173e1..f94271b 100644 --- a/drivers/mmc/core/pwrseq_simple.c +++ b/drivers/mmc/core/pwrseq_simple.c @@ -25,6 +25,8 @@ struct mmc_pwrseq_simple { struct gpio_descs *reset_gpios; }; +#define to_pwrseq_simple(p) container_of(p, struct mmc_pwrseq_simple, pwrseq) + static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq, int value) { @@ -44,8 +46,7 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq, static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host) { - struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, - struct mmc_pwrseq_simple, pwrseq); + struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq); if (!IS_ERR(pwrseq->ext_clk) && !pwrseq->clk_enabled) { clk_prepare_enable(pwrseq->ext_clk); @@ -57,16 +58,14 @@ static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host) static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host) { - struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, - struct mmc_pwrseq_simple, pwrseq); + struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq); mmc_pwrseq_simple_set_gpios_value(pwrseq, 0); } static void mmc_pwrseq_simple_power_off(struct mmc_host *host) { - struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, - struct mmc_pwrseq_simple, pwrseq); + struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq); mmc_pwrseq_simple_set_gpios_value(pwrseq, 1); @@ -78,8 +77,7 @@ static void mmc_pwrseq_simple_power_off(struct mmc_host *host) static void mmc_pwrseq_simple_free(struct mmc_host *host) { - struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq, - struct mmc_pwrseq_simple, pwrseq); + struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq); if (!IS_ERR(pwrseq->reset_gpios)) gpiod_put_array(pwrseq->reset_gpios); -- cgit v0.10.2 From f01b72d0fd53b61cafd25b16d15e18b1ef8ae065 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 14 Apr 2016 14:02:15 +0100 Subject: mmc: pwrseq_emmc: add to_pwrseq_emmc() macro This patch adds to_pwrseq_emmc() macro to make the code more readable. Signed-off-by: Srinivas Kandagatla Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c index 4a82bc7..c2d732a 100644 --- a/drivers/mmc/core/pwrseq_emmc.c +++ b/drivers/mmc/core/pwrseq_emmc.c @@ -25,6 +25,8 @@ struct mmc_pwrseq_emmc { struct gpio_desc *reset_gpio; }; +#define to_pwrseq_emmc(p) container_of(p, struct mmc_pwrseq_emmc, pwrseq) + static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq) { gpiod_set_value(pwrseq->reset_gpio, 1); @@ -35,16 +37,14 @@ static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq) static void mmc_pwrseq_emmc_reset(struct mmc_host *host) { - struct mmc_pwrseq_emmc *pwrseq = container_of(host->pwrseq, - struct mmc_pwrseq_emmc, pwrseq); + struct mmc_pwrseq_emmc *pwrseq = to_pwrseq_emmc(host->pwrseq); __mmc_pwrseq_emmc_reset(pwrseq); } static void mmc_pwrseq_emmc_free(struct mmc_host *host) { - struct mmc_pwrseq_emmc *pwrseq = container_of(host->pwrseq, - struct mmc_pwrseq_emmc, pwrseq); + struct mmc_pwrseq_emmc *pwrseq = to_pwrseq_emmc(host->pwrseq); unregister_restart_handler(&pwrseq->reset_nb); gpiod_put(pwrseq->reset_gpio); -- cgit v0.10.2 From d97a1e5d7cd2b5b0edc02a40fe6897b710c9e10f Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 14 Apr 2016 14:02:16 +0100 Subject: mmc: pwrseq: convert to proper platform device simple-pwrseq and emmc-pwrseq drivers rely on platform_device structure from of_find_device_by_node(), this works mostly. But, as there is no driver associated with this devices, cases like default/init pinctrl setup would never be performed by pwrseq. This becomes problem when the gpios used in pwrseq require pinctrl setup. Currently most of the common pinctrl setup is done in drivers/base/pinctrl.c by pinctrl_bind_pins(). There are two ways to solve this issue on either convert pwrseq drivers to a proper platform drivers or copy the exact code from pcintrl_bind_pins(). I prefer converting pwrseq to proper drivers so that other cases like setting up clks/parents from dt would also be possible. Signed-off-by: Srinivas Kandagatla Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig index 4c33d76..250f223 100644 --- a/drivers/mmc/core/Kconfig +++ b/drivers/mmc/core/Kconfig @@ -1,3 +1,24 @@ # # MMC core configuration # +config PWRSEQ_EMMC + tristate "HW reset support for eMMC" + default y + depends on OF + help + This selects Hardware reset support aka pwrseq-emmc for eMMC + devices. By default this option is set to y. + + This driver can also be built as a module. If so, the module + will be called pwrseq_emmc. + +config PWRSEQ_SIMPLE + tristate "Simple HW reset support for MMC" + default y + depends on OF + help + This selects simple hardware reset support aka pwrseq-simple for MMC + devices. By default this option is set to y. + + This driver can also be built as a module. If so, the module + will be called pwrseq_simple. diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile index 2c25138..f007151 100644 --- a/drivers/mmc/core/Makefile +++ b/drivers/mmc/core/Makefile @@ -8,5 +8,7 @@ mmc_core-y := core.o bus.o host.o \ sdio.o sdio_ops.o sdio_bus.o \ sdio_cis.o sdio_io.o sdio_irq.o \ quirks.o slot-gpio.o -mmc_core-$(CONFIG_OF) += pwrseq.o pwrseq_simple.o pwrseq_emmc.o +mmc_core-$(CONFIG_OF) += pwrseq.o +obj-$(CONFIG_PWRSEQ_SIMPLE) += pwrseq_simple.o +obj-$(CONFIG_PWRSEQ_EMMC) += pwrseq_emmc.o mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o diff --git a/drivers/mmc/core/pwrseq.c b/drivers/mmc/core/pwrseq.c index 4c1d175..9386c47 100644 --- a/drivers/mmc/core/pwrseq.c +++ b/drivers/mmc/core/pwrseq.c @@ -8,88 +8,55 @@ * MMC power sequence management */ #include -#include #include +#include #include -#include #include #include "pwrseq.h" -struct mmc_pwrseq_match { - const char *compatible; - struct mmc_pwrseq *(*alloc)(struct mmc_host *host, struct device *dev); -}; - -static struct mmc_pwrseq_match pwrseq_match[] = { - { - .compatible = "mmc-pwrseq-simple", - .alloc = mmc_pwrseq_simple_alloc, - }, { - .compatible = "mmc-pwrseq-emmc", - .alloc = mmc_pwrseq_emmc_alloc, - }, -}; - -static struct mmc_pwrseq_match *mmc_pwrseq_find(struct device_node *np) -{ - struct mmc_pwrseq_match *match = ERR_PTR(-ENODEV); - int i; - - for (i = 0; i < ARRAY_SIZE(pwrseq_match); i++) { - if (of_device_is_compatible(np, pwrseq_match[i].compatible)) { - match = &pwrseq_match[i]; - break; - } - } - - return match; -} +static DEFINE_MUTEX(pwrseq_list_mutex); +static LIST_HEAD(pwrseq_list); 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; + struct mmc_pwrseq *p; np = of_parse_phandle(host->parent->of_node, "mmc-pwrseq", 0); if (!np) return 0; - pdev = of_find_device_by_node(np); - if (!pdev) { - ret = -ENODEV; - goto err; - } + mutex_lock(&pwrseq_list_mutex); + list_for_each_entry(p, &pwrseq_list, pwrseq_node) { + if (p->dev->of_node == np) { + if (!try_module_get(p->owner)) + dev_err(host->parent, + "increasing module refcount failed\n"); + else + host->pwrseq = p; - match = mmc_pwrseq_find(np); - if (IS_ERR(match)) { - ret = PTR_ERR(match); - goto err; + break; + } } - pwrseq = match->alloc(host, &pdev->dev); - if (IS_ERR(pwrseq)) { - ret = PTR_ERR(pwrseq); - goto err; - } + of_node_put(np); + mutex_unlock(&pwrseq_list_mutex); + + if (!host->pwrseq) + return -EPROBE_DEFER; - host->pwrseq = pwrseq; dev_info(host->parent, "allocated mmc-pwrseq\n"); -err: - of_node_put(np); - return ret; + return 0; } void mmc_pwrseq_pre_power_on(struct mmc_host *host) { struct mmc_pwrseq *pwrseq = host->pwrseq; - if (pwrseq && pwrseq->ops && pwrseq->ops->pre_power_on) + if (pwrseq && pwrseq->ops->pre_power_on) pwrseq->ops->pre_power_on(host); } @@ -97,7 +64,7 @@ void mmc_pwrseq_post_power_on(struct mmc_host *host) { struct mmc_pwrseq *pwrseq = host->pwrseq; - if (pwrseq && pwrseq->ops && pwrseq->ops->post_power_on) + if (pwrseq && pwrseq->ops->post_power_on) pwrseq->ops->post_power_on(host); } @@ -105,7 +72,7 @@ void mmc_pwrseq_power_off(struct mmc_host *host) { struct mmc_pwrseq *pwrseq = host->pwrseq; - if (pwrseq && pwrseq->ops && pwrseq->ops->power_off) + if (pwrseq && pwrseq->ops->power_off) pwrseq->ops->power_off(host); } @@ -113,8 +80,31 @@ void mmc_pwrseq_free(struct mmc_host *host) { struct mmc_pwrseq *pwrseq = host->pwrseq; - if (pwrseq && pwrseq->ops && pwrseq->ops->free) - pwrseq->ops->free(host); + if (pwrseq) { + module_put(pwrseq->owner); + host->pwrseq = NULL; + } +} + +int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq) +{ + if (!pwrseq || !pwrseq->ops || !pwrseq->dev) + return -EINVAL; - host->pwrseq = NULL; + mutex_lock(&pwrseq_list_mutex); + list_add(&pwrseq->pwrseq_node, &pwrseq_list); + mutex_unlock(&pwrseq_list_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(mmc_pwrseq_register); + +void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq) +{ + if (pwrseq) { + mutex_lock(&pwrseq_list_mutex); + list_del(&pwrseq->pwrseq_node); + mutex_unlock(&pwrseq_list_mutex); + } } +EXPORT_SYMBOL_GPL(mmc_pwrseq_unregister); diff --git a/drivers/mmc/core/pwrseq.h b/drivers/mmc/core/pwrseq.h index 133de04..d69e751 100644 --- a/drivers/mmc/core/pwrseq.h +++ b/drivers/mmc/core/pwrseq.h @@ -8,32 +8,39 @@ #ifndef _MMC_CORE_PWRSEQ_H #define _MMC_CORE_PWRSEQ_H +#include + struct mmc_pwrseq_ops { void (*pre_power_on)(struct mmc_host *host); void (*post_power_on)(struct mmc_host *host); void (*power_off)(struct mmc_host *host); - void (*free)(struct mmc_host *host); }; struct mmc_pwrseq { const struct mmc_pwrseq_ops *ops; + struct device *dev; + struct list_head pwrseq_node; + struct module *owner; }; #ifdef CONFIG_OF +int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq); +void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq); + int mmc_pwrseq_alloc(struct mmc_host *host); void mmc_pwrseq_pre_power_on(struct mmc_host *host); 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); -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 +static inline int mmc_pwrseq_register(struct mmc_pwrseq *pwrseq) +{ + return -ENOSYS; +} +static inline void mmc_pwrseq_unregister(struct mmc_pwrseq *pwrseq) {} static inline int mmc_pwrseq_alloc(struct mmc_host *host) { return 0; } static inline void mmc_pwrseq_pre_power_on(struct mmc_host *host) {} static inline void mmc_pwrseq_post_power_on(struct mmc_host *host) {} diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c index c2d732a..adc9c0c 100644 --- a/drivers/mmc/core/pwrseq_emmc.c +++ b/drivers/mmc/core/pwrseq_emmc.c @@ -9,6 +9,9 @@ */ #include #include +#include +#include +#include #include #include #include @@ -42,20 +45,6 @@ static void mmc_pwrseq_emmc_reset(struct mmc_host *host) __mmc_pwrseq_emmc_reset(pwrseq); } -static void mmc_pwrseq_emmc_free(struct mmc_host *host) -{ - struct mmc_pwrseq_emmc *pwrseq = to_pwrseq_emmc(host->pwrseq); - - unregister_restart_handler(&pwrseq->reset_nb); - gpiod_put(pwrseq->reset_gpio); - kfree(pwrseq); -} - -static const struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = { - .post_power_on = mmc_pwrseq_emmc_reset, - .free = mmc_pwrseq_emmc_free, -}; - static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this, unsigned long mode, void *cmd) { @@ -66,21 +55,22 @@ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this, return NOTIFY_DONE; } -struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host, - struct device *dev) +static const struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = { + .post_power_on = mmc_pwrseq_emmc_reset, +}; + +static int mmc_pwrseq_emmc_probe(struct platform_device *pdev) { struct mmc_pwrseq_emmc *pwrseq; - int ret = 0; + struct device *dev = &pdev->dev; - pwrseq = kzalloc(sizeof(struct mmc_pwrseq_emmc), GFP_KERNEL); + pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL); if (!pwrseq) - return ERR_PTR(-ENOMEM); + return -ENOMEM; - pwrseq->reset_gpio = gpiod_get(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(pwrseq->reset_gpio)) { - ret = PTR_ERR(pwrseq->reset_gpio); - goto free; - } + pwrseq->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(pwrseq->reset_gpio)) + return PTR_ERR(pwrseq->reset_gpio); /* * register reset handler to ensure emmc reset also from @@ -92,9 +82,38 @@ struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host, register_restart_handler(&pwrseq->reset_nb); pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops; + pwrseq->pwrseq.dev = dev; + pwrseq->pwrseq.owner = THIS_MODULE; + platform_set_drvdata(pdev, pwrseq); + + return mmc_pwrseq_register(&pwrseq->pwrseq); +} + +static int mmc_pwrseq_emmc_remove(struct platform_device *pdev) +{ + struct mmc_pwrseq_emmc *pwrseq = platform_get_drvdata(pdev); + + unregister_restart_handler(&pwrseq->reset_nb); + mmc_pwrseq_unregister(&pwrseq->pwrseq); - return &pwrseq->pwrseq; -free: - kfree(pwrseq); - return ERR_PTR(ret); + return 0; } + +static const struct of_device_id mmc_pwrseq_emmc_of_match[] = { + { .compatible = "mmc-pwrseq-emmc",}, + {/* sentinel */}, +}; + +MODULE_DEVICE_TABLE(of, mmc_pwrseq_emmc_of_match); + +static struct platform_driver mmc_pwrseq_emmc_driver = { + .probe = mmc_pwrseq_emmc_probe, + .remove = mmc_pwrseq_emmc_remove, + .driver = { + .name = "pwrseq_emmc", + .of_match_table = mmc_pwrseq_emmc_of_match, + }, +}; + +module_platform_driver(mmc_pwrseq_emmc_driver); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c index f94271b..450d907 100644 --- a/drivers/mmc/core/pwrseq_simple.c +++ b/drivers/mmc/core/pwrseq_simple.c @@ -8,7 +8,10 @@ * Simple MMC power sequence management */ #include +#include #include +#include +#include #include #include #include @@ -75,58 +78,64 @@ static void mmc_pwrseq_simple_power_off(struct mmc_host *host) } } -static void mmc_pwrseq_simple_free(struct mmc_host *host) -{ - struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq); - - if (!IS_ERR(pwrseq->reset_gpios)) - gpiod_put_array(pwrseq->reset_gpios); - - if (!IS_ERR(pwrseq->ext_clk)) - clk_put(pwrseq->ext_clk); - - kfree(pwrseq); -} - static const struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = { .pre_power_on = mmc_pwrseq_simple_pre_power_on, .post_power_on = mmc_pwrseq_simple_post_power_on, .power_off = mmc_pwrseq_simple_power_off, - .free = mmc_pwrseq_simple_free, }; -struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host, - struct device *dev) +static const struct of_device_id mmc_pwrseq_simple_of_match[] = { + { .compatible = "mmc-pwrseq-simple",}, + {/* sentinel */}, +}; +MODULE_DEVICE_TABLE(of, mmc_pwrseq_simple_of_match); + +static int mmc_pwrseq_simple_probe(struct platform_device *pdev) { struct mmc_pwrseq_simple *pwrseq; - int ret = 0; + struct device *dev = &pdev->dev; - pwrseq = kzalloc(sizeof(*pwrseq), GFP_KERNEL); + pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL); if (!pwrseq) - return ERR_PTR(-ENOMEM); + return -ENOMEM; - pwrseq->ext_clk = clk_get(dev, "ext_clock"); - if (IS_ERR(pwrseq->ext_clk) && - PTR_ERR(pwrseq->ext_clk) != -ENOENT) { - ret = PTR_ERR(pwrseq->ext_clk); - goto free; - } + pwrseq->ext_clk = devm_clk_get(dev, "ext_clock"); + if (IS_ERR(pwrseq->ext_clk) && PTR_ERR(pwrseq->ext_clk) != -ENOENT) + return PTR_ERR(pwrseq->ext_clk); - pwrseq->reset_gpios = gpiod_get_array(dev, "reset", GPIOD_OUT_HIGH); + pwrseq->reset_gpios = devm_gpiod_get_array(dev, "reset", + GPIOD_OUT_HIGH); if (IS_ERR(pwrseq->reset_gpios) && PTR_ERR(pwrseq->reset_gpios) != -ENOENT && PTR_ERR(pwrseq->reset_gpios) != -ENOSYS) { - ret = PTR_ERR(pwrseq->reset_gpios); - goto clk_put; + return PTR_ERR(pwrseq->reset_gpios); } + pwrseq->pwrseq.dev = dev; pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops; + pwrseq->pwrseq.owner = THIS_MODULE; + platform_set_drvdata(pdev, pwrseq); - return &pwrseq->pwrseq; -clk_put: - if (!IS_ERR(pwrseq->ext_clk)) - clk_put(pwrseq->ext_clk); -free: - kfree(pwrseq); - return ERR_PTR(ret); + return mmc_pwrseq_register(&pwrseq->pwrseq); } + +static int mmc_pwrseq_simple_remove(struct platform_device *pdev) +{ + struct mmc_pwrseq_simple *pwrseq = platform_get_drvdata(pdev); + + mmc_pwrseq_unregister(&pwrseq->pwrseq); + + return 0; +} + +static struct platform_driver mmc_pwrseq_simple_driver = { + .probe = mmc_pwrseq_simple_probe, + .remove = mmc_pwrseq_simple_remove, + .driver = { + .name = "pwrseq_simple", + .of_match_table = mmc_pwrseq_simple_of_match, + }, +}; + +module_platform_driver(mmc_pwrseq_simple_driver); +MODULE_LICENSE("GPL v2"); -- cgit v0.10.2 From 87e88659afd1dc17d123f5759184254897494579 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 15 Apr 2016 20:16:12 +0900 Subject: mmc: core: drop unnecessary bit checking This if-block is going to call mmc_card_set_blockaddr(), so mmc_card_blockaddr() right before it is redundant. I am fixing the block comment style while I am here. Signed-off-by: Masahiro Yamada Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index b8aa12c..28b477d 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1483,12 +1483,13 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, if (err) goto free_card; - /* If doing byte addressing, check if required to do sector + /* + * If doing byte addressing, check if required to do sector * addressing. Handle the case of <2GB cards needing sector * addressing. See section 8.1 JEDEC Standard JED84-A441; * ocr register has bit 30 set for sector addressing. */ - if (!(mmc_card_blockaddr(card)) && (rocr & (1<<30))) + if (rocr & BIT(30)) mmc_card_set_blockaddr(card); /* Erase size depends on CSD and Extended CSD */ -- cgit v0.10.2 From 0b2ed795e1f49dace195f3a4d35eee281b6cfbbf Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Apr 2016 11:16:25 +0900 Subject: mmc: sdhci-pltfm: drop error message for too small MMIO resource size The requirement resource_size >= 0x100 may not necessarily be reasonable; for example, sdhci-dove appears to sidestep some registers in sdhci_dove_readw(). Moreover, current code displays an error message for too small resource size, but still moves forward. Every DT should be responsible for describing its properties correctly, so lets's remove this error message from the common framework. Signed-off-by: Masahiro Yamada Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 072bb27..03dbdeb 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -127,9 +127,6 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, goto err; } - if (resource_size(iomem) < 0x100) - dev_err(&pdev->dev, "Invalid iomem size!\n"); - host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pltfm_host) + priv_size); -- cgit v0.10.2 From 0a782cb1fc2407163123fccd01f65da70d4d2cd8 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Apr 2016 11:16:26 +0900 Subject: mmc: sdhci-pltfm: check return value of platform_get_irq() The function platform_get_irq() can fail; it returns a negative error code on failure. A negative IRQ number will make sdhci_add_host() fail to request IRQ anyway, but it makes sense to let it fail earlier here. Signed-off-by: Masahiro Yamada Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 03dbdeb..24377a3 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -146,6 +146,11 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, } host->irq = platform_get_irq(pdev, 0); + if (host->irq < 0) { + dev_err(&pdev->dev, "failed to get IRQ number\n"); + ret = host->irq; + goto err_request; + } if (!request_mem_region(iomem->start, resource_size(iomem), mmc_hostname(host->mmc))) { -- cgit v0.10.2 From e95f644d8b112647a8da5314e5e93b59ac8d3f08 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Apr 2016 11:16:27 +0900 Subject: mmc: sdhci-pltfm: use devm_request_mem_region() Use the managed variant of request_mem_region(). Signed-off-by: Masahiro Yamada Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 24377a3..8527a7c 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -152,8 +152,9 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, goto err_request; } - if (!request_mem_region(iomem->start, resource_size(iomem), - mmc_hostname(host->mmc))) { + if (!devm_request_mem_region(&pdev->dev, iomem->start, + resource_size(iomem), + mmc_hostname(host->mmc))) { dev_err(&pdev->dev, "cannot request region\n"); ret = -EBUSY; goto err_request; @@ -163,7 +164,7 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, if (!host->ioaddr) { dev_err(&pdev->dev, "failed to remap registers\n"); ret = -ENOMEM; - goto err_remap; + goto err_request; } /* @@ -177,8 +178,6 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, return host; -err_remap: - release_mem_region(iomem->start, resource_size(iomem)); err_request: sdhci_free_host(host); err: @@ -190,10 +189,8 @@ EXPORT_SYMBOL_GPL(sdhci_pltfm_init); void sdhci_pltfm_free(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); - struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); iounmap(host->ioaddr); - release_mem_region(iomem->start, resource_size(iomem)); sdhci_free_host(host); } EXPORT_SYMBOL_GPL(sdhci_pltfm_free); -- cgit v0.10.2 From 6113d8123624210fbc9412a1959d230fbd6ccf0d Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Apr 2016 11:16:28 +0900 Subject: mmc: sdhci-pltfm: use devm_ioremap() Use the managed variant of ioremap(). Signed-off-by: Masahiro Yamada Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 8527a7c..5213287 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -160,7 +160,8 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, goto err_request; } - host->ioaddr = ioremap(iomem->start, resource_size(iomem)); + host->ioaddr = devm_ioremap(&pdev->dev, iomem->start, + resource_size(iomem)); if (!host->ioaddr) { dev_err(&pdev->dev, "failed to remap registers\n"); ret = -ENOMEM; @@ -190,7 +191,6 @@ void sdhci_pltfm_free(struct platform_device *pdev) { struct sdhci_host *host = platform_get_drvdata(pdev); - iounmap(host->ioaddr); sdhci_free_host(host); } EXPORT_SYMBOL_GPL(sdhci_pltfm_free); -- cgit v0.10.2 From e30568d43f5ea63e61906d2a90c9b981ef829ff7 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Apr 2016 11:16:29 +0900 Subject: mmc: sdhci-pltfm: use devm_ioremap_resource() The chain of devm_request_mem_region() and devm_ioremap() can be replaced with devm_ioremap_resource(). Also, we can drop the error messages because devm_ioremap_resource() displays similar messages on error. Signed-off-by: Masahiro Yamada Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 5213287..caa05d7 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -152,19 +152,9 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, goto err_request; } - if (!devm_request_mem_region(&pdev->dev, iomem->start, - resource_size(iomem), - mmc_hostname(host->mmc))) { - dev_err(&pdev->dev, "cannot request region\n"); - ret = -EBUSY; - goto err_request; - } - - host->ioaddr = devm_ioremap(&pdev->dev, iomem->start, - resource_size(iomem)); - if (!host->ioaddr) { - dev_err(&pdev->dev, "failed to remap registers\n"); - ret = -ENOMEM; + host->ioaddr = devm_ioremap_resource(&pdev->dev, iomem); + if (IS_ERR(host->ioaddr)) { + ret = PTR_ERR(host->ioaddr); goto err_request; } -- cgit v0.10.2 From 378382b8d09d43371872103a58e4d4a7ff14b556 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Apr 2016 11:16:30 +0900 Subject: mmc: sdhci-pltfm: move devm_ioremap_resource() up Call devm_ioremap_resource() right after platform_get_resource(). This saves the error check of platform_get_resource() because devm_ioremap_resource() checks if the given resource is NULL. Signed-off-by: Masahiro Yamada Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index caa05d7..1d74db8 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -119,11 +119,13 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, { struct sdhci_host *host; struct resource *iomem; + void __iomem *ioaddr; int ret; iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iomem) { - ret = -ENOMEM; + ioaddr = devm_ioremap_resource(&pdev->dev, iomem); + if (IS_ERR(ioaddr)) { + ret = PTR_ERR(ioaddr); goto err; } @@ -135,6 +137,7 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, goto err; } + host->ioaddr = ioaddr; host->hw_name = dev_name(&pdev->dev); if (pdata && pdata->ops) host->ops = pdata->ops; @@ -152,12 +155,6 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, goto err_request; } - host->ioaddr = devm_ioremap_resource(&pdev->dev, iomem); - if (IS_ERR(host->ioaddr)) { - ret = PTR_ERR(host->ioaddr); - goto err_request; - } - /* * Some platforms need to probe the controller to be able to * determine which caps should be used. -- cgit v0.10.2 From 5c59065be5a1b347e06d1ad57e017ae2992e606a Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 20 Apr 2016 11:16:31 +0900 Subject: mmc: sdhci-pltfm: call platform_get_irq() before sdhci_alloc_host() Swap the call order of sdhci_alloc_host() and platform_get_irq(). It makes sdhci_alloc_host() the last function that can fail in the sdhci_pltfm_init(). So, we can drop the sdhci_free_host() call from the failure path. Signed-off-by: Masahiro Yamada Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 1d74db8..64f287a 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -120,7 +120,7 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, struct sdhci_host *host; struct resource *iomem; void __iomem *ioaddr; - int ret; + int irq, ret; iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ioaddr = devm_ioremap_resource(&pdev->dev, iomem); @@ -129,6 +129,13 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, goto err; } + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get IRQ number\n"); + ret = irq; + goto err; + } + host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pltfm_host) + priv_size); @@ -138,6 +145,7 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, } host->ioaddr = ioaddr; + host->irq = irq; host->hw_name = dev_name(&pdev->dev); if (pdata && pdata->ops) host->ops = pdata->ops; @@ -148,13 +156,6 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, host->quirks2 = pdata->quirks2; } - host->irq = platform_get_irq(pdev, 0); - if (host->irq < 0) { - dev_err(&pdev->dev, "failed to get IRQ number\n"); - ret = host->irq; - goto err_request; - } - /* * Some platforms need to probe the controller to be able to * determine which caps should be used. @@ -165,9 +166,6 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, platform_set_drvdata(pdev, host); return host; - -err_request: - sdhci_free_host(host); err: dev_err(&pdev->dev, "%s failed %d\n", __func__, ret); return ERR_PTR(ret); -- cgit v0.10.2 From 4228b21390f55616e50d2cfa3a374489b930a130 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 20 Apr 2016 09:24:03 +0300 Subject: mmc: sdhci: Remove SDHCI_SDR104_NEEDS_TUNING SDHCI_SDR104_NEEDS_TUNING was originally named SDHCI_HS200_NEEDS_TUNING and was added in commit 069c9f142822 ("mmc: host: Adds support for eMMC 4.5 HS200 mode"). That commit conflated SDHCI_SDR50_NEEDS_TUNING and SDHCI_HS200_NEEDS_TUNING due to what appears to be misplaced parentheses. Commit 156e14b126ff ("mmc: sdhci: fix caps2 for HS200") made HS200 configuration equivalent to SDR104 configuration, renaming SDHCI_HS200_NEEDS_TUNING to SDHCI_SDR104_NEEDS_TUNING despite tuning for HS200 now being non-optional. The mix-up with SDHCI_SDR50_NEEDS_TUNING remained and became more obvious after commit 4b6f37d3a379 ("mmc: sdhci: clean up sdhci_execute_tuning() decision") where the author noted the patch was "reflecting what the original code was doing, it shows that it may not be what the author actually intended." The way the code is currently written, SDHCI_SDR104_NEEDS_TUNING causes tuning to be done always for SDR50 mode if SDR104 mode is also supported by the host controller. That makes no sense because we already have capabilities bit SDHCI_USE_SDR50_TUNING and corresponding flag SDHCI_SDR50_NEEDS_TUNING for that purpose. Given the dubious origins of SDHCI_SDR104_NEEDS_TUNING, it seems reasonable to remove it. The benefit being SDR50 mode will now not un-nessessarily do tuning. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index b284924..a26c399 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1906,8 +1906,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) break; case MMC_TIMING_UHS_SDR50: - if (host->flags & SDHCI_SDR50_NEEDS_TUNING || - host->flags & SDHCI_SDR104_NEEDS_TUNING) + if (host->flags & SDHCI_SDR50_NEEDS_TUNING) break; /* FALLTHROUGH */ @@ -3171,10 +3170,6 @@ int sdhci_add_host(struct sdhci_host *host) if (caps[1] & SDHCI_USE_SDR50_TUNING) host->flags |= SDHCI_SDR50_NEEDS_TUNING; - /* Does the host need tuning for SDR104 / HS200? */ - if (mmc->caps2 & MMC_CAP2_HS200) - host->flags |= SDHCI_SDR104_NEEDS_TUNING; - /* Driver Type(s) (A, C, D) supported by the host */ if (caps[1] & SDHCI_DRIVER_TYPE_A) mmc->caps |= MMC_CAP_DRIVER_TYPE_A; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 0decc85..502627d 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -445,7 +445,6 @@ struct sdhci_host { #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_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */ #define SDHCI_HS400_TUNING (1<<13) /* Tuning for HS400 */ -- cgit v0.10.2 From 4f78230fd79d6f9e659f205b4ab0799e1635554d Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 14 Apr 2016 13:19:39 +0900 Subject: mmc: sdhci: use IS_REACHABLE(CONFIG_LEDS_CLASS) to enable LED code defined(CONFIG_LEDS_CLASS) || (defined(CONFIG_LEDS_CLASS_MODULE) && \ defined(CONFIG_MMC_SDHCI_MODULE)) is equivalent to: defined(CONFIG_LEDS_CLASS) || (defined(CONFIG_LEDS_CLASS_MODULE) && \ defined(MODULE)) and it can also be written shortly as: IS_REACHABLE(CONFIG_LEDS_CLASS) Signed-off-by: Masahiro Yamada Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index a26c399..94cffa7 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -259,9 +259,7 @@ static void __sdhci_led_deactivate(struct sdhci_host *host) sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); } -#if defined(CONFIG_LEDS_CLASS) || (defined(CONFIG_LEDS_CLASS_MODULE) && \ - defined(CONFIG_MMC_SDHCI_MODULE)) - +#if IS_REACHABLE(CONFIG_LEDS_CLASS) static void sdhci_led_control(struct led_classdev *led, enum led_brightness brightness) { -- cgit v0.10.2 From 74479c5d5009ebe28de69dd67b769c05ad953a5c Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 14 Apr 2016 13:19:40 +0900 Subject: mmc: sdhci: use IS_ENABLE(CONFIG_LEDS_CLASS) to enable LED struct members defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) is equivalent to: IS_ENABLED(CONFIG_LEDS_CLASS) Signed-off-by: Masahiro Yamada Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 502627d..609f87c 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -428,7 +428,7 @@ struct sdhci_host { struct mmc_host_ops mmc_host_ops; /* MMC host ops */ u64 dma_mask; /* custom DMA mask */ -#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) +#if IS_ENABLED(CONFIG_LEDS_CLASS) struct led_classdev led; /* LED control */ char led_name[32]; #endif -- cgit v0.10.2 From 5674a9baba32dfff9585bd50e604a06bc9b1c2b8 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 7 Apr 2016 11:40:59 +0200 Subject: mmc: core: Convert from IDR to IDA for host indexes As IDA is more lightweight than IDR, let's convert to use that instead. Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 6e4c55a..e0a3ee1 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -33,14 +33,14 @@ #define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev) -static DEFINE_IDR(mmc_host_idr); +static DEFINE_IDA(mmc_host_ida); static DEFINE_SPINLOCK(mmc_host_lock); static void mmc_host_classdev_release(struct device *dev) { struct mmc_host *host = cls_dev_to_mmc_host(dev); spin_lock(&mmc_host_lock); - idr_remove(&mmc_host_idr, host->index); + ida_remove(&mmc_host_ida, host->index); spin_unlock(&mmc_host_lock); kfree(host); } @@ -321,14 +321,20 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) /* scanning will be enabled when we're ready */ host->rescan_disable = 1; - idr_preload(GFP_KERNEL); + +again: + if (!ida_pre_get(&mmc_host_ida, GFP_KERNEL)) { + kfree(host); + return NULL; + } + spin_lock(&mmc_host_lock); - err = idr_alloc(&mmc_host_idr, host, 0, 0, GFP_NOWAIT); - if (err >= 0) - host->index = err; + err = ida_get_new(&mmc_host_ida, &host->index); spin_unlock(&mmc_host_lock); - idr_preload_end(); - if (err < 0) { + + if (err == -EAGAIN) { + goto again; + } else if (err) { kfree(host); return NULL; } -- cgit v0.10.2 From 06b5cca5e7f797b8fffa269fa6298a84256c3295 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 7 Apr 2016 14:23:23 +0200 Subject: mmc: block: Release index in partition allocation error path If the allocation of a new partition fails, let's make sure to also release the previously picked device index. Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 8a0147d..9aaf22e 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -2289,6 +2289,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, err_kfree: kfree(md); out: + __clear_bit(devidx, dev_use); return ERR_PTR(ret); } -- cgit v0.10.2 From b10fa99e9a5f8b37a4eae1522048a327fe7ce480 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 7 Apr 2016 14:36:46 +0200 Subject: mmc: block: Convert to IDA for partition device indexes Instead of using an mmc specific implementation to deal with indexes through a BITMAP, let's convert to use the IDA library. Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 9aaf22e..9ce6792 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -78,14 +79,14 @@ static int perdev_minors = CONFIG_MMC_BLOCK_MINORS; /* * We've only got one major, so number of mmcblk devices is * limited to (1 << 20) / number of minors per device. It is also - * currently limited by the size of the static bitmaps below. + * limited by the MAX_DEVICES below. */ static int max_devices; #define MAX_DEVICES 256 -/* TODO: Replace these with struct ida */ -static DECLARE_BITMAP(dev_use, MAX_DEVICES); +static DEFINE_IDA(mmc_blk_ida); +static DEFINE_SPINLOCK(mmc_blk_lock); /* * There is one mmc_blk_data per slot. @@ -178,7 +179,9 @@ static void mmc_blk_put(struct mmc_blk_data *md) int devidx = mmc_get_devidx(md->disk); blk_cleanup_queue(md->queue.queue); - __clear_bit(devidx, dev_use); + spin_lock(&mmc_blk_lock); + ida_remove(&mmc_blk_ida, devidx); + spin_unlock(&mmc_blk_lock); put_disk(md->disk); kfree(md); @@ -2189,10 +2192,23 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, struct mmc_blk_data *md; int devidx, ret; - devidx = find_first_zero_bit(dev_use, max_devices); - if (devidx >= max_devices) - return ERR_PTR(-ENOSPC); - __set_bit(devidx, dev_use); +again: + if (!ida_pre_get(&mmc_blk_ida, GFP_KERNEL)) + return ERR_PTR(-ENOMEM); + + spin_lock(&mmc_blk_lock); + ret = ida_get_new(&mmc_blk_ida, &devidx); + spin_unlock(&mmc_blk_lock); + + if (ret == -EAGAIN) + goto again; + else if (ret) + return ERR_PTR(ret); + + if (devidx >= max_devices) { + ret = -ENOSPC; + goto out; + } md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL); if (!md) { @@ -2289,7 +2305,9 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, err_kfree: kfree(md); out: - __clear_bit(devidx, dev_use); + spin_lock(&mmc_blk_lock); + ida_remove(&mmc_blk_ida, devidx); + spin_unlock(&mmc_blk_lock); return ERR_PTR(ret); } -- cgit v0.10.2 From 13bbd8af65895c524c27850495fadf23449f9f3d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 26 Apr 2016 17:55:22 +0200 Subject: mmc: sh_mobile_sdhi: don't use array for DT configs We won't access an index based array to get our DT config, but create separate structs instead. So, remove the array which only wastes memory. Signed-off-by: Wolfram Sang Acked-by: Arnd Bergmann Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 3c23027..ec6f4b6 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -51,10 +51,8 @@ struct sh_mobile_sdhi_of_data { unsigned bus_shift; }; -static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = { - { - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, - }, +static const struct sh_mobile_sdhi_of_data of_default_cfg = { + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT, }; static const struct sh_mobile_sdhi_of_data of_rcar_gen1_compatible = { @@ -81,9 +79,9 @@ static const struct sh_mobile_sdhi_of_data of_rcar_gen3_compatible = { static const struct of_device_id sh_mobile_sdhi_of_match[] = { { .compatible = "renesas,sdhi-shmobile" }, { .compatible = "renesas,sdhi-sh7372" }, - { .compatible = "renesas,sdhi-sh73a0", .data = &sh_mobile_sdhi_of_cfg[0], }, - { .compatible = "renesas,sdhi-r8a73a4", .data = &sh_mobile_sdhi_of_cfg[0], }, - { .compatible = "renesas,sdhi-r8a7740", .data = &sh_mobile_sdhi_of_cfg[0], }, + { .compatible = "renesas,sdhi-sh73a0", .data = &of_default_cfg, }, + { .compatible = "renesas,sdhi-r8a73a4", .data = &of_default_cfg, }, + { .compatible = "renesas,sdhi-r8a7740", .data = &of_default_cfg, }, { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, }, { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, }, { .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, }, -- cgit v0.10.2 From adcbc949046366edb46e44f72ac9197c32675cfd Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 26 Apr 2016 17:55:23 +0200 Subject: mmc: sh_mobile_sdhi: remove obsolete irq_by_name registration There is no user left in the kernel, so this code can be removed. (Legacy, non-DT sh_mobile boards have been removed a while ago.) The diff looks more complicated than it is: The if-block for multiplexed isr is now the main code path, the rest is removed. Signed-off-by: Wolfram Sang Acked-by: Arnd Bergmann Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index ec6f4b6..9c9bbb2 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -316,7 +315,6 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) struct tmio_mmc_host *host; struct resource *res; int irq, ret, i = 0; - bool multiplexed_isr = true; struct tmio_mmc_dma *dma_priv; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -408,62 +406,23 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) if (ret < 0) goto efree; - /* - * Allow one or more specific (named) ISRs or - * one or more multiplexed (un-named) ISRs. - */ - - irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_CARD_DETECT); - if (irq >= 0) { - multiplexed_isr = false; - ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_card_detect_irq, 0, + while (1) { + irq = platform_get_irq(pdev, i); + if (irq < 0) + break; + i++; + ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq, 0, dev_name(&pdev->dev), host); if (ret) goto eirq; } - irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDIO); - if (irq >= 0) { - multiplexed_isr = false; - ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_sdio_irq, 0, - dev_name(&pdev->dev), host); - if (ret) - goto eirq; - } - - irq = platform_get_irq_byname(pdev, SH_MOBILE_SDHI_IRQ_SDCARD); - if (irq >= 0) { - multiplexed_isr = false; - ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_sdcard_irq, 0, - dev_name(&pdev->dev), host); - if (ret) - goto eirq; - } else if (!multiplexed_isr) { - dev_err(&pdev->dev, - "Principal SD-card IRQ is missing among named interrupts\n"); + /* There must be at least one IRQ source */ + if (!i) { ret = irq; goto eirq; } - if (multiplexed_isr) { - while (1) { - irq = platform_get_irq(pdev, i); - if (irq < 0) - break; - i++; - ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq, 0, - dev_name(&pdev->dev), host); - if (ret) - goto eirq; - } - - /* There must be at least one IRQ source */ - if (!i) { - ret = irq; - goto eirq; - } - } - dev_info(&pdev->dev, "%s base at 0x%08lx max clock rate %u MHz\n", mmc_hostname(host->mmc), (unsigned long) (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start), -- cgit v0.10.2 From 4da986703882b2987b5731e8b31b88eece8c2fbb Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 26 Apr 2016 17:55:24 +0200 Subject: mmc: tmio: remove now unneeded seperate irq handlers We removed installation of separate handlers previously, so we can also remove the separate handlers. Signed-off-by: Wolfram Sang Acked-by: Arnd Bergmann Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index b1819c7..032188b 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -115,9 +115,6 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host); void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i); void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i); irqreturn_t tmio_mmc_irq(int irq, void *devid); -irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid); -irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid); -irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid); static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg, unsigned long *flags) diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 1dd1c04..3bcfd92 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -658,18 +658,6 @@ static bool __tmio_mmc_card_detect_irq(struct tmio_mmc_host *host, return false; } -irqreturn_t tmio_mmc_card_detect_irq(int irq, void *devid) -{ - unsigned int ireg, status; - struct tmio_mmc_host *host = devid; - - tmio_mmc_card_irq_status(host, &ireg, &status); - __tmio_mmc_card_detect_irq(host, ireg, status); - - return IRQ_HANDLED; -} -EXPORT_SYMBOL(tmio_mmc_card_detect_irq); - static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host, int ireg, int status) { @@ -699,19 +687,7 @@ static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host, return false; } -irqreturn_t tmio_mmc_sdcard_irq(int irq, void *devid) -{ - unsigned int ireg, status; - struct tmio_mmc_host *host = devid; - - tmio_mmc_card_irq_status(host, &ireg, &status); - __tmio_mmc_sdcard_irq(host, ireg, status); - - return IRQ_HANDLED; -} -EXPORT_SYMBOL(tmio_mmc_sdcard_irq); - -irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid) +static void tmio_mmc_sdio_irq(int irq, void *devid) { struct tmio_mmc_host *host = devid; struct mmc_host *mmc = host->mmc; @@ -720,7 +696,7 @@ irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid) unsigned int sdio_status; if (!(pdata->flags & TMIO_MMC_SDIO_IRQ)) - return IRQ_HANDLED; + return; status = sd_ctrl_read16(host, CTL_SDIO_STATUS); ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdcard_irq_mask; @@ -733,10 +709,7 @@ irqreturn_t tmio_mmc_sdio_irq(int irq, void *devid) if (mmc->caps & MMC_CAP_SDIO_IRQ && ireg & TMIO_SDIO_STAT_IOIRQ) mmc_signal_sdio_irq(mmc); - - return IRQ_HANDLED; } -EXPORT_SYMBOL(tmio_mmc_sdio_irq); irqreturn_t tmio_mmc_irq(int irq, void *devid) { -- cgit v0.10.2 From 958401266e5812619b04765bef23712a72badd55 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 26 Apr 2016 17:55:25 +0200 Subject: mmc: tmio: simplify irq handler Having just one irq handler again, let's include the 'card_status' function in the main handler which is way more readable. Drop a useless debug output while here. It should be a dev_dbg in case we ever need it again. Signed-off-by: Wolfram Sang Acked-by: Arnd Bergmann Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 3bcfd92..5712b42 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -626,19 +626,6 @@ out: spin_unlock(&host->lock); } -static void tmio_mmc_card_irq_status(struct tmio_mmc_host *host, - int *ireg, int *status) -{ - *status = sd_ctrl_read32(host, CTL_STATUS); - *ireg = *status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask; - - pr_debug_status(*status); - pr_debug_status(*ireg); - - /* Clear the status except the interrupt status */ - sd_ctrl_write32(host, CTL_STATUS, TMIO_MASK_IRQ); -} - static bool __tmio_mmc_card_detect_irq(struct tmio_mmc_host *host, int ireg, int status) { @@ -716,9 +703,15 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid) struct tmio_mmc_host *host = devid; unsigned int ireg, status; - pr_debug("MMC IRQ begin\n"); + status = sd_ctrl_read32(host, CTL_STATUS); + ireg = status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask; + + pr_debug_status(status); + pr_debug_status(ireg); + + /* Clear the status except the interrupt status */ + sd_ctrl_write32(host, CTL_STATUS, TMIO_MASK_IRQ); - tmio_mmc_card_irq_status(host, &ireg, &status); if (__tmio_mmc_card_detect_irq(host, ireg, status)) return IRQ_HANDLED; if (__tmio_mmc_sdcard_irq(host, ireg, status)) -- cgit v0.10.2 From ac86045ee9cd89774030ff1c21c7ff35f1c1eeaa Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 26 Apr 2016 17:55:26 +0200 Subject: mmc: tmio: merge distributed include files There is no reason to have a public and private header file. Merge them into a private one, so looking up symbols is less confusing. Signed-off-by: Wolfram Sang Acked-by: Arnd Bergmann Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 032188b..439fdad 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -1,6 +1,8 @@ /* * linux/drivers/mmc/host/tmio_mmc.h * + * Copyright (C) 2016 Sang Engineering, Wolfram Sang + * Copyright (C) 2015-16 Renesas Electronics Corporation * Copyright (C) 2007 Ian Molton * Copyright (C) 2004 Ian Molton * @@ -18,12 +20,64 @@ #include #include -#include #include #include #include #include +#define CTL_SD_CMD 0x00 +#define CTL_ARG_REG 0x04 +#define CTL_STOP_INTERNAL_ACTION 0x08 +#define CTL_XFER_BLK_COUNT 0xa +#define CTL_RESPONSE 0x0c +#define CTL_STATUS 0x1c +#define CTL_STATUS2 0x1e +#define CTL_IRQ_MASK 0x20 +#define CTL_SD_CARD_CLK_CTL 0x24 +#define CTL_SD_XFER_LEN 0x26 +#define CTL_SD_MEM_CARD_OPT 0x28 +#define CTL_SD_ERROR_DETAIL_STATUS 0x2c +#define CTL_SD_DATA_PORT 0x30 +#define CTL_TRANSACTION_CTL 0x34 +#define CTL_SDIO_STATUS 0x36 +#define CTL_SDIO_IRQ_MASK 0x38 +#define CTL_DMA_ENABLE 0xd8 +#define CTL_RESET_SD 0xe0 +#define CTL_VERSION 0xe2 +#define CTL_SDIO_REGS 0x100 +#define CTL_CLK_AND_WAIT_CTL 0x138 +#define CTL_RESET_SDIO 0x1e0 + +/* Definitions for values the CTRL_STATUS register can take. */ +#define TMIO_STAT_CMDRESPEND 0x00000001 +#define TMIO_STAT_DATAEND 0x00000004 +#define TMIO_STAT_CARD_REMOVE 0x00000008 +#define TMIO_STAT_CARD_INSERT 0x00000010 +#define TMIO_STAT_SIGSTATE 0x00000020 +#define TMIO_STAT_WRPROTECT 0x00000080 +#define TMIO_STAT_CARD_REMOVE_A 0x00000100 +#define TMIO_STAT_CARD_INSERT_A 0x00000200 +#define TMIO_STAT_SIGSTATE_A 0x00000400 +#define TMIO_STAT_CMD_IDX_ERR 0x00010000 +#define TMIO_STAT_CRCFAIL 0x00020000 +#define TMIO_STAT_STOPBIT_ERR 0x00040000 +#define TMIO_STAT_DATATIMEOUT 0x00080000 +#define TMIO_STAT_RXOVERFLOW 0x00100000 +#define TMIO_STAT_TXUNDERRUN 0x00200000 +#define TMIO_STAT_CMDTIMEOUT 0x00400000 +#define TMIO_STAT_RXRDY 0x01000000 +#define TMIO_STAT_TXRQ 0x02000000 +#define TMIO_STAT_ILL_FUNC 0x20000000 +#define TMIO_STAT_CMD_BUSY 0x40000000 +#define TMIO_STAT_ILL_ACCESS 0x80000000 + +#define TMIO_STATUS2_DAT0 BIT(7) + +#define CLK_CTL_DIV_MASK 0xff +#define CLK_CTL_SCLKEN BIT(8) + +#define TMIO_BBS 512 /* Boot block size */ + /* Definitions for values the CTRL_SDIO_STATUS register can take. */ #define TMIO_SDIO_STAT_IOIRQ 0x0001 #define TMIO_SDIO_STAT_EXPUB52 0x4000 diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c index 7fb0c03..fa8a936 100644 --- a/drivers/mmc/host/tmio_mmc_dma.c +++ b/drivers/mmc/host/tmio_mmc_dma.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 5712b42..0b52ef1 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include diff --git a/include/linux/mmc/tmio.h b/include/linux/mmc/tmio.h deleted file mode 100644 index b2f28e9..0000000 --- a/include/linux/mmc/tmio.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * include/linux/mmc/tmio.h - * - * Copyright (C) 2016 Sang Engineering, Wolfram Sang - * Copyright (C) 2015-16 Renesas Electronics Corporation - * Copyright (C) 2007 Ian Molton - * Copyright (C) 2004 Ian Molton - * - * 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. - * - * Driver for the MMC / SD / SDIO cell found in: - * - * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3 - */ -#ifndef LINUX_MMC_TMIO_H -#define LINUX_MMC_TMIO_H - -#define CTL_SD_CMD 0x00 -#define CTL_ARG_REG 0x04 -#define CTL_STOP_INTERNAL_ACTION 0x08 -#define CTL_XFER_BLK_COUNT 0xa -#define CTL_RESPONSE 0x0c -#define CTL_STATUS 0x1c -#define CTL_STATUS2 0x1e -#define CTL_IRQ_MASK 0x20 -#define CTL_SD_CARD_CLK_CTL 0x24 -#define CTL_SD_XFER_LEN 0x26 -#define CTL_SD_MEM_CARD_OPT 0x28 -#define CTL_SD_ERROR_DETAIL_STATUS 0x2c -#define CTL_SD_DATA_PORT 0x30 -#define CTL_TRANSACTION_CTL 0x34 -#define CTL_SDIO_STATUS 0x36 -#define CTL_SDIO_IRQ_MASK 0x38 -#define CTL_DMA_ENABLE 0xd8 -#define CTL_RESET_SD 0xe0 -#define CTL_VERSION 0xe2 -#define CTL_SDIO_REGS 0x100 -#define CTL_CLK_AND_WAIT_CTL 0x138 -#define CTL_RESET_SDIO 0x1e0 - -/* Definitions for values the CTRL_STATUS register can take. */ -#define TMIO_STAT_CMDRESPEND 0x00000001 -#define TMIO_STAT_DATAEND 0x00000004 -#define TMIO_STAT_CARD_REMOVE 0x00000008 -#define TMIO_STAT_CARD_INSERT 0x00000010 -#define TMIO_STAT_SIGSTATE 0x00000020 -#define TMIO_STAT_WRPROTECT 0x00000080 -#define TMIO_STAT_CARD_REMOVE_A 0x00000100 -#define TMIO_STAT_CARD_INSERT_A 0x00000200 -#define TMIO_STAT_SIGSTATE_A 0x00000400 -#define TMIO_STAT_CMD_IDX_ERR 0x00010000 -#define TMIO_STAT_CRCFAIL 0x00020000 -#define TMIO_STAT_STOPBIT_ERR 0x00040000 -#define TMIO_STAT_DATATIMEOUT 0x00080000 -#define TMIO_STAT_RXOVERFLOW 0x00100000 -#define TMIO_STAT_TXUNDERRUN 0x00200000 -#define TMIO_STAT_CMDTIMEOUT 0x00400000 -#define TMIO_STAT_RXRDY 0x01000000 -#define TMIO_STAT_TXRQ 0x02000000 -#define TMIO_STAT_ILL_FUNC 0x20000000 -#define TMIO_STAT_CMD_BUSY 0x40000000 -#define TMIO_STAT_ILL_ACCESS 0x80000000 - -#define TMIO_STATUS2_DAT0 BIT(7) - -#define CLK_CTL_DIV_MASK 0xff -#define CLK_CTL_SCLKEN BIT(8) - -#define TMIO_BBS 512 /* Boot block size */ - -#endif /* LINUX_MMC_TMIO_H */ -- cgit v0.10.2 From 2272c841ee301402ea7a01fc727619af1f97f0cc Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 26 Apr 2016 17:55:27 +0200 Subject: mmc: sh_mobile_sdhi: simplify code for voltage switching A last minute fix applied by Ulf made room for some simplification. Signed-off-by: Wolfram Sang Acked-by: Arnd Bergmann Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 9c9bbb2..04f15d9 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -238,11 +238,7 @@ static int sh_mobile_sdhi_start_signal_voltage_switch(struct mmc_host *mmc, if (ret) return ret; - ret = pinctrl_select_state(priv->pinctrl, pin_state); - if (ret) - return ret; - - return 0; + return pinctrl_select_state(priv->pinctrl, pin_state); } static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host) -- cgit v0.10.2 From ba9e91577843ad394a4908ea3acbbe4c78293557 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 26 Apr 2016 22:34:46 +0200 Subject: mmc: sh_mmcif: remove obsolete support for sh7372 There is no support for this platform in the kernel anymore. Make the Kconfig text more generic, so it won't get stale anymore. Reported-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang Acked-by: Geert Uytterhoeven Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index e657af0..0aa484c 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -677,9 +677,9 @@ config MMC_SH_MMCIF depends on HAS_DMA depends on SUPERH || ARCH_RENESAS || COMPILE_TEST help - This selects the MMC Host Interface controller (MMCIF). + This selects the MMC Host Interface controller (MMCIF) found in various + Renesas SoCs for SH and ARM architectures. - This driver supports MMCIF in sh7724/sh7757/sh7372. config MMC_JZ4740 tristate "JZ4740 SD/Multimedia Card Interface support" -- cgit v0.10.2 From ab22f516715086760cd01862d60afc0dd3ff30b3 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 26 Apr 2016 22:29:10 +0200 Subject: mmc: sh_mobile_sdhi: remove obsolete support for sh7372 There is no support for this platform in the kernel anymore. Reported-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang Acked-by: Geert Uytterhoeven Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 04f15d9..3bf68b4 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -77,7 +77,6 @@ static const struct sh_mobile_sdhi_of_data of_rcar_gen3_compatible = { static const struct of_device_id sh_mobile_sdhi_of_match[] = { { .compatible = "renesas,sdhi-shmobile" }, - { .compatible = "renesas,sdhi-sh7372" }, { .compatible = "renesas,sdhi-sh73a0", .data = &of_default_cfg, }, { .compatible = "renesas,sdhi-r8a73a4", .data = &of_default_cfg, }, { .compatible = "renesas,sdhi-r8a7740", .data = &of_default_cfg, }, -- cgit v0.10.2 From db863d8966818d3af3e415b5f60fcfeceba803c6 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 26 Apr 2016 16:46:23 -0700 Subject: mmc: omap_hsmmc: Check if MMC slot name is passed in pdata The legacy user space for n900 relies on the MMC slot names. Let's check if those are passed in pdata and use them. As this makes the DT booting compatible with legacy booting, we should be able to start dropping omap3 legacy booting support in v4.8. Cc: Ulf Hansson Cc: Kishon Vijay Abraham I Cc: linux-mmc@vger.kernel.org Signed-off-by: Tony Lindgren Tested-by: Ivaylo Dimitrov Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index e9d75c6..3563321 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1946,13 +1946,17 @@ MODULE_DEVICE_TABLE(of, omap_mmc_of_match); static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev) { - struct omap_hsmmc_platform_data *pdata; + struct omap_hsmmc_platform_data *pdata, *legacy; struct device_node *np = dev->of_node; pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return ERR_PTR(-ENOMEM); /* out of memory */ + legacy = dev_get_platdata(dev); + if (legacy && legacy->name) + pdata->name = legacy->name; + if (of_find_property(np, "ti,dual-volt", NULL)) pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT; -- cgit v0.10.2 From 2c54506b769d0633aac8f0511ef23f76bedeec9e Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 27 Apr 2016 18:51:23 +0200 Subject: mmc: tmio: give read32/write32 functions more descriptive names Looking at the backlogs, I am not the only one who missed that the above functions do not read u32 from one register, but create a virtual u32 from reading to adjacent u16 registers (which depending on 'bus_shift' can be up to 8 byte apart). Because this driver supports old hardware for which we don't have documentation, I first wrongly assumed there was a variant which had a few u32 registers. Let's give the functions more descriptive names to make it more obvious what is happening. Reviewed-by: Simon Horman Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 439fdad..e75e5ca 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -232,7 +232,7 @@ static inline void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr, readsw(host->ctl + (addr << host->bus_shift), buf, count); } -static inline u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr) +static inline u32 sd_ctrl_read16_and_16_as_32(struct tmio_mmc_host *host, int addr) { return readw(host->ctl + (addr << host->bus_shift)) | readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16; @@ -254,11 +254,10 @@ static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr, writesw(host->ctl + (addr << host->bus_shift), buf, count); } -static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val) +static inline void sd_ctrl_write32_as_16_and_16(struct tmio_mmc_host *host, int addr, u32 val) { writew(val, host->ctl + (addr << host->bus_shift)); writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift)); } - #endif diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 0b52ef1..3635940 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -55,18 +55,18 @@ void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i) { host->sdcard_irq_mask &= ~(i & TMIO_MASK_IRQ); - sd_ctrl_write32(host, CTL_IRQ_MASK, host->sdcard_irq_mask); + sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, host->sdcard_irq_mask); } void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i) { host->sdcard_irq_mask |= (i & TMIO_MASK_IRQ); - sd_ctrl_write32(host, CTL_IRQ_MASK, host->sdcard_irq_mask); + sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, host->sdcard_irq_mask); } static void tmio_mmc_ack_mmc_irqs(struct tmio_mmc_host *host, u32 i) { - sd_ctrl_write32(host, CTL_STATUS, ~i); + sd_ctrl_write32_as_16_and_16(host, CTL_STATUS, ~i); } static void tmio_mmc_init_sg(struct tmio_mmc_host *host, struct mmc_data *data) @@ -375,7 +375,7 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command tmio_mmc_enable_mmc_irqs(host, irq_mask); /* Fire off the command */ - sd_ctrl_write32(host, CTL_ARG_REG, cmd->arg); + sd_ctrl_write32_as_16_and_16(host, CTL_ARG_REG, cmd->arg); sd_ctrl_write16(host, CTL_SD_CMD, c); return 0; @@ -530,7 +530,7 @@ static void tmio_mmc_data_irq(struct tmio_mmc_host *host) goto out; if (host->chan_tx && (data->flags & MMC_DATA_WRITE) && !host->force_pio) { - u32 status = sd_ctrl_read32(host, CTL_STATUS); + u32 status = sd_ctrl_read16_and_16_as_32(host, CTL_STATUS); bool done = false; /* @@ -585,7 +585,7 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, */ for (i = 3, addr = CTL_RESPONSE ; i >= 0 ; i--, addr += 4) - cmd->resp[i] = sd_ctrl_read32(host, addr); + cmd->resp[i] = sd_ctrl_read16_and_16_as_32(host, addr); if (cmd->flags & MMC_RSP_136) { cmd->resp[0] = (cmd->resp[0] << 8) | (cmd->resp[1] >> 24); @@ -702,14 +702,14 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid) struct tmio_mmc_host *host = devid; unsigned int ireg, status; - status = sd_ctrl_read32(host, CTL_STATUS); + status = sd_ctrl_read16_and_16_as_32(host, CTL_STATUS); ireg = status & TMIO_MASK_IRQ & ~host->sdcard_irq_mask; pr_debug_status(status); pr_debug_status(ireg); /* Clear the status except the interrupt status */ - sd_ctrl_write32(host, CTL_STATUS, TMIO_MASK_IRQ); + sd_ctrl_write32_as_16_and_16(host, CTL_STATUS, TMIO_MASK_IRQ); if (__tmio_mmc_card_detect_irq(host, ireg, status)) return IRQ_HANDLED; @@ -944,7 +944,7 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc) return ret; ret = !((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) || - (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)); + (sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)); return ret; } @@ -964,7 +964,7 @@ static int tmio_mmc_card_busy(struct mmc_host *mmc) { struct tmio_mmc_host *host = mmc_priv(mmc); - return !(sd_ctrl_read32(host, CTL_STATUS2) & TMIO_STATUS2_DAT0); + return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS2) & TMIO_STATUS2_DAT0); } static struct mmc_host_ops tmio_mmc_ops = { @@ -1113,7 +1113,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host, tmio_mmc_clk_stop(_host); tmio_mmc_reset(_host); - _host->sdcard_irq_mask = sd_ctrl_read32(_host, CTL_IRQ_MASK); + _host->sdcard_irq_mask = sd_ctrl_read16_and_16_as_32(_host, CTL_IRQ_MASK); tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL); /* Unmask the IRQs we want to know about */ -- cgit v0.10.2 From 2cafc5cb4fcbe648d0d16ec5039ee292d85d7bfa Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 27 Apr 2016 18:51:24 +0200 Subject: mmc: tmio: use BIT() within defines BIT() makes it easier to match the bits to the datasheet. This is especially important here, since some variants have different names in their datasheets (like with Renesas R-Car). Reviewed-by: Simon Horman Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index e75e5ca..74945c1a 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -49,27 +49,29 @@ #define CTL_RESET_SDIO 0x1e0 /* Definitions for values the CTRL_STATUS register can take. */ -#define TMIO_STAT_CMDRESPEND 0x00000001 -#define TMIO_STAT_DATAEND 0x00000004 -#define TMIO_STAT_CARD_REMOVE 0x00000008 -#define TMIO_STAT_CARD_INSERT 0x00000010 -#define TMIO_STAT_SIGSTATE 0x00000020 -#define TMIO_STAT_WRPROTECT 0x00000080 -#define TMIO_STAT_CARD_REMOVE_A 0x00000100 -#define TMIO_STAT_CARD_INSERT_A 0x00000200 -#define TMIO_STAT_SIGSTATE_A 0x00000400 -#define TMIO_STAT_CMD_IDX_ERR 0x00010000 -#define TMIO_STAT_CRCFAIL 0x00020000 -#define TMIO_STAT_STOPBIT_ERR 0x00040000 -#define TMIO_STAT_DATATIMEOUT 0x00080000 -#define TMIO_STAT_RXOVERFLOW 0x00100000 -#define TMIO_STAT_TXUNDERRUN 0x00200000 -#define TMIO_STAT_CMDTIMEOUT 0x00400000 -#define TMIO_STAT_RXRDY 0x01000000 -#define TMIO_STAT_TXRQ 0x02000000 -#define TMIO_STAT_ILL_FUNC 0x20000000 -#define TMIO_STAT_CMD_BUSY 0x40000000 -#define TMIO_STAT_ILL_ACCESS 0x80000000 +#define TMIO_STAT_CMDRESPEND BIT(0) +#define TMIO_STAT_DATAEND BIT(2) +#define TMIO_STAT_CARD_REMOVE BIT(3) +#define TMIO_STAT_CARD_INSERT BIT(4) +#define TMIO_STAT_SIGSTATE BIT(5) +#define TMIO_STAT_WRPROTECT BIT(7) +#define TMIO_STAT_CARD_REMOVE_A BIT(8) +#define TMIO_STAT_CARD_INSERT_A BIT(9) +#define TMIO_STAT_SIGSTATE_A BIT(10) + +/* These belong technically to CTRL_STATUS2, but the driver merges them */ +#define TMIO_STAT_CMD_IDX_ERR BIT(16) +#define TMIO_STAT_CRCFAIL BIT(17) +#define TMIO_STAT_STOPBIT_ERR BIT(18) +#define TMIO_STAT_DATATIMEOUT BIT(19) +#define TMIO_STAT_RXOVERFLOW BIT(20) +#define TMIO_STAT_TXUNDERRUN BIT(21) +#define TMIO_STAT_CMDTIMEOUT BIT(22) +#define TMIO_STAT_RXRDY BIT(24) +#define TMIO_STAT_TXRQ BIT(25) +#define TMIO_STAT_ILL_FUNC BIT(29) +#define TMIO_STAT_CMD_BUSY BIT(30) +#define TMIO_STAT_ILL_ACCESS BIT(31) #define TMIO_STATUS2_DAT0 BIT(7) -- cgit v0.10.2 From 83e95351d49f60d6cf37706bf94529116d03e648 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 27 Apr 2016 18:51:25 +0200 Subject: mmc: tmio: use CTL_STATUS consistently To prevent confusion, use the virtual u32 CTL_STATUS in card_busy() the same way as in other parts of this driver. Reviewed-by: Simon Horman Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 74945c1a..55f251f 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -67,14 +67,13 @@ #define TMIO_STAT_RXOVERFLOW BIT(20) #define TMIO_STAT_TXUNDERRUN BIT(21) #define TMIO_STAT_CMDTIMEOUT BIT(22) +#define TMIO_STAT_DAT0 BIT(23) /* only known on R-Car so far */ #define TMIO_STAT_RXRDY BIT(24) #define TMIO_STAT_TXRQ BIT(25) #define TMIO_STAT_ILL_FUNC BIT(29) #define TMIO_STAT_CMD_BUSY BIT(30) #define TMIO_STAT_ILL_ACCESS BIT(31) -#define TMIO_STATUS2_DAT0 BIT(7) - #define CLK_CTL_DIV_MASK 0xff #define CLK_CTL_SCLKEN BIT(8) diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 3635940..57d3507 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -964,7 +964,7 @@ static int tmio_mmc_card_busy(struct mmc_host *mmc) { struct tmio_mmc_host *host = mmc_priv(mmc); - return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS2) & TMIO_STATUS2_DAT0); + return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & TMIO_STAT_DAT0); } static struct mmc_host_ops tmio_mmc_ops = { -- cgit v0.10.2 From a21553c9e0c236ae241d9f4333aafae24ae19dfc Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 27 Apr 2016 18:51:26 +0200 Subject: mmc: tmio/sdhi: distinguish between SCLKDIVEN and ILL_FUNC This bit has a different meaning in SDHI and original TMIO. Document that and use the proper naming. Reviewed-by: Simon Horman Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 3bf68b4..f8ea3d1 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -244,7 +244,8 @@ static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host) { int timeout = 1000; - while (--timeout && !(sd_ctrl_read16(host, CTL_STATUS2) & (1 << 13))) + while (--timeout && !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) + & TMIO_STAT_SCLKDIVEN)) udelay(1); if (!timeout) { diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 55f251f..8dd5ea4 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -70,7 +70,8 @@ #define TMIO_STAT_DAT0 BIT(23) /* only known on R-Car so far */ #define TMIO_STAT_RXRDY BIT(24) #define TMIO_STAT_TXRQ BIT(25) -#define TMIO_STAT_ILL_FUNC BIT(29) +#define TMIO_STAT_ILL_FUNC BIT(29) /* only when !TMIO_MMC_HAS_IDLE_WAIT */ +#define TMIO_STAT_SCLKDIVEN BIT(29) /* only when TMIO_MMC_HAS_IDLE_WAIT */ #define TMIO_STAT_CMD_BUSY BIT(30) #define TMIO_STAT_ILL_ACCESS BIT(31) diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 57d3507..95f2299 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -542,7 +542,7 @@ static void tmio_mmc_data_irq(struct tmio_mmc_host *host) * waiting for one more interrupt fixes the problem. */ if (host->pdata->flags & TMIO_MMC_HAS_IDLE_WAIT) { - if (status & TMIO_STAT_ILL_FUNC) + if (status & TMIO_STAT_SCLKDIVEN) done = true; } else { if (!(status & TMIO_STAT_CMD_BUSY)) -- cgit v0.10.2 From 184adf202bca05ca34380cb53b349307aede7ef3 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 27 Apr 2016 18:51:27 +0200 Subject: mmc: tmio: document CTL_STATUS handling Now that reading CTL_STATUS is consistent, we can remove CTL_STATUS2 and document how this is handled internally. Reviewed-by: Simon Horman Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 8dd5ea4..1aac2ad 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -30,8 +30,9 @@ #define CTL_STOP_INTERNAL_ACTION 0x08 #define CTL_XFER_BLK_COUNT 0xa #define CTL_RESPONSE 0x0c +/* driver merges STATUS and following STATUS2 */ #define CTL_STATUS 0x1c -#define CTL_STATUS2 0x1e +/* driver merges IRQ_MASK and following IRQ_MASK2 */ #define CTL_IRQ_MASK 0x20 #define CTL_SD_CARD_CLK_CTL 0x24 #define CTL_SD_XFER_LEN 0x26 -- cgit v0.10.2 From 010629436d83dc6a5c489847b0a1b8d5449a962f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 28 Apr 2016 08:18:11 +0200 Subject: mmc: sh_mobile_sdhi: remove obsolete include file A few SH boards include the file but don't make use of it (no named interrupts). The SDHI code removed support for this feature as well. So, drop the references and ultimately remove the unneeded file. Signed-off-by: Wolfram Sang Acked-by: Rich Felker Acked-by: Yoshinori Sato Signed-off-by: Ulf Hansson diff --git a/arch/sh/boards/board-sh7757lcr.c b/arch/sh/boards/board-sh7757lcr.c index 324599b..0104c81 100644 --- a/arch/sh/boards/board-sh7757lcr.c +++ b/arch/sh/boards/board-sh7757lcr.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index 62c3b81..de8393c 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index a9c0c07..6d61279 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c index 6bd9230..5deb2d8 100644 --- a/arch/sh/boards/mach-kfr2r09/setup.c +++ b/arch/sh/boards/mach-kfr2r09/setup.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index 7a04da3..5de60a7 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index e0e1df1..f1fecd3 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/include/linux/mmc/sh_mobile_sdhi.h b/include/linux/mmc/sh_mobile_sdhi.h deleted file mode 100644 index 95d6f03..0000000 --- a/include/linux/mmc/sh_mobile_sdhi.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef LINUX_MMC_SH_MOBILE_SDHI_H -#define LINUX_MMC_SH_MOBILE_SDHI_H - -#include - -#define SH_MOBILE_SDHI_IRQ_CARD_DETECT "card_detect" -#define SH_MOBILE_SDHI_IRQ_SDCARD "sdcard" -#define SH_MOBILE_SDHI_IRQ_SDIO "sdio" - -#endif /* LINUX_MMC_SH_MOBILE_SDHI_H */ -- cgit v0.10.2 From f0be051e5be1ddad4f4bc53ca3eb438e0ca2895f Mon Sep 17 00:00:00 2001 From: Lars Persson Date: Wed, 27 Apr 2016 17:21:26 +0200 Subject: mmc: dt: usdhi6rol0: add optional pinctrl binding Add a pinctrl binding to specify different pin settings for high speed modes and UHS modes. Signed-off-by: Lars Persson Acked-by: Rob Herring Signed-off-by: Ulf Hansson diff --git a/Documentation/devicetree/bindings/mmc/usdhi6rol0.txt b/Documentation/devicetree/bindings/mmc/usdhi6rol0.txt index 8babdaa..6d1b797 100644 --- a/Documentation/devicetree/bindings/mmc/usdhi6rol0.txt +++ b/Documentation/devicetree/bindings/mmc/usdhi6rol0.txt @@ -12,6 +12,12 @@ Optional properties: - vmmc-supply: a phandle of a regulator, supplying Vcc to the card - vqmmc-supply: a phandle of a regulator, supplying VccQ to the card +- pinctrl-names: Can contain a "default" entry and a "state_uhs" + entry. The state_uhs entry is used together with the default + entry when the board requires distinct settings for UHS speeds. + +- pinctrl-N: One property for each name listed in pinctrl-names, see + ../pinctrl/pinctrl-bindings.txt. Additionally any standard mmc bindings from mmc.txt can be used. -- cgit v0.10.2 From 701dcef72f45edf942cb06284c37b4fdbd4cd77b Mon Sep 17 00:00:00 2001 From: Lars Persson Date: Wed, 27 Apr 2016 17:21:27 +0200 Subject: mmc: usdhi6rol0: do not announce UHS capabilities The driver in its current form does not support UHS at all due to a missing start_signal_voltage_switch callback. Also when this callback is added we should let the device tree control UHS capabilities using the standard mmc bindings. Signed-off-by: Lars Persson Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index 807c06e..e9c8dfa 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -1785,7 +1785,7 @@ static int usdhi6_probe(struct platform_device *pdev) mmc->ops = &usdhi6_ops; mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | - MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 | MMC_CAP_SDIO_IRQ; + MMC_CAP_SDIO_IRQ; /* Set .max_segs to some random number. Feel free to adjust. */ mmc->max_segs = 32; mmc->max_blk_size = 512; -- cgit v0.10.2 From 0cd59df9f028319e193113280d51c9d87b0b36ad Mon Sep 17 00:00:00 2001 From: Lars Persson Date: Wed, 27 Apr 2016 17:21:28 +0200 Subject: mmc: usdhi6rol0: add support for UHS modes Add a start_signal_voltage_switch() operation to support enabling of UHS modes. Signed-off-by: Lars Persson Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index e9c8dfa..743e200 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -1147,12 +1147,22 @@ static void usdhi6_enable_sdio_irq(struct mmc_host *mmc, int enable) } } +static int usdhi6_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) +{ + int ret; + + ret = mmc_regulator_set_vqmmc(mmc, ios); + + return ret; +} + static struct mmc_host_ops usdhi6_ops = { .request = usdhi6_request, .set_ios = usdhi6_set_ios, .get_cd = usdhi6_get_cd, .get_ro = usdhi6_get_ro, .enable_sdio_irq = usdhi6_enable_sdio_irq, + .start_signal_voltage_switch = usdhi6_sig_volt_switch, }; /* State machine handlers */ -- cgit v0.10.2 From 488aab3d0c02b77d8d8f63a6abddb9d8beeea11a Mon Sep 17 00:00:00 2001 From: Lars Persson Date: Wed, 27 Apr 2016 17:21:29 +0200 Subject: mmc: usdhi6rol0: add pinctrl to set pin drive strength Some boards need different pin drive strength for the UHS mode. Add an optional pinctrl setting with two pin states covering UHS speeds and other speeds. Signed-off-by: Lars Persson Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index 743e200..1bd5f1a 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -198,6 +199,11 @@ struct usdhi6_host { struct dma_chan *chan_rx; struct dma_chan *chan_tx; bool dma_active; + + /* Pin control */ + struct pinctrl *pinctrl; + struct pinctrl_state *pins_default; + struct pinctrl_state *pins_uhs; }; /* I/O primitives */ @@ -1147,12 +1153,35 @@ static void usdhi6_enable_sdio_irq(struct mmc_host *mmc, int enable) } } +static int usdhi6_set_pinstates(struct usdhi6_host *host, int voltage) +{ + if (IS_ERR(host->pins_uhs)) + return 0; + + switch (voltage) { + case MMC_SIGNAL_VOLTAGE_180: + case MMC_SIGNAL_VOLTAGE_120: + return pinctrl_select_state(host->pinctrl, + host->pins_uhs); + + default: + return pinctrl_select_state(host->pinctrl, + host->pins_default); + } +} + static int usdhi6_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) { int ret; ret = mmc_regulator_set_vqmmc(mmc, ios); + if (ret < 0) + return ret; + ret = usdhi6_set_pinstates(mmc_priv(mmc), ios->signal_voltage); + if (ret) + dev_warn_once(mmc_dev(mmc), + "Failed to set pinstate err=%d\n", ret); return ret; } @@ -1740,6 +1769,25 @@ static int usdhi6_probe(struct platform_device *pdev) host->wait = USDHI6_WAIT_FOR_REQUEST; host->timeout = msecs_to_jiffies(4000); + host->pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(host->pinctrl)) { + ret = PTR_ERR(host->pinctrl); + goto e_free_mmc; + } + + host->pins_uhs = pinctrl_lookup_state(host->pinctrl, "state_uhs"); + if (!IS_ERR(host->pins_uhs)) { + host->pins_default = pinctrl_lookup_state(host->pinctrl, + PINCTRL_STATE_DEFAULT); + + if (IS_ERR(host->pins_default)) { + dev_err(dev, + "UHS pinctrl requires a default pin state.\n"); + ret = PTR_ERR(host->pins_default); + goto e_free_mmc; + } + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); host->base = devm_ioremap_resource(dev, res); if (IS_ERR(host->base)) { -- cgit v0.10.2 From 4406433dec687c54be48a18a71dd28acb319137e Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 28 Apr 2016 14:59:26 +0200 Subject: mmc: sdhci-of-at91: add presets setup The controller claims to support SDR104. In fact, it only supports a degraded SDR104 since the maximum frequency of the SD clock is 120 MHz instead of 208 MHz. The sdhci core is unaware of it and will compute a wrong clock divider. We can deal with this specific case by using presets. Signed-off-by: Ludovic Desroches Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index c1923c0..25f779e 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,8 @@ #define SDMMC_CACR_CAPWREN BIT(0) #define SDMMC_CACR_KEY (0x46 << 8) +#define SDHCI_AT91_PRESET_COMMON_CONF 0x400 /* drv type B, programmable clock mode */ + struct sdhci_at91_priv { struct clk *hclock; struct clk *gck; @@ -163,6 +166,7 @@ static int sdhci_at91_probe(struct platform_device *pdev) unsigned int clk_base, clk_mul; unsigned int gck_rate, real_gck_rate; int ret; + unsigned int preset_div; match = of_match_device(sdhci_at91_dt_match, &pdev->dev); if (!match) @@ -230,6 +234,28 @@ static int sdhci_at91_probe(struct platform_device *pdev) clk_mul, real_gck_rate); } + /* + * We have to set preset values because it depends on the clk_mul + * value. Moreover, SDR104 is supported in a degraded mode since the + * maximum sd clock value is 120 MHz instead of 208 MHz. For that + * reason, we need to use presets to support SDR104. + */ + preset_div = DIV_ROUND_UP(real_gck_rate, 24000000) - 1; + writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div, + host->ioaddr + SDHCI_PRESET_FOR_SDR12); + preset_div = DIV_ROUND_UP(real_gck_rate, 50000000) - 1; + writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div, + host->ioaddr + SDHCI_PRESET_FOR_SDR25); + preset_div = DIV_ROUND_UP(real_gck_rate, 100000000) - 1; + writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div, + host->ioaddr + SDHCI_PRESET_FOR_SDR50); + preset_div = DIV_ROUND_UP(real_gck_rate, 120000000) - 1; + writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div, + host->ioaddr + SDHCI_PRESET_FOR_SDR104); + preset_div = DIV_ROUND_UP(real_gck_rate, 50000000) - 1; + writew(SDHCI_AT91_PRESET_COMMON_CONF | preset_div, + host->ioaddr + SDHCI_PRESET_FOR_DDR50); + clk_prepare_enable(priv->mainck); clk_prepare_enable(priv->gck); -- cgit v0.10.2 From 81eef6ca92014845d40e3f1310e42b7010303acc Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 29 Apr 2016 16:06:18 +0300 Subject: mmc: omap_hsmmc: Use dma_request_chan() for requesting DMA channel With the new dma_request_chan() the client driver does not need to look for the DMA resource and it does not need to pass filter_fn anymore. By switching to the new API the driver can now support deferred probing against DMA. Signed-off-by: Peter Ujfalusi Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 3563321..24ebc9a 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -1993,8 +1992,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev) struct resource *res; int ret, irq; const struct of_device_id *match; - dma_cap_mask_t mask; - unsigned tx_req, rx_req; const struct omap_mmc_of_data *data; void __iomem *base; @@ -2124,44 +2121,17 @@ static int omap_hsmmc_probe(struct platform_device *pdev) omap_hsmmc_conf_bus_power(host); - if (!pdev->dev.of_node) { - res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); - if (!res) { - dev_err(mmc_dev(host->mmc), "cannot get DMA TX channel\n"); - ret = -ENXIO; - goto err_irq; - } - tx_req = res->start; - - res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); - if (!res) { - dev_err(mmc_dev(host->mmc), "cannot get DMA RX channel\n"); - ret = -ENXIO; - goto err_irq; - } - rx_req = res->start; - } - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - host->rx_chan = - dma_request_slave_channel_compat(mask, omap_dma_filter_fn, - &rx_req, &pdev->dev, "rx"); - - if (!host->rx_chan) { - dev_err(mmc_dev(host->mmc), "unable to obtain RX DMA engine channel\n"); - ret = -ENXIO; + host->rx_chan = dma_request_chan(&pdev->dev, "rx"); + if (IS_ERR(host->rx_chan)) { + dev_err(mmc_dev(host->mmc), "RX DMA channel request failed\n"); + ret = PTR_ERR(host->rx_chan); goto err_irq; } - host->tx_chan = - dma_request_slave_channel_compat(mask, omap_dma_filter_fn, - &tx_req, &pdev->dev, "tx"); - - if (!host->tx_chan) { - dev_err(mmc_dev(host->mmc), "unable to obtain TX DMA engine channel\n"); - ret = -ENXIO; + host->tx_chan = dma_request_chan(&pdev->dev, "tx"); + if (IS_ERR(host->tx_chan)) { + dev_err(mmc_dev(host->mmc), "TX DMA channel request failed\n"); + ret = PTR_ERR(host->tx_chan); goto err_irq; } @@ -2219,9 +2189,9 @@ err_slot_name: mmc_remove_host(mmc); err_irq: device_init_wakeup(&pdev->dev, false); - if (host->tx_chan) + if (!IS_ERR_OR_NULL(host->tx_chan)) dma_release_channel(host->tx_chan); - if (host->rx_chan) + if (!IS_ERR_OR_NULL(host->rx_chan)) dma_release_channel(host->rx_chan); pm_runtime_dont_use_autosuspend(host->dev); pm_runtime_put_sync(host->dev); -- cgit v0.10.2 From 3072ba8cd95bd0e7fbe9a3a1c9b61fb190257855 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 2 May 2016 22:25:39 +0200 Subject: mmc: sh_mobile_sdhi: make clk_update function more compact Save a few lines, the codebase is large enough. Signed-off-by: Wolfram Sang Tested-by: Geert Uytterhoeven Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index f8ea3d1..6857e4b 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -165,12 +165,9 @@ static unsigned int sh_mobile_sdhi_clk_update(struct tmio_mmc_host *host, unsigned int new_clock) { struct sh_mobile_sdhi *priv = host_to_priv(host); - unsigned int freq, best_freq, diff_min, diff; + unsigned int freq, diff, best_freq = 0, diff_min = ~0; int i; - diff_min = ~0; - best_freq = 0; - /* * We want the bus clock to be as close as possible to, but no * greater than, new_clock. As we can divide by 1 << i for -- cgit v0.10.2 From 3d376fb2ea907f0c1bbccf87125456439feb4ed4 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 2 May 2016 22:25:40 +0200 Subject: mmc: tmio/sdhi: introduce flag for RCar 2+ specific features RCar Gen2 and later implementations of TMIO/SDHI have their own set of features and additions. FAST_CLK_CHG is just one of them and I see a few others being added soon. Some may work on older chipsets but this needs to be tested case by case. Instead of adding a bunch of flags for each feature, add a global RCar2+ one for now. We can still break out features if the need arises. Signed-off-by: Wolfram Sang Tested-by: Geert Uytterhoeven Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 6857e4b..19e4c29 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -62,7 +62,7 @@ static const struct sh_mobile_sdhi_of_data of_rcar_gen1_compatible = { static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = { .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | - TMIO_MMC_CLK_ACTUAL | TMIO_MMC_FAST_CLK_CHG, + TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES, .dma_rx_offset = 0x2000, @@ -70,7 +70,7 @@ static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = { static const struct sh_mobile_sdhi_of_data of_rcar_gen3_compatible = { .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | - TMIO_MMC_CLK_ACTUAL | TMIO_MMC_FAST_CLK_CHG, + TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2, .capabilities = MMC_CAP_SD_HIGHSPEED, .bus_shift = 2, }; diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 95f2299..f44e2ab 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -157,7 +157,7 @@ static void tmio_mmc_clk_start(struct tmio_mmc_host *host) { sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN | sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); - msleep(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG ? 1 : 10); + msleep(host->pdata->flags & TMIO_MMC_MIN_RCAR2 ? 1 : 10); if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG) { sd_ctrl_write16(host, CTL_CLK_AND_WAIT_CTL, 0x0100); @@ -174,7 +174,7 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host) sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); - msleep(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG ? 5 : 10); + msleep(host->pdata->flags & TMIO_MMC_MIN_RCAR2 ? 5 : 10); } static void tmio_mmc_set_clock(struct tmio_mmc_host *host, @@ -205,7 +205,7 @@ static void tmio_mmc_set_clock(struct tmio_mmc_host *host, sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN & sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL)); sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, clk & CLK_CTL_DIV_MASK); - if (!(host->pdata->flags & TMIO_MMC_FAST_CLK_CHG)) + if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) msleep(10); tmio_mmc_clk_start(host); diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h index 05d58ee..7a26286 100644 --- a/include/linux/mfd/tmio.h +++ b/include/linux/mfd/tmio.h @@ -66,8 +66,8 @@ */ #define TMIO_MMC_SDIO_IRQ (1 << 2) -/* Some controllers don't need to wait 10ms for clock changes */ -#define TMIO_MMC_FAST_CLK_CHG (1 << 3) +/* Some features are only available or tested on RCar Gen2 or later */ +#define TMIO_MMC_MIN_RCAR2 (1 << 3) /* * Some controllers require waiting for the SD bus to become -- cgit v0.10.2 From 8fc009986471729533fb1246c7ea9395635dac26 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 2 May 2016 22:25:41 +0200 Subject: mmc: sh_mobile_sdhi: only change the clock on RCar Gen2+ We had a regression on r8a7740 where the SDHI clock was a generic peripheral clock, so changing its rate was not desired. This should be fixed in the clock driver. However, it also shows that the new clock calculation should only be used on tested systems. Add a check for that. Signed-off-by: Wolfram Sang Tested-by: Geert Uytterhoeven Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 19e4c29..ac9ba36 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -168,6 +168,10 @@ static unsigned int sh_mobile_sdhi_clk_update(struct tmio_mmc_host *host, unsigned int freq, diff, best_freq = 0, diff_min = ~0; int i; + /* tested only on RCar Gen2+ currently; may work for others */ + if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) + return clk_get_rate(priv->clk); + /* * We want the bus clock to be as close as possible to, but no * greater than, new_clock. As we can divide by 1 << i for -- cgit v0.10.2 From f3f44d512cafef7e3d2cb140f642786dd6ec8818 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 2 May 2016 22:25:42 +0200 Subject: mmc: sh_mobile_sdhi: check return value when changing clk And return the old clock rate if something went wrong. Signed-off-by: Wolfram Sang Tested-by: Geert Uytterhoeven Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index ac9ba36..5309c73b 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -166,7 +166,7 @@ static unsigned int sh_mobile_sdhi_clk_update(struct tmio_mmc_host *host, { struct sh_mobile_sdhi *priv = host_to_priv(host); unsigned int freq, diff, best_freq = 0, diff_min = ~0; - int i; + int i, ret; /* tested only on RCar Gen2+ currently; may work for others */ if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2)) @@ -195,9 +195,9 @@ static unsigned int sh_mobile_sdhi_clk_update(struct tmio_mmc_host *host, } } - clk_set_rate(priv->clk, best_freq); + ret = clk_set_rate(priv->clk, best_freq); - return best_freq; + return ret == 0 ? best_freq : clk_get_rate(priv->clk); } static void sh_mobile_sdhi_clk_disable(struct tmio_mmc_host *host) -- cgit v0.10.2 From 437db4c6e79881d33aca521987188c728df350a8 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 4 May 2016 10:38:21 +0300 Subject: mmc: mmc: Attempt to flush cache before reset CMD0 or hardware reset may invalidate the cache, so it needs to be flushed before reset. In the case of recovery, we can't expect flushing the cache to work always, but have a go and ignore errors. Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 28b477d..f99c47e 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1958,6 +1958,12 @@ static int mmc_reset(struct mmc_host *host) { struct mmc_card *card = host->card; + /* + * In the case of recovery, we can't expect flushing the cache to work + * always, but we have a go and ignore errors. + */ + mmc_flush_cache(host->card); + if ((host->caps & MMC_CAP_HW_RESET) && host->ops->hw_reset && mmc_can_reset(card)) { /* If the card accept RST_n signal, send it. */ -- cgit v0.10.2 From d15b08fb2246fa28b4cf01337951026177641af4 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 4 May 2016 11:23:08 +0300 Subject: mmc: omap: Use dma_request_chan() for requesting DMA channel With the new dma_request_chan() the client driver does not need to look for the DMA resource and it does not need to pass filter_fn anymore. By switching to the new API the driver can now support deferred probing against DMA. Signed-off-by: Peter Ujfalusi CC: Ulf Hansson CC: Jarkko Nikula Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index b9958a1..f23d65e 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -1321,8 +1320,6 @@ static int mmc_omap_probe(struct platform_device *pdev) struct omap_mmc_platform_data *pdata = pdev->dev.platform_data; struct mmc_omap_host *host = NULL; struct resource *res; - dma_cap_mask_t mask; - unsigned sig = 0; int i, ret = 0; int irq; @@ -1382,29 +1379,34 @@ static int mmc_omap_probe(struct platform_device *pdev) goto err_free_iclk; } - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - host->dma_tx_burst = -1; host->dma_rx_burst = -1; - res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); - if (res) - sig = res->start; - host->dma_tx = dma_request_slave_channel_compat(mask, - omap_dma_filter_fn, &sig, &pdev->dev, "tx"); - if (!host->dma_tx) - dev_warn(host->dev, "unable to obtain TX DMA engine channel %u\n", - sig); - - res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx"); - if (res) - sig = res->start; - host->dma_rx = dma_request_slave_channel_compat(mask, - omap_dma_filter_fn, &sig, &pdev->dev, "rx"); - if (!host->dma_rx) - dev_warn(host->dev, "unable to obtain RX DMA engine channel %u\n", - sig); + host->dma_tx = dma_request_chan(&pdev->dev, "tx"); + if (IS_ERR(host->dma_tx)) { + ret = PTR_ERR(host->dma_tx); + if (ret == -EPROBE_DEFER) { + clk_put(host->fclk); + goto err_free_iclk; + } + + host->dma_tx = NULL; + dev_warn(host->dev, "TX DMA channel request failed\n"); + } + + host->dma_rx = dma_request_chan(&pdev->dev, "rx"); + if (IS_ERR(host->dma_rx)) { + ret = PTR_ERR(host->dma_rx); + if (ret == -EPROBE_DEFER) { + if (host->dma_tx) + dma_release_channel(host->dma_tx); + clk_put(host->fclk); + goto err_free_iclk; + } + + host->dma_rx = NULL; + dev_warn(host->dev, "RX DMA channel request failed\n"); + } ret = request_irq(host->irq, mmc_omap_irq, 0, DRIVER_NAME, host); if (ret) -- cgit v0.10.2 From 802ac39a55664b15dd162e3444d5be34045abeeb Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 4 May 2016 09:43:24 +0800 Subject: mmc: sdhci-of-arasan: fix set_clock when a phy is supported commit 61b914eb81f8 ("mmc: sdhci-of-arasan: add phy support for sdhci-of-arasan") introduce phy support for arasan. According to the vendor's databook, we should make sure the phy is in poweroff status before we configure the clk stuff. Otherwise it may cause some IO sample timing issues from the test. And we don't need this extra operation while running in low performance mode since phy doesn't trigger sampling block. Signed-off-by: Shawn Lin Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 2e482b1..b6f4c1d 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -55,8 +55,32 @@ static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host) return freq; } +static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host); + bool ctrl_phy = false; + + if (clock > MMC_HIGH_52_MAX_DTR && (!IS_ERR(sdhci_arasan->phy))) + ctrl_phy = true; + + if (ctrl_phy) { + spin_unlock_irq(&host->lock); + phy_power_off(sdhci_arasan->phy); + spin_lock_irq(&host->lock); + } + + sdhci_set_clock(host, clock); + + if (ctrl_phy) { + spin_unlock_irq(&host->lock); + phy_power_on(sdhci_arasan->phy); + spin_lock_irq(&host->lock); + } +} + static struct sdhci_ops sdhci_arasan_ops = { - .set_clock = sdhci_set_clock, + .set_clock = sdhci_arasan_set_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_timeout_clock = sdhci_arasan_get_timeout_clock, .set_bus_width = sdhci_set_bus_width, -- cgit v0.10.2 From e51534c806609c806d81bfb034f02737461f855c Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Thu, 21 Apr 2016 00:51:30 +0800 Subject: mmc: core: fix using wrong io voltage if mmc_select_hs200 fails Currently MMC core will keep going if HS200/HS timing switch failed with -EBADMSG error by the assumption that the old timing is still valid. However, for mmc_select_hs200 case, the signal voltage may have already been switched. If the timing switch failed, we should fall back to the old voltage in case the card is continue run with legacy timing. If fall back signal voltage failed, we explicitly report an EIO error to force retry during the next power cycle. Signed-off-by: Dong Aisheng Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index f99c47e..e0c9a55 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1244,10 +1244,11 @@ static int mmc_select_hs200(struct mmc_card *card) { struct mmc_host *host = card->host; bool send_status = true; - unsigned int old_timing; + unsigned int old_timing, old_signal_voltage; int err = -EINVAL; u8 val; + old_signal_voltage = host->ios.signal_voltage; if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V) err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120); @@ -1256,7 +1257,7 @@ static int mmc_select_hs200(struct mmc_card *card) /* If fails try again during next card power cycle */ if (err) - goto err; + return err; mmc_select_driver_type(card); @@ -1290,9 +1291,14 @@ static int mmc_select_hs200(struct mmc_card *card) } } err: - if (err) + if (err) { + /* fall back to the old signal voltage, if fails report error */ + if (__mmc_set_signal_voltage(host, old_signal_voltage)) + err = -EIO; + pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host), __func__, err); + } return err; } -- cgit v0.10.2 From 0400ed0a083a6567d45df96fb813f4702ece7d1b Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Thu, 21 Apr 2016 00:51:31 +0800 Subject: mmc: core: remove the invalid message in mmc_select_timing mmc_select_hs200() and mmc_select_hs() will keep the timing as before if switch fails. So it's meaningless to print the failed switched mode outside based on the current host timing. Furthermore, the original print is wrong, it should be: pr_warn("%s: switch to %s failed\n", mmc_hostname(card->host), mmc_card_hs(card) ? "high-speed" : (mmc_card_hs200(card) ? "hs200" : "")); Since we already have error message in mmc_select_hs200(), simply remove it outside. Signed-off-by: Dong Aisheng Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index e0c9a55..35873d4 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1320,21 +1320,13 @@ static int mmc_select_timing(struct mmc_card *card) if (err && err != -EBADMSG) return err; - if (err) { - pr_warn("%s: switch to %s failed\n", - mmc_card_hs(card) ? "high-speed" : - (mmc_card_hs200(card) ? "hs200" : ""), - mmc_hostname(card->host)); - err = 0; - } - bus_speed: /* * Set the bus speed to the selected bus timing. * If timing is not selected, backward compatible is the default. */ mmc_set_bus_speed(card); - return err; + return 0; } /* -- cgit v0.10.2 From ded97e0b165076556714d4a5708c87f5bcf03783 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Sat, 16 Apr 2016 01:29:25 +0800 Subject: mmc: sdhci: removed unneeded function wrappers After commit d6463f170cf0 ("mmc: sdhci: Remove redundant runtime PM calls"), some of original sdhci_do_xx() function wrappers becomes meaningless, so remove them. Signed-off-by: Dong Aisheng Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 94cffa7..e010ea4 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -48,7 +48,7 @@ static void sdhci_finish_data(struct sdhci_host *); static void sdhci_finish_command(struct sdhci_host *); static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); -static int sdhci_do_get_cd(struct sdhci_host *host); +static int sdhci_get_cd(struct mmc_host *mmc); static void sdhci_dumpregs(struct sdhci_host *host) { @@ -193,7 +193,7 @@ EXPORT_SYMBOL_GPL(sdhci_reset); static void sdhci_do_reset(struct sdhci_host *host, u8 mask) { if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) { - if (!sdhci_do_get_cd(host)) + if (!sdhci_get_cd(host->mmc)) return; } @@ -1450,11 +1450,11 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing) } EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling); -static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) +static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { + struct sdhci_host *host = mmc_priv(mmc); unsigned long flags; u8 ctrl; - struct mmc_host *mmc = host->mmc; spin_lock_irqsave(&host->lock, flags); @@ -1608,16 +1608,10 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) spin_unlock_irqrestore(&host->lock, flags); } -static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +static int sdhci_get_cd(struct mmc_host *mmc) { struct sdhci_host *host = mmc_priv(mmc); - - sdhci_do_set_ios(host, ios); -} - -static int sdhci_do_get_cd(struct sdhci_host *host) -{ - int gpio_cd = mmc_gpio_get_cd(host->mmc); + int gpio_cd = mmc_gpio_get_cd(mmc); if (host->flags & SDHCI_DEVICE_DEAD) return 0; @@ -1641,13 +1635,6 @@ static int sdhci_do_get_cd(struct sdhci_host *host) return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT); } -static int sdhci_get_cd(struct mmc_host *mmc) -{ - struct sdhci_host *host = mmc_priv(mmc); - - return sdhci_do_get_cd(host); -} - static int sdhci_check_ro(struct sdhci_host *host) { unsigned long flags; @@ -1672,8 +1659,9 @@ static int sdhci_check_ro(struct sdhci_host *host) #define SAMPLE_COUNT 5 -static int sdhci_do_get_ro(struct sdhci_host *host) +static int sdhci_get_ro(struct mmc_host *mmc) { + struct sdhci_host *host = mmc_priv(mmc); int i, ro_count; if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT)) @@ -1698,13 +1686,6 @@ static void sdhci_hw_reset(struct mmc_host *mmc) host->ops->hw_reset(host); } -static int sdhci_get_ro(struct mmc_host *mmc) -{ - struct sdhci_host *host = mmc_priv(mmc); - - return sdhci_do_get_ro(host); -} - static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable) { if (!(host->flags & SDHCI_DEVICE_DEAD)) { @@ -1734,10 +1715,10 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) spin_unlock_irqrestore(&host->lock, flags); } -static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, - struct mmc_ios *ios) +static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, + struct mmc_ios *ios) { - struct mmc_host *mmc = host->mmc; + struct sdhci_host *host = mmc_priv(mmc); u16 ctrl; int ret; @@ -1825,17 +1806,6 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, } } -static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, - struct mmc_ios *ios) -{ - struct sdhci_host *host = mmc_priv(mmc); - - if (host->version < SDHCI_SPEC_300) - return 0; - - return sdhci_do_start_signal_voltage_switch(host, ios); -} - static int sdhci_card_busy(struct mmc_host *mmc) { struct sdhci_host *host = mmc_priv(mmc); @@ -2126,7 +2096,7 @@ static void sdhci_card_event(struct mmc_host *mmc) if (host->ops->card_event) host->ops->card_event(host); - present = sdhci_do_get_cd(host); + present = sdhci_get_cd(host->mmc); spin_lock_irqsave(&host->lock, flags); @@ -2697,7 +2667,7 @@ int sdhci_resume_host(struct sdhci_host *host) sdhci_init(host, 0); host->pwr = 0; host->clock = 0; - sdhci_do_set_ios(host, &host->mmc->ios); + sdhci_set_ios(host->mmc, &host->mmc->ios); } else { sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER)); mmiowb(); @@ -2759,8 +2729,8 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) /* Force clock and power re-program */ host->pwr = 0; host->clock = 0; - sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios); - sdhci_do_set_ios(host, &host->mmc->ios); + sdhci_start_signal_voltage_switch(host->mmc, &host->mmc->ios); + sdhci_set_ios(host->mmc, &host->mmc->ios); if ((host_flags & SDHCI_PV_ENABLED) && !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) { -- cgit v0.10.2 From cc4d04be94e34fc6d53307b534f830c6854c8721 Mon Sep 17 00:00:00 2001 From: Ken Sumrall Date: Tue, 10 May 2016 14:53:13 +0530 Subject: mmc: block: improve logging of handling emmc timeouts Add some logging to make it clear just how the emmc timeout was handled. Signed-off-by: Ken Sumrall [AmitP: cherry-picked this Android patch from aosp common kernel android-4.4] Signed-off-by: Amit Pundir Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 9ce6792..5f2a3d69 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -948,16 +948,22 @@ static int mmc_blk_cmd_error(struct request *req, const char *name, int error, req->rq_disk->disk_name, "timed out", name, status); /* If the status cmd initially failed, retry the r/w cmd */ - if (!status_valid) + if (!status_valid) { + pr_err("%s: status not valid, retrying timeout\n", + req->rq_disk->disk_name); return ERR_RETRY; + } /* * If it was a r/w cmd crc error, or illegal command * (eg, issued in wrong state) then retry - we should * have corrected the state problem above. */ - if (status & (R1_COM_CRC_ERROR | R1_ILLEGAL_COMMAND)) + if (status & (R1_COM_CRC_ERROR | R1_ILLEGAL_COMMAND)) { + pr_err("%s: command error, retrying timeout\n", + req->rq_disk->disk_name); return ERR_RETRY; + } /* Otherwise abort the command */ return ERR_ABORT; -- cgit v0.10.2 From 560e647515ca90f4277fb8d8f94d370dae0709b5 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 9 May 2016 10:26:58 +0200 Subject: MAINTAINERS: update entry for TMIO MMC driver I have some more additions planned for this driver, so I'd like to get notified of other changes and coordinate them. Drop Ian as maintainer because he hasn't been involved in development for a while. Thanks for all the initial work, of course! Also, reflect the recent changes to the include file layout. Signed-off-by: Wolfram Sang Cc: Ian Molton Acked-by: Simon Horman Signed-off-by: Ulf Hansson diff --git a/MAINTAINERS b/MAINTAINERS index 42e65d1..d22540c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11245,14 +11245,13 @@ S: Maintained F: drivers/media/i2c/tc358743* F: include/media/i2c/tc358743.h -TMIO MMC DRIVER -M: Ian Molton +TMIO/SDHI MMC DRIVER +M: Wolfram Sang L: linux-mmc@vger.kernel.org -S: Maintained +S: Supported F: drivers/mmc/host/tmio_mmc* F: drivers/mmc/host/sh_mobile_sdhi.c -F: include/linux/mmc/tmio.h -F: include/linux/mmc/sh_mobile_sdhi.h +F: include/linux/mfd/tmio.h TMP401 HARDWARE MONITOR DRIVER M: Guenter Roeck -- cgit v0.10.2 From 5b5fe95a6977b9cdd30749cb1576df2329d70da9 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Tue, 10 May 2016 09:14:24 +0900 Subject: mmc: sdhci-st: correct name of sd-uhs-sdr50 property Correct what appears to be a typo in the name of the sd-uhs-sdr50. Also fix mixed tab/space indentation. Signed-off-by: Simon Horman Signed-off-by: Ulf Hansson diff --git a/Documentation/devicetree/bindings/mmc/sdhci-st.txt b/Documentation/devicetree/bindings/mmc/sdhci-st.txt index 18d950d..88faa91 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-st.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-st.txt @@ -38,7 +38,7 @@ Optional properties: - bus-width: Number of data lines. See: Documentation/devicetree/bindings/mmc/mmc.txt. -- max-frequency: Can be 200MHz, 100Mz or 50MHz (default) and used for +- max-frequency: Can be 200MHz, 100Mz or 50MHz (default) and used for configuring the CCONFIG3 in the mmcss. See: Documentation/devicetree/bindings/mmc/mmc.txt. @@ -48,7 +48,7 @@ Optional properties: - vqmmc-supply: Phandle to the regulator dt node, mentioned as the vcc/vdd supply in eMMC/SD specs. -- sd-uhs--sdr50: To enable the SDR50 in the mmcss. +- sd-uhs-sdr50: To enable the SDR50 in the mmcss. See: Documentation/devicetree/bindings/mmc/mmc.txt. - sd-uhs-sdr104: To enable the SDR104 in the mmcss. -- cgit v0.10.2 From 88ea46bcbfd677b779897bbada32ec0709a6c92f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 9 May 2016 09:59:59 +0200 Subject: mmc: sdio: fall back to SDIO 1.0 for broken 1.1 cards I have two SDIO WLAN cards which specify being SDIO Rev. 1.1 cards but their FUNCE tuple reports the smaller size of a Rev 1.0 card. So, enforce 1.0 on these cards to avoid reading the not present registers. They are not really used anyhow. My cards initialize properly after this patch. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c index 6f6fc52..dcb3dee 100644 --- a/drivers/mmc/core/sdio_cis.c +++ b/drivers/mmc/core/sdio_cis.c @@ -177,8 +177,13 @@ static int cistpl_funce_func(struct mmc_card *card, struct sdio_func *func, vsn = func->card->cccr.sdio_vsn; min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42; - if (size < min_size) + if (size == 28 && vsn == SDIO_SDIO_REV_1_10) { + pr_warn("%s: card has broken SDIO 1.1 CIS, forcing SDIO 1.0\n", + mmc_hostname(card->host)); + vsn = SDIO_SDIO_REV_1_00; + } else if (size < min_size) { return -EINVAL; + } /* TPLFE_MAX_BLK_SIZE */ func->max_blksize = buf[12] | (buf[13] << 8); -- cgit v0.10.2 From 685d29ef1783af0049c4aeeec43722e410d5845d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 9 May 2016 17:01:07 +0200 Subject: mmc: sh_mobile_sdhi: enable SDIO IRQs for RCar Gen3 Tested on a Salvator-X board with a Spectec SDW-823 WLAN card. Signed-off-by: Wolfram Sang Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index 5309c73b..f750f94 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -71,7 +71,7 @@ static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = { static const struct sh_mobile_sdhi_of_data of_rcar_gen3_compatible = { .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2, - .capabilities = MMC_CAP_SD_HIGHSPEED, + .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, .bus_shift = 2, }; -- cgit v0.10.2 From 1c447116d017a98c90f8f71c8c5a611e0aa42178 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 5 May 2016 08:12:28 +0300 Subject: mmc: mmc: Fix partition switch timeout for some eMMCs Some eMMCs set the partition switch timeout too low. Now typically eMMCs are considered a critical component (e.g. because they store the root file system) and consequently are expected to be reliable. Thus we can neglect the use case where eMMCs can't switch reliably and we might want a lower timeout to facilitate speedy recovery. Although we could employ a quirk for the cards that are affected (if we could identify them all), as described above, there is little benefit to having a low timeout, so instead simply set a minimum timeout. The minimum is set to 300ms somewhat arbitrarily - the examples that have been seen had a timeout of 10ms but were sometimes taking 60-70ms. Cc: stable@vger.kernel.org Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 35873d4..b81b08f 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -333,6 +333,9 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd) } } +/* Minimum partition switch timeout in milliseconds */ +#define MMC_MIN_PART_SWITCH_TIME 300 + /* * Decode extended CSD. */ @@ -397,6 +400,10 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) /* EXT_CSD value is in units of 10ms, but we store in ms */ card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME]; + /* Some eMMC set the value too low so set a minimum */ + if (card->ext_csd.part_time && + card->ext_csd.part_time < MMC_MIN_PART_SWITCH_TIME) + card->ext_csd.part_time = MMC_MIN_PART_SWITCH_TIME; /* Sleep / awake timeout in 100ns units */ if (sa_shift > 0 && sa_shift <= 0x17) -- cgit v0.10.2