diff options
Diffstat (limited to 'drivers/mmc/host')
83 files changed, 2321 insertions, 1115 deletions
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 264e11fa58ea..7232de1c0688 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -250,6 +250,20 @@ config MMC_SDHCI_OF_DWCMSHC If you have a controller with this interface, say Y or M here. If unsure, say N. +config MMC_SDHCI_OF_K1 + tristate "SDHCI OF support for the SpacemiT K1 SoC" + depends on ARCH_SPACEMIT || COMPILE_TEST + depends on MMC_SDHCI_PLTFM + depends on OF + depends on COMMON_CLK + help + This selects the Secure Digital Host Controller Interface (SDHCI) + found in the SpacemiT K1 SoC. + + If you have a controller with this interface, say Y or M here. + + If unsure, say N. + config MMC_SDHCI_OF_SPARX5 tristate "SDHCI OF support for the MCHP Sparx5 SoC" depends on MMC_SDHCI_PLTFM @@ -1097,6 +1111,19 @@ config MMC_OWL This selects support for the SD/MMC Host Controller on Actions Semi Owl SoCs. +config MMC_LOONGSON2 + tristate "Loongson-2K SD/SDIO/eMMC Host Interface support" + depends on LOONGARCH || COMPILE_TEST + depends on HAS_DMA + help + This selects support for the SD/SDIO/eMMC Host Controller on + Loongson-2K series CPUs. + + To compile this driver as a module, choose M here: the + module will be called mmc_loongson2. + + If unsure, say N. + config MMC_SDHCI_EXTERNAL_DMA bool diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 5147467ec825..5057fea8afb6 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_MMC_USDHI6ROL0) += usdhi6rol0.o obj-$(CONFIG_MMC_TOSHIBA_PCI) += toshsd.o obj-$(CONFIG_MMC_BCM2835) += bcm2835.o obj-$(CONFIG_MMC_OWL) += owl-mmc.o +obj-$(CONFIG_MMC_LOONGSON2) += loongson2-mmc.o obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o @@ -88,6 +89,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_AT91) += sdhci-of-at91.o obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o obj-$(CONFIG_MMC_SDHCI_OF_DWCMSHC) += sdhci-of-dwcmshc.o +obj-$(CONFIG_MMC_SDHCI_OF_K1) += sdhci-of-k1.o obj-$(CONFIG_MMC_SDHCI_OF_SPARX5) += sdhci-of-sparx5.o obj-$(CONFIG_MMC_SDHCI_OF_MA35D1) += sdhci-of-ma35d1.o obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o diff --git a/drivers/mmc/host/alcor.c b/drivers/mmc/host/alcor.c index b6b6dd677ae5..288c3a91a0af 100644 --- a/drivers/mmc/host/alcor.c +++ b/drivers/mmc/host/alcor.c @@ -20,6 +20,7 @@ #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/platform_device.h> +#include <linux/string_choices.h> #include <linux/mmc/host.h> #include <linux/mmc/mmc.h> @@ -208,7 +209,7 @@ static void alcor_trf_block_pio(struct alcor_sdmmc_host *host, bool read) len = min(host->sg_miter.length, blksize); dev_dbg(host->dev, "PIO, %s block size: 0x%zx\n", - read ? "read" : "write", blksize); + str_read_write(read), blksize); host->sg_miter.consumed = len; host->blocks--; @@ -1083,7 +1084,7 @@ static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev) struct alcor_sdmmc_host *host; int ret; - mmc = mmc_alloc_host(sizeof(*host), &pdev->dev); + mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(*host)); if (!mmc) { dev_err(&pdev->dev, "Can't allocate MMC\n"); return -ENOMEM; @@ -1101,11 +1102,9 @@ static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(&pdev->dev, priv->irq, alcor_irq, alcor_irq_thread, IRQF_SHARED, DRV_NAME_ALCOR_PCI_SDMMC, host); - - if (ret) { - dev_err(&pdev->dev, "Failed to get irq for data line\n"); - goto free_host; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to get irq for data line\n"); mutex_init(&host->cmd_mutex); INIT_DELAYED_WORK(&host->timeout_work, alcor_timeout_timer); @@ -1114,15 +1113,8 @@ static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev) alcor_hw_init(host); dev_set_drvdata(&pdev->dev, host); - ret = mmc_add_host(mmc); - if (ret) - goto free_host; - return 0; - -free_host: - mmc_free_host(mmc); - return ret; + return mmc_add_host(mmc); } static void alcor_pci_sdmmc_drv_remove(struct platform_device *pdev) @@ -1135,7 +1127,6 @@ static void alcor_pci_sdmmc_drv_remove(struct platform_device *pdev) alcor_hw_uninit(host); mmc_remove_host(mmc); - mmc_free_host(mmc); } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 14e981b834b6..777342fb7657 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -38,6 +38,7 @@ #include <asm/cacheflush.h> #include <asm/io.h> #include <linux/unaligned.h> +#include <linux/string_choices.h> #define ATMCI_MAX_NR_SLOTS 2 @@ -541,7 +542,6 @@ static int atmci_regs_show(struct seq_file *s, void *v) memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE); spin_unlock_bh(&host->lock); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); seq_printf(s, "MR:\t0x%08x%s%s ", @@ -714,7 +714,7 @@ static inline unsigned int atmci_convert_chksize(struct atmel_mci *host, static void atmci_timeout_timer(struct timer_list *t) { - struct atmel_mci *host = from_timer(host, t, timer); + struct atmel_mci *host = timer_container_of(host, t, timer); struct device *dev = host->dev; dev_dbg(dev, "software timeout\n"); @@ -1652,7 +1652,8 @@ static void atmci_command_complete(struct atmel_mci *host, static void atmci_detect_change(struct timer_list *t) { - struct atmel_mci_slot *slot = from_timer(slot, t, detect_timer); + struct atmel_mci_slot *slot = timer_container_of(slot, t, + detect_timer); bool present; bool present_old; @@ -2247,7 +2248,7 @@ static int atmci_init_slot(struct atmel_mci *host, struct atmel_mci_slot *slot; int ret; - mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), dev); + mmc = devm_mmc_alloc_host(dev, sizeof(*slot)); if (!mmc) return -ENOMEM; @@ -2263,7 +2264,7 @@ static int atmci_init_slot(struct atmel_mci *host, "slot[%u]: bus_width=%u, detect_pin=%d, " "detect_is_active_high=%s, wp_pin=%d\n", id, slot_data->bus_width, desc_to_gpio(slot_data->detect_pin), - !gpiod_is_active_low(slot_data->detect_pin) ? "true" : "false", + str_true_false(!gpiod_is_active_low(slot_data->detect_pin)), desc_to_gpio(slot_data->wp_pin)); mmc->ops = &atmci_ops; @@ -2320,10 +2321,8 @@ static int atmci_init_slot(struct atmel_mci *host, host->slot[id] = slot; mmc_regulator_get_supply(mmc); ret = mmc_add_host(mmc); - if (ret) { - mmc_free_host(mmc); + if (ret) return ret; - } if (slot->detect_pin) { timer_setup(&slot->detect_timer, atmci_detect_change, 0); @@ -2361,7 +2360,6 @@ static void atmci_cleanup_slot(struct atmel_mci_slot *slot, } slot->host->slot[id] = NULL; - mmc_free_host(slot->mmc); } static int atmci_configure_dma(struct atmel_mci *host) @@ -2569,7 +2567,6 @@ static int atmci_probe(struct platform_device *pdev) dev_info(dev, "Atmel MCI controller at 0x%08lx irq %d, %u slots\n", host->mapbase, irq, nr_slots); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c index 057d42307832..85470773650d 100644 --- a/drivers/mmc/host/au1xmmc.c +++ b/drivers/mmc/host/au1xmmc.c @@ -937,11 +937,10 @@ static int au1xmmc_probe(struct platform_device *pdev) struct resource *r; int ret, iflag; - mmc = mmc_alloc_host(sizeof(struct au1xmmc_host), &pdev->dev); + mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(*host)); if (!mmc) { dev_err(&pdev->dev, "no memory for mmc_host\n"); - ret = -ENOMEM; - goto out0; + return -ENOMEM; } host = mmc_priv(mmc); @@ -953,14 +952,14 @@ static int au1xmmc_probe(struct platform_device *pdev) r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) { dev_err(&pdev->dev, "no mmio defined\n"); - goto out1; + return ret; } host->ioarea = request_mem_region(r->start, resource_size(r), pdev->name); if (!host->ioarea) { dev_err(&pdev->dev, "mmio already in use\n"); - goto out1; + return ret; } host->iobase = ioremap(r->start, 0x3c); @@ -1109,9 +1108,6 @@ out3: out2: release_resource(host->ioarea); kfree(host->ioarea); -out1: - mmc_free_host(mmc); -out0: return ret; } @@ -1151,8 +1147,6 @@ static void au1xmmc_remove(struct platform_device *pdev) iounmap((void *)host->iobase); release_resource(host->ioarea); kfree(host->ioarea); - - mmc_free_host(host->mmc); } } diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c index e5f151d092cd..ee63835b3ca0 100644 --- a/drivers/mmc/host/bcm2835.c +++ b/drivers/mmc/host/bcm2835.c @@ -44,6 +44,7 @@ #include <linux/scatterlist.h> #include <linux/time.h> #include <linux/workqueue.h> +#include <linux/string_choices.h> #include <linux/mmc/host.h> #include <linux/mmc/mmc.h> @@ -391,8 +392,7 @@ static void bcm2835_transfer_block_pio(struct bcm2835_host *host, bool is_read) if (time_after(jiffies, wait_max)) { dev_err(dev, "PIO %s timeout - EDM %08x\n", - is_read ? "read" : "write", - edm); + str_read_write(is_read), edm); hsts = SDHSTS_REW_TIME_OUT; break; } @@ -435,12 +435,12 @@ static void bcm2835_transfer_pio(struct bcm2835_host *host) SDHSTS_CRC7_ERROR | SDHSTS_FIFO_ERROR)) { dev_err(dev, "%s transfer error - HSTS %08x\n", - is_read ? "read" : "write", sdhsts); + str_read_write(is_read), sdhsts); host->data->error = -EILSEQ; } else if ((sdhsts & (SDHSTS_CMD_TIME_OUT | SDHSTS_REW_TIME_OUT))) { dev_err(dev, "%s timeout error - HSTS %08x\n", - is_read ? "read" : "write", sdhsts); + str_read_write(is_read), sdhsts); host->data->error = -ETIMEDOUT; } } @@ -503,7 +503,8 @@ void bcm2835_prepare_dma(struct bcm2835_host *host, struct mmc_data *data) DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!desc) { - dma_unmap_sg(dma_chan->device->dev, data->sg, sg_len, dir_data); + dma_unmap_sg(dma_chan->device->dev, data->sg, data->sg_len, + dir_data); return; } @@ -1371,7 +1372,7 @@ static int bcm2835_probe(struct platform_device *pdev) int ret; dev_dbg(dev, "%s\n", __func__); - mmc = mmc_alloc_host(sizeof(*host), dev); + mmc = devm_mmc_alloc_host(dev, sizeof(*host)); if (!mmc) return -ENOMEM; @@ -1450,7 +1451,6 @@ err: dev_dbg(dev, "%s -> err %d\n", __func__, ret); if (host->dma_chan_rxtx) dma_release_channel(host->dma_chan_rxtx); - mmc_free_host(mmc); return ret; } @@ -1473,8 +1473,6 @@ static void bcm2835_remove(struct platform_device *pdev) if (host->dma_chan_rxtx) dma_release_channel(host->dma_chan_rxtx); - - mmc_free_host(mmc); } static const struct of_device_id bcm2835_match[] = { diff --git a/drivers/mmc/host/cavium-thunderx.c b/drivers/mmc/host/cavium-thunderx.c index 2e2ff984f0b3..1373deb3f531 100644 --- a/drivers/mmc/host/cavium-thunderx.c +++ b/drivers/mmc/host/cavium-thunderx.c @@ -72,7 +72,7 @@ static int thunder_mmc_probe(struct pci_dev *pdev, if (ret) return ret; - ret = pci_request_regions(pdev, KBUILD_MODNAME); + ret = pcim_request_all_regions(pdev, KBUILD_MODNAME); if (ret) return ret; @@ -164,7 +164,6 @@ error: } } clk_disable_unprepare(host->clk); - pci_release_regions(pdev); return ret; } @@ -183,7 +182,6 @@ static void thunder_mmc_remove(struct pci_dev *pdev) writeq(dma_cfg, host->dma_base + MIO_EMM_DMA_CFG(host)); clk_disable_unprepare(host->clk); - pci_release_regions(pdev); } static const struct pci_device_id thunder_mmc_id_table[] = { diff --git a/drivers/mmc/host/cavium.c b/drivers/mmc/host/cavium.c index 95a41983c6c0..9a55db0e657c 100644 --- a/drivers/mmc/host/cavium.c +++ b/drivers/mmc/host/cavium.c @@ -1012,7 +1012,7 @@ int cvm_mmc_of_slot_probe(struct device *dev, struct cvm_mmc_host *host) struct mmc_host *mmc; int ret, id; - mmc = mmc_alloc_host(sizeof(struct cvm_mmc_slot), dev); + mmc = devm_mmc_alloc_host(dev, sizeof(*slot)); if (!mmc) return -ENOMEM; @@ -1022,7 +1022,7 @@ int cvm_mmc_of_slot_probe(struct device *dev, struct cvm_mmc_host *host) ret = cvm_mmc_of_parse(dev, slot); if (ret < 0) - goto error; + return ret; id = ret; /* Set up host parameters */ @@ -1066,12 +1066,7 @@ int cvm_mmc_of_slot_probe(struct device *dev, struct cvm_mmc_host *host) if (ret) { dev_err(dev, "mmc_add_host() returned %d\n", ret); slot->host->slot[id] = NULL; - goto error; } - return 0; - -error: - mmc_free_host(slot->mmc); return ret; } @@ -1079,6 +1074,5 @@ int cvm_mmc_of_slot_remove(struct cvm_mmc_slot *slot) { mmc_remove_host(slot->mmc); slot->host->slot[slot->bus_id] = NULL; - mmc_free_host(slot->mmc); return 0; } diff --git a/drivers/mmc/host/cb710-mmc.c b/drivers/mmc/host/cb710-mmc.c index d741c1f9cf87..448d2f9159ea 100644 --- a/drivers/mmc/host/cb710-mmc.c +++ b/drivers/mmc/host/cb710-mmc.c @@ -8,6 +8,7 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> +#include <linux/string_choices.h> #include "cb710-mmc.h" #define CB710_MMC_REQ_TIMEOUT_MS 2000 @@ -215,7 +216,7 @@ static void cb710_mmc_set_transfer_size(struct cb710_slot *slot, ((count - 1) << 16)|(blocksize - 1)); dev_vdbg(cb710_slot_dev(slot), "set up for %zu block%s of %zu bytes\n", - count, count == 1 ? "" : "s", blocksize); + count, str_plural(count), blocksize); } static void cb710_mmc_fifo_hack(struct cb710_slot *slot) @@ -692,7 +693,7 @@ static int cb710_mmc_init(struct platform_device *pdev) int err; u32 val; - mmc = mmc_alloc_host(sizeof(*reader), cb710_slot_dev(slot)); + mmc = devm_mmc_alloc_host(cb710_slot_dev(slot), sizeof(*reader)); if (!mmc) return -ENOMEM; @@ -741,7 +742,6 @@ err_free_mmc: dev_dbg(cb710_slot_dev(slot), "mmc_add_host() failed: %d\n", err); cb710_set_irq_handler(slot, NULL); - mmc_free_host(mmc); return err; } @@ -764,8 +764,6 @@ static void cb710_mmc_exit(struct platform_device *pdev) cb710_write_port_16(slot, CB710_MMC_CONFIGB_PORT, 0); cancel_work_sync(&reader->finish_req_bh_work); - - mmc_free_host(mmc); } static struct platform_driver cb710_mmc_driver = { diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c index cde4c4339ab7..c691f1b60395 100644 --- a/drivers/mmc/host/davinci_mmc.c +++ b/drivers/mmc/host/davinci_mmc.c @@ -1203,7 +1203,7 @@ static int davinci_mmcsd_probe(struct platform_device *pdev) if (!mem) return -EBUSY; - mmc = mmc_alloc_host(sizeof(struct mmc_davinci_host), &pdev->dev); + mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(*host)); if (!mmc) return -ENOMEM; @@ -1212,19 +1212,16 @@ static int davinci_mmcsd_probe(struct platform_device *pdev) host->mem_res = mem; host->base = devm_ioremap(&pdev->dev, mem->start, mem_size); - if (!host->base) { - ret = -ENOMEM; - goto ioremap_fail; - } + if (!host->base) + return -ENOMEM; host->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); - goto clk_get_fail; - } + if (IS_ERR(host->clk)) + return PTR_ERR(host->clk); + ret = clk_prepare_enable(host->clk); if (ret) - goto clk_prepare_enable_fail; + return ret; host->mmc_input_clk = clk_get_rate(host->clk); @@ -1336,10 +1333,6 @@ cpu_freq_fail: parse_fail: dma_probe_defer: clk_disable_unprepare(host->clk); -clk_prepare_enable_fail: -clk_get_fail: -ioremap_fail: - mmc_free_host(mmc); return ret; } @@ -1352,7 +1345,6 @@ static void davinci_mmcsd_remove(struct platform_device *pdev) mmc_davinci_cpufreq_deregister(host); davinci_release_dma_channels(host); clk_disable_unprepare(host->clk); - mmc_free_host(host->mmc); } #ifdef CONFIG_PM diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 578290015e5b..c5db92bbb094 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -3008,7 +3008,7 @@ static int dw_mci_init_slot(struct dw_mci *host) struct dw_mci_slot *slot; int ret; - mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev); + mmc = devm_mmc_alloc_host(host->dev, sizeof(*slot)); if (!mmc) return -ENOMEM; @@ -3024,18 +3024,18 @@ static int dw_mci_init_slot(struct dw_mci *host) /*if there are external regulators, get them*/ ret = mmc_regulator_get_supply(mmc); if (ret) - goto err_host_allocated; + return ret; if (!mmc->ocr_avail) mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; ret = mmc_of_parse(mmc); if (ret) - goto err_host_allocated; + return ret; ret = dw_mci_init_slot_caps(slot); if (ret) - goto err_host_allocated; + return ret; /* Useful defaults if platform data is unset. */ if (host->use_dma == TRANS_MODE_IDMAC) { @@ -3065,17 +3065,13 @@ static int dw_mci_init_slot(struct dw_mci *host) ret = mmc_add_host(mmc); if (ret) - goto err_host_allocated; + return ret; #if defined(CONFIG_DEBUG_FS) dw_mci_init_debugfs(slot); #endif return 0; - -err_host_allocated: - mmc_free_host(mmc); - return ret; } static void dw_mci_cleanup_slot(struct dw_mci_slot *slot) @@ -3083,7 +3079,6 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot) /* Debugfs stuff is cleaned up by mmc core */ mmc_remove_host(slot->mmc); slot->host->slot = NULL; - mmc_free_host(slot->mmc); } static void dw_mci_init_dma(struct dw_mci *host) @@ -3179,7 +3174,7 @@ no_dma: static void dw_mci_cmd11_timer(struct timer_list *t) { - struct dw_mci *host = from_timer(host, t, cmd11_timer); + struct dw_mci *host = timer_container_of(host, t, cmd11_timer); if (host->state != STATE_SENDING_CMD11) { dev_warn(host->dev, "Unexpected CMD11 timeout\n"); @@ -3193,7 +3188,7 @@ static void dw_mci_cmd11_timer(struct timer_list *t) static void dw_mci_cto_timer(struct timer_list *t) { - struct dw_mci *host = from_timer(host, t, cto_timer); + struct dw_mci *host = timer_container_of(host, t, cto_timer); unsigned long irqflags; u32 pending; @@ -3248,7 +3243,7 @@ exit: static void dw_mci_dto_timer(struct timer_list *t) { - struct dw_mci *host = from_timer(host, t, dto_timer); + struct dw_mci *host = timer_container_of(host, t, dto_timer); unsigned long irqflags; u32 pending; @@ -3622,7 +3617,7 @@ int dw_mci_runtime_suspend(struct device *dev) clk_disable_unprepare(host->ciu_clk); if (host->slot && - (mmc_can_gpio_cd(host->slot->mmc) || + (mmc_host_can_gpio_cd(host->slot->mmc) || !mmc_card_is_removable(host->slot->mmc))) clk_disable_unprepare(host->biu_clk); @@ -3636,7 +3631,7 @@ int dw_mci_runtime_resume(struct device *dev) struct dw_mci *host = dev_get_drvdata(dev); if (host->slot && - (mmc_can_gpio_cd(host->slot->mmc) || + (mmc_host_can_gpio_cd(host->slot->mmc) || !mmc_card_is_removable(host->slot->mmc))) { ret = clk_prepare_enable(host->biu_clk); if (ret) @@ -3690,7 +3685,7 @@ int dw_mci_runtime_resume(struct device *dev) err: if (host->slot && - (mmc_can_gpio_cd(host->slot->mmc) || + (mmc_host_can_gpio_cd(host->slot->mmc) || !mmc_card_is_removable(host->slot->mmc))) clk_disable_unprepare(host->biu_clk); diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index bd1662e275d4..6a0d0250d47b 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -641,7 +641,8 @@ poll_timeout: static void jz4740_mmc_timeout(struct timer_list *t) { - struct jz4740_mmc_host *host = from_timer(host, t, timeout_timer); + struct jz4740_mmc_host *host = timer_container_of(host, t, + timeout_timer); if (!test_and_clear_bit(0, &host->waiting)) return; @@ -1042,7 +1043,7 @@ static int jz4740_mmc_probe(struct platform_device* pdev) struct mmc_host *mmc; struct jz4740_mmc_host *host; - mmc = mmc_alloc_host(sizeof(struct jz4740_mmc_host), &pdev->dev); + mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(*host)); if (!mmc) { dev_err(&pdev->dev, "Failed to alloc mmc host structure\n"); return -ENOMEM; @@ -1054,31 +1055,24 @@ static int jz4740_mmc_probe(struct platform_device* pdev) host->version = (enum jz4740_mmc_version)device_get_match_data(&pdev->dev); ret = mmc_of_parse(mmc); - if (ret) { - dev_err_probe(&pdev->dev, ret, "could not parse device properties\n"); - goto err_free_host; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "could not parse device properties\n"); mmc_regulator_get_supply(mmc); host->irq = platform_get_irq(pdev, 0); - if (host->irq < 0) { - ret = host->irq; - goto err_free_host; - } + if (host->irq < 0) + return host->irq; host->clk = devm_clk_get(&pdev->dev, "mmc"); - if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); - dev_err(&pdev->dev, "Failed to get mmc clock\n"); - goto err_free_host; - } + if (IS_ERR(host->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(host->clk), + "Failed to get mmc clock\n"); host->base = devm_platform_get_and_ioremap_resource(pdev, 0, &host->mem_res); - if (IS_ERR(host->base)) { - ret = PTR_ERR(host->base); - goto err_free_host; - } + if (IS_ERR(host->base)) + return PTR_ERR(host->base); mmc->ops = &jz4740_mmc_ops; if (!mmc->f_max) @@ -1118,10 +1112,8 @@ static int jz4740_mmc_probe(struct platform_device* pdev) ret = request_threaded_irq(host->irq, jz_mmc_irq, jz_mmc_irq_worker, 0, dev_name(&pdev->dev), host); - if (ret) { - dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); - goto err_free_host; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to request irq\n"); jz4740_mmc_clock_disable(host); timer_setup(&host->timeout_timer, jz4740_mmc_timeout, 0); @@ -1152,9 +1144,6 @@ err_release_dma: jz4740_mmc_release_dma_channels(host); err_free_irq: free_irq(host->irq, host); -err_free_host: - mmc_free_host(mmc); - return ret; } @@ -1172,8 +1161,6 @@ static void jz4740_mmc_remove(struct platform_device *pdev) if (host->use_dma) jz4740_mmc_release_dma_channels(host); - - mmc_free_host(host->mmc); } static int jz4740_mmc_suspend(struct device *dev) diff --git a/drivers/mmc/host/litex_mmc.c b/drivers/mmc/host/litex_mmc.c index b338ccfa8f33..d2f19c2dc673 100644 --- a/drivers/mmc/host/litex_mmc.c +++ b/drivers/mmc/host/litex_mmc.c @@ -506,11 +506,6 @@ use_polling: return 0; } -static void litex_mmc_free_host_wrapper(void *mmc) -{ - mmc_free_host(mmc); -} - static int litex_mmc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -525,15 +520,10 @@ static int litex_mmc_probe(struct platform_device *pdev) * If for some reason we need to modify max_blk_count, we must also * re-calculate `max_[req,seg]_size = max_blk_size * max_blk_count;` */ - mmc = mmc_alloc_host(sizeof(struct litex_mmc_host), dev); + mmc = devm_mmc_alloc_host(dev, sizeof(*host)); if (!mmc) return -ENOMEM; - ret = devm_add_action_or_reset(dev, litex_mmc_free_host_wrapper, mmc); - if (ret) - return dev_err_probe(dev, ret, - "Can't register mmc_free_host action\n"); - host = mmc_priv(mmc); host->mmc = mmc; diff --git a/drivers/mmc/host/loongson2-mmc.c b/drivers/mmc/host/loongson2-mmc.c new file mode 100644 index 000000000000..da3daab5f3d6 --- /dev/null +++ b/drivers/mmc/host/loongson2-mmc.c @@ -0,0 +1,1030 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Loongson-2K MMC/SDIO controller driver + * + * Copyright (C) 2018-2025 Loongson Technology Corporation Limited. + * + */ + +#include <linux/bitfield.h> +#include <linux/bitrev.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/dmaengine.h> +#include <linux/dma-mapping.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/mmc/core.h> +#include <linux/mmc/host.h> +#include <linux/mmc/mmc.h> +#include <linux/mmc/sd.h> +#include <linux/mmc/sdio.h> +#include <linux/mmc/slot-gpio.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#define LOONGSON2_MMC_REG_CTL 0x00 /* Control Register */ +#define LOONGSON2_MMC_REG_PRE 0x04 /* Prescaler Register */ +#define LOONGSON2_MMC_REG_CARG 0x08 /* Command Register */ +#define LOONGSON2_MMC_REG_CCTL 0x0c /* Command Control Register */ +#define LOONGSON2_MMC_REG_CSTS 0x10 /* Command Status Register */ +#define LOONGSON2_MMC_REG_RSP0 0x14 /* Command Response Register 0 */ +#define LOONGSON2_MMC_REG_RSP1 0x18 /* Command Response Register 1 */ +#define LOONGSON2_MMC_REG_RSP2 0x1c /* Command Response Register 2 */ +#define LOONGSON2_MMC_REG_RSP3 0x20 /* Command Response Register 3 */ +#define LOONGSON2_MMC_REG_TIMER 0x24 /* Data Timeout Register */ +#define LOONGSON2_MMC_REG_BSIZE 0x28 /* Block Size Register */ +#define LOONGSON2_MMC_REG_DCTL 0x2c /* Data Control Register */ +#define LOONGSON2_MMC_REG_DCNT 0x30 /* Data Counter Register */ +#define LOONGSON2_MMC_REG_DSTS 0x34 /* Data Status Register */ +#define LOONGSON2_MMC_REG_FSTS 0x38 /* FIFO Status Register */ +#define LOONGSON2_MMC_REG_INT 0x3c /* Interrupt Register */ +#define LOONGSON2_MMC_REG_DATA 0x40 /* Data Register */ +#define LOONGSON2_MMC_REG_IEN 0x64 /* Interrupt Enable Register */ + +/* EMMC DLL Mode Registers */ +#define LOONGSON2_MMC_REG_DLLVAL 0xf0 /* DLL Master Lock-value Register */ +#define LOONGSON2_MMC_REG_DLLCTL 0xf4 /* DLL Control Register */ +#define LOONGSON2_MMC_REG_DELAY 0xf8 /* DLL Delayed Parameter Register */ +#define LOONGSON2_MMC_REG_SEL 0xfc /* Bus Mode Selection Register */ + +/* Exclusive DMA R/W Registers */ +#define LOONGSON2_MMC_REG_WDMA_LO 0x400 +#define LOONGSON2_MMC_REG_WDMA_HI 0x404 +#define LOONGSON2_MMC_REG_RDMA_LO 0x800 +#define LOONGSON2_MMC_REG_RDMA_HI 0x804 + +/* Bitfields of control register */ +#define LOONGSON2_MMC_CTL_ENCLK BIT(0) +#define LOONGSON2_MMC_CTL_EXTCLK BIT(1) +#define LOONGSON2_MMC_CTL_RESET BIT(8) + +/* Bitfields of prescaler register */ +#define LOONGSON2_MMC_PRE GENMASK(9, 0) +#define LOONGSON2_MMC_PRE_EN BIT(31) + +/* Bitfields of command control register */ +#define LOONGSON2_MMC_CCTL_INDEX GENMASK(5, 0) +#define LOONGSON2_MMC_CCTL_HOST BIT(6) +#define LOONGSON2_MMC_CCTL_START BIT(8) +#define LOONGSON2_MMC_CCTL_WAIT_RSP BIT(9) +#define LOONGSON2_MMC_CCTL_LONG_RSP BIT(10) +#define LOONGSON2_MMC_CCTL_ABORT BIT(12) +#define LOONGSON2_MMC_CCTL_CHECK BIT(13) +#define LOONGSON2_MMC_CCTL_SDIO BIT(14) +#define LOONGSON2_MMC_CCTL_CMD6 BIT(18) + +/* Bitfields of command status register */ +#define LOONGSON2_MMC_CSTS_INDEX GENMASK(7, 0) +#define LOONGSON2_MMC_CSTS_ON BIT(8) +#define LOONGSON2_MMC_CSTS_RSP BIT(9) +#define LOONGSON2_MMC_CSTS_TIMEOUT BIT(10) +#define LOONGSON2_MMC_CSTS_END BIT(11) +#define LOONGSON2_MMC_CSTS_CRC_ERR BIT(12) +#define LOONGSON2_MMC_CSTS_AUTO_STOP BIT(13) +#define LOONGSON2_MMC_CSTS_FIN BIT(14) + +/* Bitfields of data timeout register */ +#define LOONGSON2_MMC_DTIMR GENMASK(23, 0) + +/* Bitfields of block size register */ +#define LOONGSON2_MMC_BSIZE GENMASK(11, 0) + +/* Bitfields of data control register */ +#define LOONGSON2_MMC_DCTL_BNUM GENMASK(11, 0) +#define LOONGSON2_MMC_DCTL_START BIT(14) +#define LOONGSON2_MMC_DCTL_ENDMA BIT(15) +#define LOONGSON2_MMC_DCTL_WIDE BIT(16) +#define LOONGSON2_MMC_DCTL_RWAIT BIT(17) +#define LOONGSON2_MMC_DCTL_IO_SUSPEND BIT(18) +#define LOONGSON2_MMC_DCTL_IO_RESUME BIT(19) +#define LOONGSON2_MMC_DCTL_RW_RESUME BIT(20) +#define LOONGSON2_MMC_DCTL_8BIT_BUS BIT(26) + +/* Bitfields of sata counter register */ +#define LOONGSON2_MMC_DCNT_BNUM GENMASK(11, 0) +#define LOONGSON2_MMC_DCNT_BYTE GENMASK(23, 12) + +/* Bitfields of command status register */ +#define LOONGSON2_MMC_DSTS_RXON BIT(0) +#define LOONGSON2_MMC_DSTS_TXON BIT(1) +#define LOONGSON2_MMC_DSTS_SBITERR BIT(2) +#define LOONGSON2_MMC_DSTS_BUSYFIN BIT(3) +#define LOONGSON2_MMC_DSTS_XFERFIN BIT(4) +#define LOONGSON2_MMC_DSTS_DTIMEOUT BIT(5) +#define LOONGSON2_MMC_DSTS_RXCRC BIT(6) +#define LOONGSON2_MMC_DSTS_TXCRC BIT(7) +#define LOONGSON2_MMC_DSTS_IRQ BIT(8) +#define LOONGSON2_MMC_DSTS_START BIT(13) +#define LOONGSON2_MMC_DSTS_RESUME BIT(15) +#define LOONGSON2_MMC_DSTS_SUSPEND BIT(16) + +/* Bitfields of FIFO Status Register */ +#define LOONGSON2_MMC_FSTS_TXFULL BIT(11) + +/* Bitfields of interrupt register */ +#define LOONGSON2_MMC_INT_DFIN BIT(0) +#define LOONGSON2_MMC_INT_DTIMEOUT BIT(1) +#define LOONGSON2_MMC_INT_RXCRC BIT(2) +#define LOONGSON2_MMC_INT_TXCRC BIT(3) +#define LOONGSON2_MMC_INT_PROGERR BIT(4) +#define LOONGSON2_MMC_INT_SDIOIRQ BIT(5) +#define LOONGSON2_MMC_INT_CSENT BIT(6) +#define LOONGSON2_MMC_INT_CTIMEOUT BIT(7) +#define LOONGSON2_MMC_INT_RESPCRC BIT(8) +#define LOONGSON2_MMC_INT_BUSYEND BIT(9) + +/* Bitfields of interrupt enable register */ +#define LOONGSON2_MMC_IEN_DFIN BIT(0) +#define LOONGSON2_MMC_IEN_DTIMEOUT BIT(1) +#define LOONGSON2_MMC_IEN_RXCRC BIT(2) +#define LOONGSON2_MMC_IEN_TXCRC BIT(3) +#define LOONGSON2_MMC_IEN_PROGERR BIT(4) +#define LOONGSON2_MMC_IEN_SDIOIRQ BIT(5) +#define LOONGSON2_MMC_IEN_CSENT BIT(6) +#define LOONGSON2_MMC_IEN_CTIMEOUT BIT(7) +#define LOONGSON2_MMC_IEN_RESPCRC BIT(8) +#define LOONGSON2_MMC_IEN_BUSYEND BIT(9) + +#define LOONGSON2_MMC_IEN_ALL GENMASK(9, 0) +#define LOONGSON2_MMC_INT_CLEAR GENMASK(9, 0) + +/* Bitfields of DLL master lock-value register */ +#define LOONGSON2_MMC_DLLVAL_DONE BIT(8) + +/* Bitfields of DLL control register */ +#define LOONGSON2_MMC_DLLCTL_TIME GENMASK(7, 0) +#define LOONGSON2_MMC_DLLCTL_INCRE GENMASK(15, 8) +#define LOONGSON2_MMC_DLLCTL_START GENMASK(23, 16) +#define LOONGSON2_MMC_DLLCTL_CLK_MODE BIT(24) +#define LOONGSON2_MMC_DLLCTL_START_BIT BIT(25) +#define LOONGSON2_MMC_DLLCTL_TIME_BPASS GENMASK(29, 26) + +#define LOONGSON2_MMC_DELAY_PAD GENMASK(7, 0) +#define LOONGSON2_MMC_DELAY_RD GENMASK(15, 8) + +#define LOONGSON2_MMC_SEL_DATA BIT(0) /* 0: SDR, 1: DDR */ +#define LOONGSON2_MMC_SEL_BUS BIT(0) /* 0: EMMC, 1: SDIO */ + +/* Internal dma controller registers */ + +/* Bitfields of Global Configuration Register */ +#define LOONGSON2_MMC_DMA_64BIT_EN BIT(0) /* 1: 64 bit support */ +#define LOONGSON2_MMC_DMA_UNCOHERENT_EN BIT(1) /* 0: cache, 1: uncache */ +#define LOONGSON2_MMC_DMA_ASK_VALID BIT(2) +#define LOONGSON2_MMC_DMA_START BIT(3) /* DMA start operation */ +#define LOONGSON2_MMC_DMA_STOP BIT(4) /* DMA stop operation */ +#define LOONGSON2_MMC_DMA_CONFIG_MASK GENMASK_ULL(4, 0) /* DMA controller config bits mask */ + +/* Bitfields of ndesc_addr field of HW descriptor */ +#define LOONGSON2_MMC_DMA_DESC_EN BIT(0) /*1: The next descriptor is valid */ +#define LOONGSON2_MMC_DMA_DESC_ADDR_LOW GENMASK(31, 1) + +/* Bitfields of cmd field of HW descriptor */ +#define LOONGSON2_MMC_DMA_INT BIT(1) /* Enable DMA interrupts */ +#define LOONGSON2_MMC_DMA_DATA_DIR BIT(12) /* 1: write to device, 0: read from device */ + +#define LOONGSON2_MMC_DLLVAL_TIMEOUT_US 4000 +#define LOONGSON2_MMC_TXFULL_TIMEOUT_US 500 + +/* Loongson-2K1000 SDIO2 DMA routing register */ +#define LS2K1000_SDIO_DMA_MASK GENMASK(17, 15) +#define LS2K1000_DMA0_CONF 0x0 +#define LS2K1000_DMA1_CONF 0x1 +#define LS2K1000_DMA2_CONF 0x2 +#define LS2K1000_DMA3_CONF 0x3 +#define LS2K1000_DMA4_CONF 0x4 + +/* Loongson-2K0500 SDIO2 DMA routing register */ +#define LS2K0500_SDIO_DMA_MASK GENMASK(15, 14) +#define LS2K0500_DMA0_CONF 0x1 +#define LS2K0500_DMA1_CONF 0x2 +#define LS2K0500_DMA2_CONF 0x3 + +enum loongson2_mmc_state { + STATE_NONE, + STATE_FINALIZE, + STATE_CMDSENT, + STATE_RSPFIN, + STATE_XFERFINISH, + STATE_XFERFINISH_RSPFIN, +}; + +struct loongson2_dma_desc { + u32 ndesc_addr; + u32 mem_addr; + u32 apb_addr; + u32 len; + u32 step_len; + u32 step_times; + u32 cmd; + u32 stats; + u32 high_ndesc_addr; + u32 high_mem_addr; + u32 reserved[2]; +} __packed; + +struct loongson2_mmc_host { + struct device *dev; + struct mmc_request *mrq; + struct regmap *regmap; + struct resource *res; + struct clk *clk; + u32 current_clk; + void *sg_cpu; + dma_addr_t sg_dma; + int dma_complete; + struct dma_chan *chan; + int cmd_is_stop; + int bus_width; + spinlock_t lock; /* Prevent races with irq handler */ + enum loongson2_mmc_state state; + const struct loongson2_mmc_pdata *pdata; +}; + +struct loongson2_mmc_pdata { + const struct regmap_config *regmap_config; + void (*reorder_cmd_data)(struct loongson2_mmc_host *host, struct mmc_command *cmd); + void (*fix_data_timeout)(struct loongson2_mmc_host *host, struct mmc_command *cmd); + int (*setting_dma)(struct loongson2_mmc_host *host, struct platform_device *pdev); + int (*prepare_dma)(struct loongson2_mmc_host *host, struct mmc_data *data); + void (*release_dma)(struct loongson2_mmc_host *host, struct device *dev); +}; + +static void loongson2_mmc_send_command(struct loongson2_mmc_host *host, + struct mmc_command *cmd) +{ + u32 cctrl; + + if (cmd->data) + host->state = STATE_XFERFINISH_RSPFIN; + else if (cmd->flags & MMC_RSP_PRESENT) + host->state = STATE_RSPFIN; + else + host->state = STATE_CMDSENT; + + regmap_write(host->regmap, LOONGSON2_MMC_REG_CARG, cmd->arg); + + cctrl = FIELD_PREP(LOONGSON2_MMC_CCTL_INDEX, cmd->opcode); + cctrl |= LOONGSON2_MMC_CCTL_HOST | LOONGSON2_MMC_CCTL_START; + + if (cmd->opcode == SD_SWITCH && cmd->data) + cctrl |= LOONGSON2_MMC_CCTL_CMD6; + + if (cmd->flags & MMC_RSP_PRESENT) + cctrl |= LOONGSON2_MMC_CCTL_WAIT_RSP; + + if (cmd->flags & MMC_RSP_136) + cctrl |= LOONGSON2_MMC_CCTL_LONG_RSP; + + regmap_write(host->regmap, LOONGSON2_MMC_REG_CCTL, cctrl); +} + +static int loongson2_mmc_setup_data(struct loongson2_mmc_host *host, + struct mmc_data *data) +{ + u32 dctrl; + + if ((data->blksz & 3) != 0) + return -EINVAL; + + dctrl = FIELD_PREP(LOONGSON2_MMC_DCTL_BNUM, data->blocks); + dctrl |= LOONGSON2_MMC_DCTL_START | LOONGSON2_MMC_DCTL_ENDMA; + + if (host->bus_width == MMC_BUS_WIDTH_4) + dctrl |= LOONGSON2_MMC_DCTL_WIDE; + else if (host->bus_width == MMC_BUS_WIDTH_8) + dctrl |= LOONGSON2_MMC_DCTL_8BIT_BUS; + + regmap_write(host->regmap, LOONGSON2_MMC_REG_DCTL, dctrl); + regmap_write(host->regmap, LOONGSON2_MMC_REG_BSIZE, data->blksz); + regmap_write(host->regmap, LOONGSON2_MMC_REG_TIMER, U32_MAX); + + return 0; +} + +static int loongson2_mmc_prepare_dma(struct loongson2_mmc_host *host, + struct mmc_data *data) +{ + int ret; + + if (!data) + return 0; + + ret = loongson2_mmc_setup_data(host, data); + if (ret) + return ret; + + host->dma_complete = 0; + + return host->pdata->prepare_dma(host, data); +} + +static void loongson2_mmc_send_request(struct mmc_host *mmc) +{ + int ret; + struct loongson2_mmc_host *host = mmc_priv(mmc); + struct mmc_request *mrq = host->mrq; + struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd; + + ret = loongson2_mmc_prepare_dma(host, cmd->data); + if (ret) { + dev_err(host->dev, "DMA data prepared failed with %d\n", ret); + cmd->error = ret; + cmd->data->error = ret; + mmc_request_done(mmc, mrq); + return; + } + + if (host->pdata->fix_data_timeout) + host->pdata->fix_data_timeout(host, cmd); + + loongson2_mmc_send_command(host, cmd); + + /* Fix deselect card */ + if (cmd->opcode == MMC_SELECT_CARD && cmd->arg == 0) { + cmd->error = 0; + mmc_request_done(mmc, mrq); + } +} + +static irqreturn_t loongson2_mmc_irq_worker(int irq, void *devid) +{ + struct loongson2_mmc_host *host = (struct loongson2_mmc_host *)devid; + struct mmc_host *mmc = mmc_from_priv(host); + struct mmc_request *mrq = host->mrq; + struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd; + + if (cmd->data) + dma_unmap_sg(mmc_dev(mmc), cmd->data->sg, cmd->data->sg_len, + mmc_get_dma_dir(cmd->data)); + + if (cmd->data && !cmd->error && + !cmd->data->error && !host->dma_complete) + return IRQ_HANDLED; + + /* Read response from controller. */ + regmap_read(host->regmap, LOONGSON2_MMC_REG_RSP0, &cmd->resp[0]); + regmap_read(host->regmap, LOONGSON2_MMC_REG_RSP1, &cmd->resp[1]); + regmap_read(host->regmap, LOONGSON2_MMC_REG_RSP2, &cmd->resp[2]); + regmap_read(host->regmap, LOONGSON2_MMC_REG_RSP3, &cmd->resp[3]); + + /* Cleanup controller */ + regmap_write(host->regmap, LOONGSON2_MMC_REG_CARG, 0); + regmap_write(host->regmap, LOONGSON2_MMC_REG_CCTL, 0); + + if (cmd->data && cmd->error) + cmd->data->error = cmd->error; + + if (cmd->data && cmd->data->stop && !host->cmd_is_stop) { + host->cmd_is_stop = 1; + loongson2_mmc_send_request(mmc); + return IRQ_HANDLED; + } + + /* If we have no data transfer we are finished here */ + if (!mrq->data) + goto request_done; + + /* Calculate the amount of bytes transfer if there was no error */ + if (mrq->data->error == 0) { + mrq->data->bytes_xfered = + (mrq->data->blocks * mrq->data->blksz); + } else { + mrq->data->bytes_xfered = 0; + } + +request_done: + host->state = STATE_NONE; + host->mrq = NULL; + mmc_request_done(mmc, mrq); + return IRQ_HANDLED; +} + +static irqreturn_t loongson2_mmc_irq(int irq, void *devid) +{ + struct loongson2_mmc_host *host = (struct loongson2_mmc_host *)devid; + struct mmc_host *mmc = mmc_from_priv(host); + struct mmc_command *cmd; + unsigned long iflags; + u32 dsts, imsk; + + regmap_read(host->regmap, LOONGSON2_MMC_REG_INT, &imsk); + regmap_read(host->regmap, LOONGSON2_MMC_REG_DSTS, &dsts); + + if ((dsts & LOONGSON2_MMC_DSTS_IRQ) && + (imsk & LOONGSON2_MMC_INT_SDIOIRQ)) { + regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_INT, + LOONGSON2_MMC_INT_SDIOIRQ, LOONGSON2_MMC_INT_SDIOIRQ); + + sdio_signal_irq(mmc); + return IRQ_HANDLED; + } + + spin_lock_irqsave(&host->lock, iflags); + + if (host->state == STATE_NONE || host->state == STATE_FINALIZE || !host->mrq) + goto irq_out; + + cmd = host->cmd_is_stop ? host->mrq->stop : host->mrq->cmd; + if (!cmd) + goto irq_out; + + cmd->error = 0; + + if (imsk & LOONGSON2_MMC_INT_CTIMEOUT) { + cmd->error = -ETIMEDOUT; + goto close_transfer; + } + + if (imsk & LOONGSON2_MMC_INT_CSENT) { + if (host->state == STATE_RSPFIN || host->state == STATE_CMDSENT) + goto close_transfer; + + if (host->state == STATE_XFERFINISH_RSPFIN) + host->state = STATE_XFERFINISH; + } + + if (!cmd->data) + goto irq_out; + + if (imsk & (LOONGSON2_MMC_INT_RXCRC | LOONGSON2_MMC_INT_TXCRC)) { + cmd->data->error = -EILSEQ; + goto close_transfer; + } + + if (imsk & LOONGSON2_MMC_INT_DTIMEOUT) { + cmd->data->error = -ETIMEDOUT; + goto close_transfer; + } + + if (imsk & LOONGSON2_MMC_INT_DFIN) { + if (host->state == STATE_XFERFINISH) { + host->dma_complete = 1; + goto close_transfer; + } + + if (host->state == STATE_XFERFINISH_RSPFIN) + host->state = STATE_RSPFIN; + } + +irq_out: + regmap_write(host->regmap, LOONGSON2_MMC_REG_INT, imsk); + spin_unlock_irqrestore(&host->lock, iflags); + return IRQ_HANDLED; + +close_transfer: + host->state = STATE_FINALIZE; + host->pdata->reorder_cmd_data(host, cmd); + regmap_write(host->regmap, LOONGSON2_MMC_REG_INT, imsk); + spin_unlock_irqrestore(&host->lock, iflags); + return IRQ_WAKE_THREAD; +} + +static void loongson2_mmc_dll_mode_init(struct loongson2_mmc_host *host) +{ + u32 val, pad_delay, delay; + int ret; + + regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_SEL, + LOONGSON2_MMC_SEL_DATA, LOONGSON2_MMC_SEL_DATA); + + val = FIELD_PREP(LOONGSON2_MMC_DLLCTL_TIME, 0xc8) + | FIELD_PREP(LOONGSON2_MMC_DLLCTL_INCRE, 0x1) + | FIELD_PREP(LOONGSON2_MMC_DLLCTL_START, 0x1) + | FIELD_PREP(LOONGSON2_MMC_DLLCTL_CLK_MODE, 0x1) + | FIELD_PREP(LOONGSON2_MMC_DLLCTL_START_BIT, 0x1) + | FIELD_PREP(LOONGSON2_MMC_DLLCTL_TIME_BPASS, 0xf); + + regmap_write(host->regmap, LOONGSON2_MMC_REG_DLLCTL, val); + + ret = regmap_read_poll_timeout(host->regmap, LOONGSON2_MMC_REG_DLLVAL, val, + (val & LOONGSON2_MMC_DLLVAL_DONE), 0, + LOONGSON2_MMC_DLLVAL_TIMEOUT_US); + if (ret < 0) + return; + + regmap_read(host->regmap, LOONGSON2_MMC_REG_DLLVAL, &val); + pad_delay = FIELD_GET(GENMASK(7, 1), val); + + delay = FIELD_PREP(LOONGSON2_MMC_DELAY_PAD, pad_delay) + | FIELD_PREP(LOONGSON2_MMC_DELAY_RD, pad_delay + 1); + + regmap_write(host->regmap, LOONGSON2_MMC_REG_DELAY, delay); +} + +static void loongson2_mmc_set_clk(struct loongson2_mmc_host *host, struct mmc_ios *ios) +{ + u32 pre; + + pre = DIV_ROUND_UP(host->current_clk, ios->clock); + if (pre > 255) + pre = 255; + + regmap_write(host->regmap, LOONGSON2_MMC_REG_PRE, pre | LOONGSON2_MMC_PRE_EN); + + regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_CTL, + LOONGSON2_MMC_CTL_ENCLK, LOONGSON2_MMC_CTL_ENCLK); + + /* EMMC DLL mode setting */ + if (ios->timing == MMC_TIMING_UHS_DDR50 || ios->timing == MMC_TIMING_MMC_DDR52) + loongson2_mmc_dll_mode_init(host); +} + +static void loongson2_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct loongson2_mmc_host *host = mmc_priv(mmc); + int ret; + + if (ios->power_mode == MMC_POWER_UP) { + if (!IS_ERR(mmc->supply.vmmc)) { + ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); + if (ret) { + dev_err(host->dev, "failed to enable vmmc regulator\n"); + return; /* return, if failed turn on vmmc */ + } + } + regmap_write(host->regmap, LOONGSON2_MMC_REG_CTL, LOONGSON2_MMC_CTL_RESET); + mdelay(10); + regmap_write(host->regmap, LOONGSON2_MMC_REG_CTL, LOONGSON2_MMC_CTL_EXTCLK); + regmap_write(host->regmap, LOONGSON2_MMC_REG_INT, LOONGSON2_MMC_IEN_ALL); + regmap_write(host->regmap, LOONGSON2_MMC_REG_IEN, LOONGSON2_MMC_INT_CLEAR); + } else if (ios->power_mode == MMC_POWER_OFF) { + regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_CTL, + LOONGSON2_MMC_CTL_RESET, LOONGSON2_MMC_CTL_RESET); + if (!IS_ERR(mmc->supply.vmmc)) + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); + return; + } + + loongson2_mmc_set_clk(host, ios); + + host->bus_width = ios->bus_width; +} + +static void loongson2_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct loongson2_mmc_host *host = mmc_priv(mmc); + + host->cmd_is_stop = 0; + host->mrq = mrq; + loongson2_mmc_send_request(mmc); +} + +static void loongson2_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) +{ + struct loongson2_mmc_host *host = mmc_priv(mmc); + + regmap_update_bits(host->regmap, LOONGSON2_MMC_REG_IEN, LOONGSON2_MMC_INT_SDIOIRQ, enable); +} + +static void loongson2_mmc_ack_sdio_irq(struct mmc_host *mmc) +{ + loongson2_mmc_enable_sdio_irq(mmc, 1); +} + +static struct mmc_host_ops loongson2_mmc_ops = { + .request = loongson2_mmc_request, + .set_ios = loongson2_mmc_set_ios, + .get_ro = mmc_gpio_get_ro, + .get_cd = mmc_gpio_get_cd, + .enable_sdio_irq = loongson2_mmc_enable_sdio_irq, + .ack_sdio_irq = loongson2_mmc_ack_sdio_irq, +}; + +static const struct regmap_config ls2k0500_mmc_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = LOONGSON2_MMC_REG_IEN, +}; + +static int loongson2_reorder_cmd_list[] = { SD_APP_SEND_SCR, SD_APP_SEND_NUM_WR_BLKS, + SD_APP_SD_STATUS, MMC_SEND_WRITE_PROT, SD_SWITCH }; + +/* + * According to SD spec, ACMD13, ACMD22, ACMD51 and CMD30 + * response datas has different byte order with usual data packets. + * However sdio controller will send these datas in usual data format, + * so we need to adjust these datas to a protocol consistent byte order. + */ +static void ls2k0500_mmc_reorder_cmd_data(struct loongson2_mmc_host *host, + struct mmc_command *cmd) +{ + struct scatterlist *sg; + u32 *data; + int i, j; + + if (mmc_cmd_type(cmd) != MMC_CMD_ADTC) + return; + + for (i = 0; i < ARRAY_SIZE(loongson2_reorder_cmd_list); i++) + if (cmd->opcode == loongson2_reorder_cmd_list[i]) + break; + + if (i == ARRAY_SIZE(loongson2_reorder_cmd_list)) + return; + + for_each_sg(cmd->data->sg, sg, cmd->data->sg_len, i) { + data = sg_virt(&sg[i]); + for (j = 0; j < (sg_dma_len(&sg[i]) / 4); j++) + if (cmd->opcode == SD_SWITCH) + data[j] = bitrev8x4(data[j]); + else + data[j] = (__force u32)cpu_to_be32(data[j]); + } +} + +static int loongson2_mmc_prepare_external_dma(struct loongson2_mmc_host *host, + struct mmc_data *data) +{ + struct mmc_host *mmc = mmc_from_priv(host); + struct dma_slave_config dma_conf = { }; + struct dma_async_tx_descriptor *desc; + int ret; + + ret = dma_map_sg(mmc_dev(mmc), data->sg, data->sg_len, + mmc_get_dma_dir(data)); + if (!ret) + return -ENOMEM; + + dma_conf.src_addr = host->res->start + LOONGSON2_MMC_REG_DATA, + dma_conf.dst_addr = host->res->start + LOONGSON2_MMC_REG_DATA, + dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, + dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, + dma_conf.direction = !(data->flags & MMC_DATA_WRITE) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV; + + dmaengine_slave_config(host->chan, &dma_conf); + desc = dmaengine_prep_slave_sg(host->chan, data->sg, data->sg_len, + dma_conf.direction, + DMA_CTRL_ACK | DMA_PREP_INTERRUPT); + if (!desc) + goto unmap_exit; + + dmaengine_submit(desc); + dma_async_issue_pending(host->chan); + + return 0; + +unmap_exit: + dma_unmap_sg(mmc_dev(mmc), data->sg, data->sg_len, mmc_get_dma_dir(data)); + return -ENOMEM; +} + +static void loongson2_mmc_release_external_dma(struct loongson2_mmc_host *host, + struct device *dev) +{ + dma_release_channel(host->chan); +} + +static int ls2k0500_mmc_set_external_dma(struct loongson2_mmc_host *host, + struct platform_device *pdev) +{ + int ret, val; + void __iomem *regs; + + regs = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + val = readl(regs); + val |= FIELD_PREP(LS2K0500_SDIO_DMA_MASK, LS2K0500_DMA2_CONF); + writel(val, regs); + + host->chan = dma_request_chan(&pdev->dev, "rx-tx"); + ret = PTR_ERR_OR_ZERO(host->chan); + if (ret) { + dev_err(&pdev->dev, "Cannot get DMA channel.\n"); + return ret; + } + + return 0; +} + +static struct loongson2_mmc_pdata ls2k0500_mmc_pdata = { + .regmap_config = &ls2k0500_mmc_regmap_config, + .reorder_cmd_data = ls2k0500_mmc_reorder_cmd_data, + .setting_dma = ls2k0500_mmc_set_external_dma, + .prepare_dma = loongson2_mmc_prepare_external_dma, + .release_dma = loongson2_mmc_release_external_dma, +}; + +static int ls2k1000_mmc_set_external_dma(struct loongson2_mmc_host *host, + struct platform_device *pdev) +{ + int ret, val; + void __iomem *regs; + + regs = devm_platform_ioremap_resource(pdev, 1); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + val = readl(regs); + val |= FIELD_PREP(LS2K1000_SDIO_DMA_MASK, LS2K1000_DMA1_CONF); + writel(val, regs); + + host->chan = dma_request_chan(&pdev->dev, "rx-tx"); + ret = PTR_ERR_OR_ZERO(host->chan); + if (ret) { + dev_err(&pdev->dev, "Cannot get DMA channel.\n"); + return ret; + } + + return 0; +} + +static struct loongson2_mmc_pdata ls2k1000_mmc_pdata = { + .regmap_config = &ls2k0500_mmc_regmap_config, + .reorder_cmd_data = ls2k0500_mmc_reorder_cmd_data, + .setting_dma = ls2k1000_mmc_set_external_dma, + .prepare_dma = loongson2_mmc_prepare_external_dma, + .release_dma = loongson2_mmc_release_external_dma, +}; + +static const struct regmap_config ls2k2000_mmc_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = LOONGSON2_MMC_REG_RDMA_HI, +}; + +static void ls2k2000_mmc_reorder_cmd_data(struct loongson2_mmc_host *host, + struct mmc_command *cmd) +{ + struct scatterlist *sg; + u32 *data; + int i, j; + + if (cmd->opcode != SD_SWITCH || mmc_cmd_type(cmd) != MMC_CMD_ADTC) + return; + + for_each_sg(cmd->data->sg, sg, cmd->data->sg_len, i) { + data = sg_virt(&sg[i]); + for (j = 0; j < (sg_dma_len(&sg[i]) / 4); j++) + data[j] = bitrev8x4(data[j]); + } +} + +/* + * This is a controller hardware defect. Single/multiple block write commands + * must be sent after the TX FULL flag is set, otherwise a data timeout interrupt + * will occur. + */ +static void ls2k2000_mmc_fix_data_timeout(struct loongson2_mmc_host *host, + struct mmc_command *cmd) +{ + int val; + + if (cmd->opcode != MMC_WRITE_BLOCK && cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK) + return; + + regmap_read_poll_timeout(host->regmap, LOONGSON2_MMC_REG_FSTS, val, + (val & LOONGSON2_MMC_FSTS_TXFULL), 0, + LOONGSON2_MMC_TXFULL_TIMEOUT_US); +} + +static int loongson2_mmc_prepare_internal_dma(struct loongson2_mmc_host *host, + struct mmc_data *data) +{ + struct loongson2_dma_desc *pdes = (struct loongson2_dma_desc *)host->sg_cpu; + struct mmc_host *mmc = mmc_from_priv(host); + dma_addr_t next_desc = host->sg_dma; + struct scatterlist *sg; + int reg_lo, reg_hi; + u64 dma_order; + int i, ret; + + ret = dma_map_sg(mmc_dev(mmc), data->sg, data->sg_len, + mmc_get_dma_dir(data)); + if (!ret) + return -ENOMEM; + + for_each_sg(data->sg, sg, data->sg_len, i) { + pdes[i].len = sg_dma_len(&sg[i]) / 4; + pdes[i].step_len = 0; + pdes[i].step_times = 1; + pdes[i].mem_addr = lower_32_bits(sg_dma_address(&sg[i])); + pdes[i].high_mem_addr = upper_32_bits(sg_dma_address(&sg[i])); + pdes[i].apb_addr = host->res->start + LOONGSON2_MMC_REG_DATA; + pdes[i].cmd = LOONGSON2_MMC_DMA_INT; + + if (data->flags & MMC_DATA_READ) { + reg_lo = LOONGSON2_MMC_REG_RDMA_LO; + reg_hi = LOONGSON2_MMC_REG_RDMA_HI; + } else { + pdes[i].cmd |= LOONGSON2_MMC_DMA_DATA_DIR; + reg_lo = LOONGSON2_MMC_REG_WDMA_LO; + reg_hi = LOONGSON2_MMC_REG_WDMA_HI; + } + + next_desc += sizeof(struct loongson2_dma_desc); + pdes[i].ndesc_addr = lower_32_bits(next_desc) | + LOONGSON2_MMC_DMA_DESC_EN; + pdes[i].high_ndesc_addr = upper_32_bits(next_desc); + } + + /* Setting the last descriptor enable bit */ + pdes[i - 1].ndesc_addr &= ~LOONGSON2_MMC_DMA_DESC_EN; + + dma_order = (host->sg_dma & ~LOONGSON2_MMC_DMA_CONFIG_MASK) | + LOONGSON2_MMC_DMA_64BIT_EN | + LOONGSON2_MMC_DMA_START; + + regmap_write(host->regmap, reg_hi, upper_32_bits(dma_order)); + regmap_write(host->regmap, reg_lo, lower_32_bits(dma_order)); + + return 0; +} + +static int ls2k2000_mmc_set_internal_dma(struct loongson2_mmc_host *host, + struct platform_device *pdev) +{ + host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, + &host->sg_dma, GFP_KERNEL); + if (!host->sg_cpu) + return -ENOMEM; + + memset(host->sg_cpu, 0, PAGE_SIZE); + return 0; +} + +static void loongson2_mmc_release_internal_dma(struct loongson2_mmc_host *host, + struct device *dev) +{ + dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); +} + +static struct loongson2_mmc_pdata ls2k2000_mmc_pdata = { + .regmap_config = &ls2k2000_mmc_regmap_config, + .reorder_cmd_data = ls2k2000_mmc_reorder_cmd_data, + .fix_data_timeout = ls2k2000_mmc_fix_data_timeout, + .setting_dma = ls2k2000_mmc_set_internal_dma, + .prepare_dma = loongson2_mmc_prepare_internal_dma, + .release_dma = loongson2_mmc_release_internal_dma, +}; + +static int loongson2_mmc_resource_request(struct platform_device *pdev, + struct loongson2_mmc_host *host) +{ + struct device *dev = &pdev->dev; + void __iomem *base; + int ret, irq; + + base = devm_platform_get_and_ioremap_resource(pdev, 0, &host->res); + if (IS_ERR(base)) + return PTR_ERR(base); + + host->regmap = devm_regmap_init_mmio(dev, base, host->pdata->regmap_config); + if (IS_ERR(host->regmap)) + return PTR_ERR(host->regmap); + + host->clk = devm_clk_get_optional_enabled(dev, NULL); + if (IS_ERR(host->clk)) + return PTR_ERR(host->clk); + + if (host->clk) { + ret = devm_clk_rate_exclusive_get(dev, host->clk); + if (ret) + return ret; + + host->current_clk = clk_get_rate(host->clk); + } else { + /* For ACPI, the clock is accessed via the clock-frequency attribute. */ + device_property_read_u32(dev, "clock-frequency", &host->current_clk); + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_threaded_irq(dev, irq, loongson2_mmc_irq, + loongson2_mmc_irq_worker, + IRQF_ONESHOT, "loongson2-mmc", host); + if (ret) + return ret; + + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + if (ret) + return ret; + + return host->pdata->setting_dma(host, pdev); +} + +static int loongson2_mmc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct loongson2_mmc_host *host; + struct mmc_host *mmc; + int ret; + + mmc = devm_mmc_alloc_host(dev, sizeof(*host)); + if (!mmc) + return -ENOMEM; + + platform_set_drvdata(pdev, mmc); + + host = mmc_priv(mmc); + host->state = STATE_NONE; + spin_lock_init(&host->lock); + + host->pdata = device_get_match_data(dev); + if (!host->pdata) + return dev_err_probe(dev, -EINVAL, "Failed to get match data\n"); + + ret = loongson2_mmc_resource_request(pdev, host); + if (ret) + return dev_err_probe(dev, ret, "Failed to request resource\n"); + + mmc->ops = &loongson2_mmc_ops; + mmc->f_min = DIV_ROUND_UP(host->current_clk, 256); + mmc->f_max = host->current_clk; + mmc->max_blk_count = 4095; + mmc->max_blk_size = 4095; + mmc->max_req_size = mmc->max_blk_count * mmc->max_blk_size; + mmc->max_segs = 1; + mmc->max_seg_size = mmc->max_req_size; + + /* Process SDIO IRQs through the sdio_irq_work. */ + if (mmc->caps & MMC_CAP_SDIO_IRQ) + mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD; + + ret = mmc_regulator_get_supply(mmc); + if (ret || mmc->ocr_avail == 0) { + dev_warn(dev, "Can't get voltage, defaulting to 3.3V\n"); + mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; + } + + ret = mmc_of_parse(mmc); + if (ret) { + dev_err(dev, "Failed to parse device node\n"); + goto free_dma; + } + + ret = mmc_add_host(mmc); + if (ret) { + dev_err(dev, "Failed to add mmc host\n"); + goto free_dma; + } + + return 0; + +free_dma: + host->pdata->release_dma(host, dev); + return ret; +} + +static void loongson2_mmc_remove(struct platform_device *pdev) +{ + struct mmc_host *mmc = platform_get_drvdata(pdev); + struct loongson2_mmc_host *host = mmc_priv(mmc); + + mmc_remove_host(mmc); + host->pdata->release_dma(host, &pdev->dev); +} + +static const struct of_device_id loongson2_mmc_of_ids[] = { + { .compatible = "loongson,ls2k0500-mmc", .data = &ls2k0500_mmc_pdata }, + { .compatible = "loongson,ls2k1000-mmc", .data = &ls2k1000_mmc_pdata }, + { .compatible = "loongson,ls2k2000-mmc", .data = &ls2k2000_mmc_pdata }, + { }, +}; +MODULE_DEVICE_TABLE(of, loongson2_mmc_of_ids); + +static int loongson2_mmc_suspend(struct device *dev) +{ + struct mmc_host *mmc = dev_get_drvdata(dev); + struct loongson2_mmc_host *host = mmc_priv(mmc); + + clk_disable_unprepare(host->clk); + + return 0; +} + +static int loongson2_mmc_resume(struct device *dev) +{ + struct mmc_host *mmc = dev_get_drvdata(dev); + struct loongson2_mmc_host *host = mmc_priv(mmc); + + return clk_prepare_enable(host->clk); +} + +static DEFINE_SIMPLE_DEV_PM_OPS(loongson2_mmc_pm_ops, loongson2_mmc_suspend, loongson2_mmc_resume); + +static struct platform_driver loongson2_mmc_driver = { + .driver = { + .name = "loongson2-mmc", + .of_match_table = loongson2_mmc_of_ids, + .pm = pm_ptr(&loongson2_mmc_pm_ops), + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, + .probe = loongson2_mmc_probe, + .remove = loongson2_mmc_remove, +}; + +module_platform_driver(loongson2_mmc_driver); + +MODULE_DESCRIPTION("Loongson-2K SD/SDIO/eMMC Interface driver"); +MODULE_AUTHOR("Loongson Technology Corporation Limited"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/meson-mx-sdhc-mmc.c b/drivers/mmc/host/meson-mx-sdhc-mmc.c index b4e56ccffca2..fb49ea71289e 100644 --- a/drivers/mmc/host/meson-mx-sdhc-mmc.c +++ b/drivers/mmc/host/meson-mx-sdhc-mmc.c @@ -757,11 +757,6 @@ static void meson_mx_sdhc_init_hw(struct mmc_host *mmc) regmap_write(host->regmap, MESON_SDHC_ISTA, MESON_SDHC_ISTA_ALL_IRQS); } -static void meason_mx_mmc_free_host(void *data) -{ - mmc_free_host(data); -} - static int meson_mx_sdhc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -770,16 +765,10 @@ static int meson_mx_sdhc_probe(struct platform_device *pdev) void __iomem *base; int ret, irq; - mmc = mmc_alloc_host(sizeof(*host), dev); + mmc = devm_mmc_alloc_host(dev, sizeof(*host)); if (!mmc) return -ENOMEM; - ret = devm_add_action_or_reset(dev, meason_mx_mmc_free_host, mmc); - if (ret) { - dev_err(dev, "Failed to register mmc_free_host action\n"); - return ret; - } - host = mmc_priv(mmc); host->mmc = mmc; diff --git a/drivers/mmc/host/meson-mx-sdio.c b/drivers/mmc/host/meson-mx-sdio.c index e0ae5a0c9670..8a49c32fd3f9 100644 --- a/drivers/mmc/host/meson-mx-sdio.c +++ b/drivers/mmc/host/meson-mx-sdio.c @@ -467,7 +467,8 @@ static irqreturn_t meson_mx_mmc_irq_thread(int irq, void *irq_data) static void meson_mx_mmc_timeout(struct timer_list *t) { - struct meson_mx_mmc_host *host = from_timer(host, t, cmd_timeout); + struct meson_mx_mmc_host *host = timer_container_of(host, t, + cmd_timeout); unsigned long irqflags; u32 irqc; diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 47443fb5eb33..35b0ad273b4f 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -1185,7 +1185,7 @@ static int mmc_spi_probe(struct spi_device *spi) goto nomem; memset(ones, 0xff, MMC_SPI_BLOCKSIZE); - mmc = mmc_alloc_host(sizeof(*host), &spi->dev); + mmc = devm_mmc_alloc_host(&spi->dev, sizeof(*host)); if (!mmc) goto nomem; @@ -1305,7 +1305,6 @@ fail_glue_init: kfree(host->data); fail_nobuf1: mmc_spi_put_pdata(spi); - mmc_free_host(mmc); nomem: kfree(ones); return status; @@ -1328,7 +1327,6 @@ static void mmc_spi_remove(struct spi_device *spi) spi->max_speed_hz = mmc->f_max; mmc_spi_put_pdata(spi); - mmc_free_host(mmc); } static const struct spi_device_id mmc_spi_dev_ids[] = { diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index b790c3c3c8f9..8367283647a9 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -2082,7 +2082,6 @@ static void mmci_enable_sdio_irq(struct mmc_host *mmc, int enable) spin_unlock_irqrestore(&host->lock, flags); if (!enable) { - pm_runtime_mark_last_busy(mmc_dev(mmc)); pm_runtime_put_autosuspend(mmc_dev(mmc)); } } @@ -2223,7 +2222,7 @@ static int mmci_probe(struct amba_device *dev, return -ENOMEM; } - mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev); + mmc = devm_mmc_alloc_host(&dev->dev, sizeof(*host)); if (!mmc) return -ENOMEM; @@ -2234,7 +2233,7 @@ static int mmci_probe(struct amba_device *dev, ret = mmci_of_parse(np, mmc); if (ret) - goto host_free; + return ret; /* * Some variant (STM32) doesn't have opendrain bit, nevertheless @@ -2242,19 +2241,15 @@ static int mmci_probe(struct amba_device *dev, */ if (!variant->opendrain) { host->pinctrl = devm_pinctrl_get(&dev->dev); - if (IS_ERR(host->pinctrl)) { - dev_err(&dev->dev, "failed to get pinctrl"); - ret = PTR_ERR(host->pinctrl); - goto host_free; - } + if (IS_ERR(host->pinctrl)) + return dev_err_probe(&dev->dev, PTR_ERR(host->pinctrl), + "failed to get pinctrl\n"); host->pins_opendrain = pinctrl_lookup_state(host->pinctrl, MMCI_PINCTRL_STATE_OPENDRAIN); - if (IS_ERR(host->pins_opendrain)) { - dev_err(mmc_dev(mmc), "Can't select opendrain pins\n"); - ret = PTR_ERR(host->pins_opendrain); - goto host_free; - } + if (IS_ERR(host->pins_opendrain)) + return dev_err_probe(&dev->dev, PTR_ERR(host->pins_opendrain), + "Can't select opendrain pins\n"); } host->hw_designer = amba_manf(dev); @@ -2263,14 +2258,12 @@ static int mmci_probe(struct amba_device *dev, dev_dbg(mmc_dev(mmc), "revision = 0x%01x\n", host->hw_revision); host->clk = devm_clk_get(&dev->dev, NULL); - if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); - goto host_free; - } + if (IS_ERR(host->clk)) + return PTR_ERR(host->clk); ret = clk_prepare_enable(host->clk); if (ret) - goto host_free; + return ret; if (variant->qcom_fifo) host->get_rx_fifocnt = mmci_qcom_get_rx_fifocnt; @@ -2491,8 +2484,6 @@ static int mmci_probe(struct amba_device *dev, clk_disable: clk_disable_unprepare(host->clk); - host_free: - mmc_free_host(mmc); return ret; } @@ -2522,7 +2513,6 @@ static void mmci_remove(struct amba_device *dev) mmci_dma_release(host); clk_disable_unprepare(host->clk); - mmc_free_host(mmc); } } diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c index a12048e5de63..3dd8f232052f 100644 --- a/drivers/mmc/host/moxart-mmc.c +++ b/drivers/mmc/host/moxart-mmc.c @@ -558,41 +558,33 @@ static int moxart_probe(struct platform_device *pdev) int irq, ret; u32 i; - mmc = mmc_alloc_host(sizeof(struct moxart_host), dev); + mmc = devm_mmc_alloc_host(dev, sizeof(*host)); if (!mmc) { - dev_err(dev, "mmc_alloc_host failed\n"); - ret = -ENOMEM; - goto out_mmc; + dev_err(dev, "devm_mmc_alloc_host failed\n"); + return -ENOMEM; } ret = of_address_to_resource(node, 0, &res_mmc); - if (ret) { - dev_err(dev, "of_address_to_resource failed\n"); - goto out_mmc; - } + if (ret) + return dev_err_probe(dev, ret, + "of_address_to_resource failed\n"); irq = irq_of_parse_and_map(node, 0); - if (irq <= 0) { - dev_err(dev, "irq_of_parse_and_map failed\n"); - ret = -EINVAL; - goto out_mmc; - } + if (irq <= 0) + return dev_err_probe(dev, -EINVAL, + "irq_of_parse_and_map failed\n"); clk = devm_clk_get(dev, NULL); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - goto out_mmc; - } + if (IS_ERR(clk)) + return PTR_ERR(clk); reg_mmc = devm_ioremap_resource(dev, &res_mmc); - if (IS_ERR(reg_mmc)) { - ret = PTR_ERR(reg_mmc); - goto out_mmc; - } + if (IS_ERR(reg_mmc)) + return PTR_ERR(reg_mmc); ret = mmc_of_parse(mmc); if (ret) - goto out_mmc; + return ret; host = mmc_priv(mmc); host->mmc = mmc; @@ -686,9 +678,6 @@ out: dma_release_channel(host->dma_chan_tx); if (!IS_ERR_OR_NULL(host->dma_chan_rx)) dma_release_channel(host->dma_chan_rx); -out_mmc: - if (mmc) - mmc_free_host(mmc); return ret; } @@ -707,7 +696,6 @@ static void moxart_remove(struct platform_device *pdev) writel(0, host->base + REG_POWER_CONTROL); writel(readl(host->base + REG_CLOCK_CONTROL) | CLK_OFF, host->base + REG_CLOCK_CONTROL); - mmc_free_host(mmc); } static const struct of_device_id moxart_mmc_match[] = { diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 345ea91629e0..d7020e06dd55 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -5,6 +5,7 @@ */ #include <linux/module.h> +#include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/clk.h> #include <linux/delay.h> @@ -83,6 +84,7 @@ #define EMMC51_CFG0 0x204 #define EMMC50_CFG0 0x208 #define EMMC50_CFG1 0x20c +#define EMMC50_CFG2 0x21c #define EMMC50_CFG3 0x220 #define SDC_FIFO_CFG 0x228 #define CQHCI_SETTING 0x7fc @@ -233,7 +235,9 @@ /* MSDC_PATCH_BIT mask */ #define MSDC_PATCH_BIT_ODDSUPP BIT(1) /* RW */ +#define MSDC_PATCH_BIT_DIS_WRMON BIT(2) /* RW */ #define MSDC_PATCH_BIT_RD_DAT_SEL BIT(3) /* RW */ +#define MSDC_PATCH_BIT_DESCUP_SEL BIT(6) /* RW */ #define MSDC_INT_DAT_LATCH_CK_SEL GENMASK(9, 7) #define MSDC_CKGEN_MSDC_DLY_SEL GENMASK(14, 10) #define MSDC_PATCH_BIT_IODSSEL BIT(16) /* RW */ @@ -246,10 +250,22 @@ #define MSDC_PATCH_BIT_SPCPUSH BIT(29) /* RW */ #define MSDC_PATCH_BIT_DECRCTMO BIT(30) /* RW */ -#define MSDC_PATCH_BIT1_CMDTA GENMASK(5, 3) /* RW */ +/* MSDC_PATCH_BIT1 mask */ +#define MSDC_PB1_WRDAT_CRC_TACNTR GENMASK(2, 0) /* RW */ +#define MSDC_PATCH_BIT1_CMDTA GENMASK(5, 3) /* RW */ #define MSDC_PB1_BUSY_CHECK_SEL BIT(7) /* RW */ #define MSDC_PATCH_BIT1_STOP_DLY GENMASK(11, 8) /* RW */ - +#define MSDC_PB1_DDR_CMD_FIX_SEL BIT(14) /* RW */ +#define MSDC_PB1_SINGLE_BURST BIT(16) /* RW */ +#define MSDC_PB1_RSVD20 GENMASK(18, 17) /* RW */ +#define MSDC_PB1_AUTO_SYNCST_CLR BIT(19) /* RW */ +#define MSDC_PB1_MARK_POP_WATER BIT(20) /* RW */ +#define MSDC_PB1_LP_DCM_EN BIT(21) /* RW */ +#define MSDC_PB1_RSVD3 BIT(22) /* RW */ +#define MSDC_PB1_AHB_GDMA_HCLK BIT(23) /* RW */ +#define MSDC_PB1_MSDC_CLK_ENFEAT GENMASK(31, 24) /* RW */ + +/* MSDC_PATCH_BIT2 mask */ #define MSDC_PATCH_BIT2_CFGRESP BIT(15) /* RW */ #define MSDC_PATCH_BIT2_CFGCRCSTS BIT(28) /* RW */ #define MSDC_PB2_SUPPORT_64G BIT(1) /* RW */ @@ -291,7 +307,10 @@ /* EMMC50_CFG1 mask */ #define EMMC50_CFG1_DS_CFG BIT(28) /* RW */ -#define EMMC50_CFG3_OUTS_WR GENMASK(4, 0) /* RW */ +/* EMMC50_CFG2 mask */ +#define EMMC50_CFG2_AXI_SET_LEN GENMASK(27, 24) /* RW */ + +#define EMMC50_CFG3_OUTS_WR GENMASK(4, 0) /* RW */ #define SDC_FIFO_CFG_WRVALIDSEL BIT(24) /* RW */ #define SDC_FIFO_CFG_RDVALIDSEL BIT(25) /* RW */ @@ -827,12 +846,18 @@ static inline void msdc_dma_setup(struct msdc_host *host, struct msdc_dma *dma, static void msdc_prepare_data(struct msdc_host *host, struct mmc_data *data) { if (!(data->host_cookie & MSDC_PREPARE_FLAG)) { - data->host_cookie |= MSDC_PREPARE_FLAG; data->sg_count = dma_map_sg(host->dev, data->sg, data->sg_len, mmc_get_dma_dir(data)); + if (data->sg_count) + data->host_cookie |= MSDC_PREPARE_FLAG; } } +static bool msdc_data_prepared(struct mmc_data *data) +{ + return data->host_cookie & MSDC_PREPARE_FLAG; +} + static void msdc_unprepare_data(struct msdc_host *host, struct mmc_data *data) { if (data->host_cookie & MSDC_ASYNC_FLAG) @@ -927,15 +952,15 @@ static int msdc_ungate_clock(struct msdc_host *host) static void msdc_new_tx_setting(struct msdc_host *host) { + u32 val; + if (!host->top_base) return; - sdr_set_bits(host->top_base + LOOP_TEST_CONTROL, - TEST_LOOP_DSCLK_MUX_SEL); - sdr_set_bits(host->top_base + LOOP_TEST_CONTROL, - TEST_LOOP_LATCH_MUX_SEL); - sdr_clr_bits(host->top_base + LOOP_TEST_CONTROL, - TEST_HS400_CMD_LOOP_MUX_SEL); + val = readl(host->top_base + LOOP_TEST_CONTROL); + val |= TEST_LOOP_DSCLK_MUX_SEL; + val |= TEST_LOOP_LATCH_MUX_SEL; + val &= ~TEST_HS400_CMD_LOOP_MUX_SEL; switch (host->timing) { case MMC_TIMING_LEGACY: @@ -945,19 +970,18 @@ static void msdc_new_tx_setting(struct msdc_host *host) case MMC_TIMING_UHS_SDR25: case MMC_TIMING_UHS_DDR50: case MMC_TIMING_MMC_DDR52: - sdr_clr_bits(host->top_base + LOOP_TEST_CONTROL, - LOOP_EN_SEL_CLK); + val &= ~LOOP_EN_SEL_CLK; break; case MMC_TIMING_UHS_SDR50: case MMC_TIMING_UHS_SDR104: case MMC_TIMING_MMC_HS200: case MMC_TIMING_MMC_HS400: - sdr_set_bits(host->top_base + LOOP_TEST_CONTROL, - LOOP_EN_SEL_CLK); + val |= LOOP_EN_SEL_CLK; break; default: break; } + writel(val, host->top_base + LOOP_TEST_CONTROL); } static void msdc_set_mclk(struct msdc_host *host, unsigned char timing, u32 hz) @@ -1465,8 +1489,19 @@ static void msdc_ops_request(struct mmc_host *mmc, struct mmc_request *mrq) WARN_ON(!host->hsq_en && host->mrq); host->mrq = mrq; - if (mrq->data) + if (mrq->data) { msdc_prepare_data(host, mrq->data); + if (!msdc_data_prepared(mrq->data)) { + host->mrq = NULL; + /* + * Failed to prepare DMA area, fail fast before + * starting any commands. + */ + mrq->cmd->error = -ENOSPC; + mmc_request_done(mmc_from_priv(host), mrq); + return; + } + } /* if SBC is required, we have HW option and SW option. * if HW option is enabled, and SBC does not have "special" flags, @@ -1816,7 +1851,7 @@ static irqreturn_t msdc_irq(int irq, void *dev_id) static void msdc_init_hw(struct msdc_host *host) { - u32 val; + u32 val, pb1_val, pb2_val; u32 tune_reg = host->dev_comp->pad_tune_reg; struct mmc_host *mmc = mmc_from_priv(host); @@ -1869,71 +1904,115 @@ static void msdc_init_hw(struct msdc_host *host) } writel(0, host->base + MSDC_IOCON); sdr_set_field(host->base + MSDC_IOCON, MSDC_IOCON_DDLSEL, 0); - writel(0x403c0046, host->base + MSDC_PATCH_BIT); - sdr_set_field(host->base + MSDC_PATCH_BIT, MSDC_CKGEN_MSDC_DLY_SEL, 1); - writel(0xffff4089, host->base + MSDC_PATCH_BIT1); - sdr_set_bits(host->base + EMMC50_CFG0, EMMC50_CFG_CFCSTS_SEL); + + /* + * Patch bit 0 and 1 are completely rewritten, but for patch bit 2 + * defaults are retained and, if necessary, only some bits are fixed + * up: read the PB2 register here for later usage in this function. + */ + pb2_val = readl(host->base + MSDC_PATCH_BIT2); + + /* Enable odd number support for 8-bit data bus */ + val = MSDC_PATCH_BIT_ODDSUPP; + + /* Disable SD command register write monitor */ + val |= MSDC_PATCH_BIT_DIS_WRMON; + + /* Issue transfer done interrupt after GPD update */ + val |= MSDC_PATCH_BIT_DESCUP_SEL; + + /* Extend R1B busy detection delay (in clock cycles) */ + val |= FIELD_PREP(MSDC_PATCH_BIT_BUSYDLY, 15); + + /* Enable CRC phase timeout during data write operation */ + val |= MSDC_PATCH_BIT_DECRCTMO; + + /* Set CKGEN delay to one stage */ + val |= FIELD_PREP(MSDC_CKGEN_MSDC_DLY_SEL, 1); + + /* First MSDC_PATCH_BIT setup is done: pull the trigger! */ + writel(val, host->base + MSDC_PATCH_BIT); + + /* Set wr data, crc status, cmd response turnaround period for UHS104 */ + pb1_val = FIELD_PREP(MSDC_PB1_WRDAT_CRC_TACNTR, 1); + pb1_val |= FIELD_PREP(MSDC_PATCH_BIT1_CMDTA, 1); + pb1_val |= MSDC_PB1_DDR_CMD_FIX_SEL; + + /* Support 'single' burst type only when AXI_LEN is 0 */ + sdr_get_field(host->base + EMMC50_CFG2, EMMC50_CFG2_AXI_SET_LEN, &val); + if (!val) + pb1_val |= MSDC_PB1_SINGLE_BURST; + + /* Set auto sync state clear, block gap stop clk */ + pb1_val |= MSDC_PB1_RSVD20 | MSDC_PB1_AUTO_SYNCST_CLR | MSDC_PB1_MARK_POP_WATER; + + /* Set low power DCM, use HCLK for GDMA, use MSDC CLK for everything else */ + pb1_val |= MSDC_PB1_LP_DCM_EN | MSDC_PB1_RSVD3 | + MSDC_PB1_AHB_GDMA_HCLK | MSDC_PB1_MSDC_CLK_ENFEAT; + + /* If needed, enable R1b command busy check at controller init time */ + if (!host->dev_comp->busy_check) + pb1_val |= MSDC_PB1_BUSY_CHECK_SEL; if (host->dev_comp->stop_clk_fix) { if (host->dev_comp->stop_dly_sel) - sdr_set_field(host->base + MSDC_PATCH_BIT1, - MSDC_PATCH_BIT1_STOP_DLY, - host->dev_comp->stop_dly_sel); + pb1_val |= FIELD_PREP(MSDC_PATCH_BIT1_STOP_DLY, + host->dev_comp->stop_dly_sel); - if (host->dev_comp->pop_en_cnt) - sdr_set_field(host->base + MSDC_PATCH_BIT2, - MSDC_PB2_POP_EN_CNT, - host->dev_comp->pop_en_cnt); + if (host->dev_comp->pop_en_cnt) { + pb2_val &= ~MSDC_PB2_POP_EN_CNT; + pb2_val |= FIELD_PREP(MSDC_PB2_POP_EN_CNT, + host->dev_comp->pop_en_cnt); + } - sdr_clr_bits(host->base + SDC_FIFO_CFG, - SDC_FIFO_CFG_WRVALIDSEL); - sdr_clr_bits(host->base + SDC_FIFO_CFG, - SDC_FIFO_CFG_RDVALIDSEL); + sdr_clr_bits(host->base + SDC_FIFO_CFG, SDC_FIFO_CFG_WRVALIDSEL); + sdr_clr_bits(host->base + SDC_FIFO_CFG, SDC_FIFO_CFG_RDVALIDSEL); } - if (host->dev_comp->busy_check) - sdr_clr_bits(host->base + MSDC_PATCH_BIT1, BIT(7)); - if (host->dev_comp->async_fifo) { - sdr_set_field(host->base + MSDC_PATCH_BIT2, - MSDC_PB2_RESPWAIT, 3); - if (host->dev_comp->enhance_rx) { - if (host->top_base) - sdr_set_bits(host->top_base + EMMC_TOP_CONTROL, - SDC_RX_ENH_EN); - else - sdr_set_bits(host->base + SDC_ADV_CFG0, - SDC_RX_ENHANCE_EN); + /* Set CMD response timeout multiplier to 65 + (16 * 3) cycles */ + pb2_val &= ~MSDC_PB2_RESPWAIT; + pb2_val |= FIELD_PREP(MSDC_PB2_RESPWAIT, 3); + + /* eMMC4.5: Select async FIFO path for CMD resp and CRC status */ + pb2_val &= ~MSDC_PATCH_BIT2_CFGRESP; + pb2_val |= MSDC_PATCH_BIT2_CFGCRCSTS; + + if (!host->dev_comp->enhance_rx) { + /* eMMC4.5: Delay 2T for CMD resp and CRC status EN signals */ + pb2_val &= ~(MSDC_PB2_RESPSTSENSEL | MSDC_PB2_CRCSTSENSEL); + pb2_val |= FIELD_PREP(MSDC_PB2_RESPSTSENSEL, 2); + pb2_val |= FIELD_PREP(MSDC_PB2_CRCSTSENSEL, 2); + } else if (host->top_base) { + sdr_set_bits(host->top_base + EMMC_TOP_CONTROL, SDC_RX_ENH_EN); } else { - sdr_set_field(host->base + MSDC_PATCH_BIT2, - MSDC_PB2_RESPSTSENSEL, 2); - sdr_set_field(host->base + MSDC_PATCH_BIT2, - MSDC_PB2_CRCSTSENSEL, 2); + sdr_set_bits(host->base + SDC_ADV_CFG0, SDC_RX_ENHANCE_EN); } - /* use async fifo, then no need tune internal delay */ - sdr_clr_bits(host->base + MSDC_PATCH_BIT2, - MSDC_PATCH_BIT2_CFGRESP); - sdr_set_bits(host->base + MSDC_PATCH_BIT2, - MSDC_PATCH_BIT2_CFGCRCSTS); } if (host->dev_comp->support_64g) - sdr_set_bits(host->base + MSDC_PATCH_BIT2, - MSDC_PB2_SUPPORT_64G); + pb2_val |= MSDC_PB2_SUPPORT_64G; + + /* Patch Bit 1/2 setup is done: pull the trigger! */ + writel(pb1_val, host->base + MSDC_PATCH_BIT1); + writel(pb2_val, host->base + MSDC_PATCH_BIT2); + sdr_set_bits(host->base + EMMC50_CFG0, EMMC50_CFG_CFCSTS_SEL); + if (host->dev_comp->data_tune) { if (host->top_base) { - sdr_set_bits(host->top_base + EMMC_TOP_CONTROL, - PAD_DAT_RD_RXDLY_SEL); - sdr_clr_bits(host->top_base + EMMC_TOP_CONTROL, - DATA_K_VALUE_SEL); - sdr_set_bits(host->top_base + EMMC_TOP_CMD, - PAD_CMD_RD_RXDLY_SEL); + u32 top_ctl_val = readl(host->top_base + EMMC_TOP_CONTROL); + u32 top_cmd_val = readl(host->top_base + EMMC_TOP_CMD); + + top_cmd_val |= PAD_CMD_RD_RXDLY_SEL; + top_ctl_val |= PAD_DAT_RD_RXDLY_SEL; + top_ctl_val &= ~DATA_K_VALUE_SEL; if (host->tuning_step > PAD_DELAY_HALF) { - sdr_set_bits(host->top_base + EMMC_TOP_CONTROL, - PAD_DAT_RD_RXDLY2_SEL); - sdr_set_bits(host->top_base + EMMC_TOP_CMD, - PAD_CMD_RD_RXDLY2_SEL); + top_cmd_val |= PAD_CMD_RD_RXDLY2_SEL; + top_ctl_val |= PAD_DAT_RD_RXDLY2_SEL; } + + writel(top_ctl_val, host->top_base + EMMC_TOP_CONTROL); + writel(top_cmd_val, host->top_base + EMMC_TOP_CMD); } else { sdr_set_bits(host->base + tune_reg, MSDC_PAD_TUNE_RD_SEL | @@ -2143,15 +2222,17 @@ static inline void msdc_set_cmd_delay(struct msdc_host *host, u32 value) u32 tune_reg = host->dev_comp->pad_tune_reg; if (host->top_base) { + u32 regval = readl(host->top_base + EMMC_TOP_CMD); + + regval &= ~(PAD_CMD_RXDLY | PAD_CMD_RXDLY2); + if (value < PAD_DELAY_HALF) { - sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY, value); - sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY2, 0); + regval |= FIELD_PREP(PAD_CMD_RXDLY, value); } else { - sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY, - PAD_DELAY_HALF - 1); - sdr_set_field(host->top_base + EMMC_TOP_CMD, PAD_CMD_RXDLY2, - value - PAD_DELAY_HALF); + regval |= FIELD_PREP(PAD_CMD_RXDLY, PAD_DELAY_HALF - 1); + regval |= FIELD_PREP(PAD_CMD_RXDLY2, value - PAD_DELAY_HALF); } + writel(regval, host->top_base + EMMC_TOP_CMD); } else { if (value < PAD_DELAY_HALF) { sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_CMDRDLY, value); @@ -2171,17 +2252,18 @@ static inline void msdc_set_data_delay(struct msdc_host *host, u32 value) u32 tune_reg = host->dev_comp->pad_tune_reg; if (host->top_base) { + u32 regval = readl(host->top_base + EMMC_TOP_CONTROL); + + regval &= ~(PAD_DAT_RD_RXDLY | PAD_DAT_RD_RXDLY2); + if (value < PAD_DELAY_HALF) { - sdr_set_field(host->top_base + EMMC_TOP_CONTROL, - PAD_DAT_RD_RXDLY, value); - sdr_set_field(host->top_base + EMMC_TOP_CONTROL, - PAD_DAT_RD_RXDLY2, 0); + regval |= FIELD_PREP(PAD_DAT_RD_RXDLY, value); + regval |= FIELD_PREP(PAD_DAT_RD_RXDLY2, value); } else { - sdr_set_field(host->top_base + EMMC_TOP_CONTROL, - PAD_DAT_RD_RXDLY, PAD_DELAY_HALF - 1); - sdr_set_field(host->top_base + EMMC_TOP_CONTROL, - PAD_DAT_RD_RXDLY2, value - PAD_DELAY_HALF); + regval |= FIELD_PREP(PAD_DAT_RD_RXDLY, PAD_DELAY_HALF - 1); + regval |= FIELD_PREP(PAD_DAT_RD_RXDLY2, value - PAD_DELAY_HALF); } + writel(regval, host->top_base + EMMC_TOP_CONTROL); } else { if (value < PAD_DELAY_HALF) { sdr_set_field(host->base + tune_reg, MSDC_PAD_TUNE_DATRRDLY, value); @@ -2977,7 +3059,7 @@ static int msdc_drv_probe(struct platform_device *pdev) mmc->f_min = DIV_ROUND_UP(host->src_clk_freq, 4 * 4095); if (!(mmc->caps & MMC_CAP_NONREMOVABLE) && - !mmc_can_gpio_cd(mmc) && + !mmc_host_can_gpio_cd(mmc) && host->dev_comp->use_internal_cd) { /* * Is removable but no GPIO declared, so diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index 912ffacbad88..a9e6277789ba 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -509,7 +509,7 @@ static irqreturn_t mvsd_irq(int irq, void *dev) static void mvsd_timeout_timer(struct timer_list *t) { - struct mvsd_host *host = from_timer(host, t, timer); + struct mvsd_host *host = timer_container_of(host, t, timer); void __iomem *iobase = host->base; struct mmc_request *mrq; unsigned long flags; @@ -706,11 +706,9 @@ static int mvsd_probe(struct platform_device *pdev) if (irq < 0) return irq; - mmc = mmc_alloc_host(sizeof(struct mvsd_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto out; - } + mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(*host)); + if (!mmc) + return -ENOMEM; host = mmc_priv(mmc); host->mmc = mmc; @@ -724,11 +722,9 @@ static int mvsd_probe(struct platform_device *pdev) * fixed rate clock). */ host->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(host->clk)) { - dev_err(&pdev->dev, "no clock associated\n"); - ret = -EINVAL; - goto out; - } + if (IS_ERR(host->clk)) + return dev_err_probe(&pdev->dev, -EINVAL, "no clock associated\n"); + clk_prepare_enable(host->clk); mmc->ops = &mvsd_ops; @@ -787,12 +783,7 @@ static int mvsd_probe(struct platform_device *pdev) return 0; out: - if (mmc) { - if (!IS_ERR(host->clk)) - clk_disable_unprepare(host->clk); - mmc_free_host(mmc); - } - + clk_disable_unprepare(host->clk); return ret; } @@ -808,7 +799,6 @@ static void mvsd_remove(struct platform_device *pdev) if (!IS_ERR(host->clk)) clk_disable_unprepare(host->clk); - mmc_free_host(mmc); } static const struct of_device_id mvsdio_dt_ids[] = { diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 95d8d40a06a8..c405cfb8b269 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -955,7 +955,7 @@ static bool filter(struct dma_chan *chan, void *param) static void mxcmci_watchdog(struct timer_list *t) { - struct mxcmci_host *host = from_timer(host, t, watchdog); + struct mxcmci_host *host = timer_container_of(host, t, watchdog); struct mmc_request *req = host->req; unsigned int stat = mxcmci_readl(host, MMC_REG_STATUS); @@ -1005,23 +1005,21 @@ static int mxcmci_probe(struct platform_device *pdev) if (irq < 0) return irq; - mmc = mmc_alloc_host(sizeof(*host), &pdev->dev); + mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(*host)); if (!mmc) return -ENOMEM; host = mmc_priv(mmc); host->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(host->base)) { - ret = PTR_ERR(host->base); - goto out_free; - } + if (IS_ERR(host->base)) + return PTR_ERR(host->base); host->phys_base = res->start; ret = mmc_of_parse(mmc); if (ret) - goto out_free; + return ret; mmc->ops = &mxcmci_ops; /* For devicetree parsing, the bus width is read from devicetree */ @@ -1054,7 +1052,7 @@ static int mxcmci_probe(struct platform_device *pdev) ret = mmc_regulator_get_supply(mmc); if (ret) - goto out_free; + return ret; if (!mmc->ocr_avail) { if (pdata && pdata->ocr_avail) @@ -1070,20 +1068,16 @@ static int mxcmci_probe(struct platform_device *pdev) host->default_irq_mask = 0; host->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); - if (IS_ERR(host->clk_ipg)) { - ret = PTR_ERR(host->clk_ipg); - goto out_free; - } + if (IS_ERR(host->clk_ipg)) + return PTR_ERR(host->clk_ipg); host->clk_per = devm_clk_get(&pdev->dev, "per"); - if (IS_ERR(host->clk_per)) { - ret = PTR_ERR(host->clk_per); - goto out_free; - } + if (IS_ERR(host->clk_per)) + return PTR_ERR(host->clk_per); ret = clk_prepare_enable(host->clk_per); if (ret) - goto out_free; + return ret; ret = clk_prepare_enable(host->clk_ipg); if (ret) @@ -1169,9 +1163,6 @@ out_clk_put: out_clk_per_put: clk_disable_unprepare(host->clk_per); -out_free: - mmc_free_host(mmc); - return ret; } @@ -1190,8 +1181,6 @@ static void mxcmci_remove(struct platform_device *pdev) clk_disable_unprepare(host->clk_per); clk_disable_unprepare(host->clk_ipg); - - mmc_free_host(mmc); } static int mxcmci_suspend(struct device *dev) diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index 80e6f48c83aa..a6e44e406106 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -569,7 +569,7 @@ static int mxs_mmc_probe(struct platform_device *pdev) if (irq_err < 0) return irq_err; - mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev); + mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(*host)); if (!mmc) return -ENOMEM; @@ -577,10 +577,8 @@ static int mxs_mmc_probe(struct platform_device *pdev) ssp = &host->ssp; ssp->dev = &pdev->dev; ssp->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(ssp->base)) { - ret = PTR_ERR(ssp->base); - goto out_mmc_free; - } + if (IS_ERR(ssp->base)) + return PTR_ERR(ssp->base); ssp->devid = (enum mxs_ssp_id)of_device_get_match_data(&pdev->dev); @@ -590,26 +588,23 @@ static int mxs_mmc_probe(struct platform_device *pdev) reg_vmmc = devm_regulator_get(&pdev->dev, "vmmc"); if (!IS_ERR(reg_vmmc)) { ret = regulator_enable(reg_vmmc); - if (ret) { - dev_err(&pdev->dev, - "Failed to enable vmmc regulator: %d\n", ret); - goto out_mmc_free; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to enable vmmc regulator\n"); ret = devm_add_action_or_reset(&pdev->dev, mxs_mmc_regulator_disable, reg_vmmc); if (ret) - goto out_mmc_free; + return ret; } ssp->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(ssp->clk)) { - ret = PTR_ERR(ssp->clk); - goto out_mmc_free; - } + if (IS_ERR(ssp->clk)) + return PTR_ERR(ssp->clk); + ret = clk_prepare_enable(ssp->clk); if (ret) - goto out_mmc_free; + return ret; ret = mxs_mmc_reset(host); if (ret) { @@ -668,8 +663,6 @@ out_free_dma: dma_release_channel(ssp->dmach); out_clk_disable: clk_disable_unprepare(ssp->clk); -out_mmc_free: - mmc_free_host(mmc); return ret; } @@ -685,8 +678,6 @@ static void mxs_mmc_remove(struct platform_device *pdev) dma_release_channel(ssp->dmach); clk_disable_unprepare(ssp->clk); - - mmc_free_host(mmc); } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index c50617d03709..52ac3f128a1c 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -639,7 +639,8 @@ static void mmc_omap_abort_command(struct work_struct *work) static void mmc_omap_cmd_timer(struct timer_list *t) { - struct mmc_omap_host *host = from_timer(host, t, cmd_abort_timer); + struct mmc_omap_host *host = timer_container_of(host, t, + cmd_abort_timer); unsigned long flags; spin_lock_irqsave(&host->slot_lock, flags); @@ -655,7 +656,7 @@ mmc_omap_cmd_timer(struct timer_list *t) static void mmc_omap_clk_timer(struct timer_list *t) { - struct mmc_omap_host *host = from_timer(host, t, clk_timer); + struct mmc_omap_host *host = timer_container_of(host, t, clk_timer); mmc_omap_fclk_enable(host, 0); } @@ -879,7 +880,7 @@ void omap_mmc_notify_cover_event(struct device *dev, int num, int is_closed) static void mmc_omap_cover_timer(struct timer_list *t) { - struct mmc_omap_slot *slot = from_timer(slot, t, cover_timer); + struct mmc_omap_slot *slot = timer_container_of(slot, t, cover_timer); queue_work(system_bh_wq, &slot->cover_bh_work); } @@ -1258,7 +1259,7 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id) struct mmc_host *mmc; int r; - mmc = mmc_alloc_host(sizeof(struct mmc_omap_slot), host->dev); + mmc = devm_mmc_alloc_host(host->dev, sizeof(*slot)); if (mmc == NULL) return -ENOMEM; @@ -1272,25 +1273,21 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id) /* Check for some optional GPIO controls */ slot->vsd = devm_gpiod_get_index_optional(host->dev, "vsd", id, GPIOD_OUT_LOW); - if (IS_ERR(slot->vsd)) { - r = dev_err_probe(host->dev, PTR_ERR(slot->vsd), + if (IS_ERR(slot->vsd)) + return dev_err_probe(host->dev, PTR_ERR(slot->vsd), "error looking up VSD GPIO\n"); - goto err_free_host; - } + slot->vio = devm_gpiod_get_index_optional(host->dev, "vio", id, GPIOD_OUT_LOW); - if (IS_ERR(slot->vio)) { - r = dev_err_probe(host->dev, PTR_ERR(slot->vio), + if (IS_ERR(slot->vio)) + return dev_err_probe(host->dev, PTR_ERR(slot->vio), "error looking up VIO GPIO\n"); - goto err_free_host; - } + slot->cover = devm_gpiod_get_index_optional(host->dev, "cover", id, GPIOD_IN); - if (IS_ERR(slot->cover)) { - r = dev_err_probe(host->dev, PTR_ERR(slot->cover), + if (IS_ERR(slot->cover)) + return dev_err_probe(host->dev, PTR_ERR(slot->cover), "error looking up cover switch GPIO\n"); - goto err_free_host; - } host->slots[id] = slot; @@ -1350,8 +1347,6 @@ err_remove_slot_name: device_remove_file(&mmc->class_dev, &dev_attr_slot_name); err_remove_host: mmc_remove_host(mmc); -err_free_host: - mmc_free_host(mmc); return r; } @@ -1369,7 +1364,6 @@ static void mmc_omap_remove_slot(struct mmc_omap_slot *slot) flush_workqueue(slot->host->mmc_omap_wq); mmc_remove_host(mmc); - mmc_free_host(mmc); } static int mmc_omap_probe(struct platform_device *pdev) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 59e36e0ebbbf..adc0d0b6ae37 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1663,7 +1663,6 @@ static int mmc_regs_show(struct seq_file *s, void *data) seq_printf(s, "CAPA:\t\t0x%08x\n", OMAP_HSMMC_READ(host->base, CAPA)); - pm_runtime_mark_last_busy(host->dev); pm_runtime_put_autosuspend(host->dev); return 0; @@ -1798,15 +1797,13 @@ static int omap_hsmmc_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); - mmc = mmc_alloc_host(sizeof(struct omap_hsmmc_host), &pdev->dev); - if (!mmc) { - ret = -ENOMEM; - goto err; - } + mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(*host)); + if (!mmc) + return -ENOMEM; ret = mmc_of_parse(mmc); if (ret) - goto err1; + return ret; host = mmc_priv(mmc); host->mmc = mmc; @@ -1842,7 +1839,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) if (IS_ERR(host->fclk)) { ret = PTR_ERR(host->fclk); host->fclk = NULL; - goto err1; + return ret; } if (host->pdata->controller_flags & OMAP_HSMMC_BROKEN_MULTIBLOCK_READ) { @@ -1956,7 +1953,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev) } omap_hsmmc_debugfs(mmc); - pm_runtime_mark_last_busy(host->dev); pm_runtime_put_autosuspend(host->dev); return 0; @@ -1973,9 +1969,6 @@ err_irq: pm_runtime_put_sync(host->dev); pm_runtime_disable(host->dev); clk_disable_unprepare(host->dbclk); -err1: - mmc_free_host(mmc); -err: return ret; } @@ -1995,8 +1988,6 @@ static void omap_hsmmc_remove(struct platform_device *pdev) pm_runtime_disable(host->dev); device_init_wakeup(&pdev->dev, false); clk_disable_unprepare(host->dbclk); - - mmc_free_host(host->mmc); } #ifdef CONFIG_PM_SLEEP @@ -2038,7 +2029,6 @@ static int omap_hsmmc_resume(struct device *dev) if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) omap_hsmmc_conf_bus_power(host); - pm_runtime_mark_last_busy(host->dev); pm_runtime_put_autosuspend(host->dev); return 0; } diff --git a/drivers/mmc/host/owl-mmc.c b/drivers/mmc/host/owl-mmc.c index 797ef48d9204..dc585726b66e 100644 --- a/drivers/mmc/host/owl-mmc.c +++ b/drivers/mmc/host/owl-mmc.c @@ -567,7 +567,7 @@ static int owl_mmc_probe(struct platform_device *pdev) struct resource *res; int ret; - mmc = mmc_alloc_host(sizeof(struct owl_mmc_host), &pdev->dev); + mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(*owl_host)); if (!mmc) { dev_err(&pdev->dev, "mmc alloc host failed\n"); return -ENOMEM; @@ -580,24 +580,18 @@ static int owl_mmc_probe(struct platform_device *pdev) spin_lock_init(&owl_host->lock); owl_host->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(owl_host->base)) { - ret = PTR_ERR(owl_host->base); - goto err_free_host; - } + if (IS_ERR(owl_host->base)) + return PTR_ERR(owl_host->base); owl_host->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(owl_host->clk)) { - dev_err(&pdev->dev, "No clock defined\n"); - ret = PTR_ERR(owl_host->clk); - goto err_free_host; - } + if (IS_ERR(owl_host->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(owl_host->clk), + "No clock defined\n"); owl_host->reset = devm_reset_control_get_exclusive(&pdev->dev, NULL); - if (IS_ERR(owl_host->reset)) { - dev_err(&pdev->dev, "Could not get reset control\n"); - ret = PTR_ERR(owl_host->reset); - goto err_free_host; - } + if (IS_ERR(owl_host->reset)) + return dev_err_probe(&pdev->dev, PTR_ERR(owl_host->reset), + "Could not get reset control\n"); mmc->ops = &owl_mmc_ops; mmc->max_blk_count = 512; @@ -616,16 +610,14 @@ static int owl_mmc_probe(struct platform_device *pdev) ret = mmc_of_parse(mmc); if (ret) - goto err_free_host; + return ret; pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; owl_host->dma = dma_request_chan(&pdev->dev, "mmc"); - if (IS_ERR(owl_host->dma)) { - dev_err(owl_host->dev, "Failed to get external DMA channel.\n"); - ret = PTR_ERR(owl_host->dma); - goto err_free_host; - } + if (IS_ERR(owl_host->dma)) + return dev_err_probe(&pdev->dev, PTR_ERR(owl_host->dma), + "Failed to get external DMA channel.\n"); dev_info(&pdev->dev, "Using %s for DMA transfers\n", dma_chan_name(owl_host->dma)); @@ -662,8 +654,6 @@ static int owl_mmc_probe(struct platform_device *pdev) err_release_channel: dma_release_channel(owl_host->dma); -err_free_host: - mmc_free_host(mmc); return ret; } @@ -676,7 +666,6 @@ static void owl_mmc_remove(struct platform_device *pdev) mmc_remove_host(mmc); disable_irq(owl_host->irq); dma_release_channel(owl_host->dma); - mmc_free_host(mmc); } static const struct of_device_id owl_mmc_of_match[] = { diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 2d0ad006913d..26d03352af63 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -615,11 +615,9 @@ static int pxamci_probe(struct platform_device *pdev) if (irq < 0) return irq; - mmc = mmc_alloc_host(sizeof(struct pxamci_host), dev); - if (!mmc) { - ret = -ENOMEM; - goto out; - } + mmc = devm_mmc_alloc_host(dev, sizeof(*host)); + if (!mmc) + return -ENOMEM; mmc->ops = &pxamci_ops; @@ -646,7 +644,7 @@ static int pxamci_probe(struct platform_device *pdev) ret = pxamci_of_init(pdev, mmc); if (ret) - goto out; + return ret; host = mmc_priv(mmc); host->mmc = mmc; @@ -655,9 +653,8 @@ static int pxamci_probe(struct platform_device *pdev) host->clk = devm_clk_get(dev, NULL); if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); host->clk = NULL; - goto out; + return PTR_ERR(host->clk); } host->clkrate = clk_get_rate(host->clk); @@ -670,7 +667,7 @@ static int pxamci_probe(struct platform_device *pdev) ret = pxamci_init_ocr(host); if (ret < 0) - goto out; + return ret; mmc->caps = 0; host->cmdat = 0; @@ -686,10 +683,8 @@ static int pxamci_probe(struct platform_device *pdev) host->imask = MMC_I_MASK_ALL; host->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r); - if (IS_ERR(host->base)) { - ret = PTR_ERR(host->base); - goto out; - } + if (IS_ERR(host->base)) + return PTR_ERR(host->base); host->res = r; /* @@ -704,16 +699,15 @@ static int pxamci_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, pxamci_irq, 0, DRIVER_NAME, host); if (ret) - goto out; + return ret; platform_set_drvdata(pdev, mmc); host->dma_chan_rx = dma_request_chan(dev, "rx"); if (IS_ERR(host->dma_chan_rx)) { - dev_err(dev, "unable to request rx dma channel\n"); - ret = PTR_ERR(host->dma_chan_rx); host->dma_chan_rx = NULL; - goto out; + return dev_err_probe(dev, PTR_ERR(host->dma_chan_rx), + "unable to request rx dma channel\n"); } host->dma_chan_tx = dma_request_chan(dev, "tx"); @@ -771,14 +765,10 @@ static int pxamci_probe(struct platform_device *pdev) return 0; out: - if (host) { - if (host->dma_chan_rx) - dma_release_channel(host->dma_chan_rx); - if (host->dma_chan_tx) - dma_release_channel(host->dma_chan_tx); - } - if (mmc) - mmc_free_host(mmc); + if (host->dma_chan_rx) + dma_release_channel(host->dma_chan_rx); + if (host->dma_chan_tx) + dma_release_channel(host->dma_chan_tx); return ret; } @@ -803,8 +793,6 @@ static void pxamci_remove(struct platform_device *pdev) dmaengine_terminate_all(host->dma_chan_tx); dma_release_channel(host->dma_chan_rx); dma_release_channel(host->dma_chan_tx); - - mmc_free_host(mmc); } } diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h index 291ddb4ad9be..084964cecf9d 100644 --- a/drivers/mmc/host/renesas_sdhi.h +++ b/drivers/mmc/host/renesas_sdhi.h @@ -85,6 +85,7 @@ struct renesas_sdhi { u32 scc_tappos_hs400; const u8 *adjust_hs400_calib_table; bool needs_adjust_hs400; + bool card_is_sdio; /* Tuning values: 1 for success, 0 for failure */ DECLARE_BITMAP(taps, BITS_PER_LONG); diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c index 8c83e203c516..fb8ca03f661d 100644 --- a/drivers/mmc/host/renesas_sdhi_core.c +++ b/drivers/mmc/host/renesas_sdhi_core.c @@ -686,9 +686,8 @@ static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host) /* Set SCC */ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, priv->tap_set); - /* Enable auto re-tuning */ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL, - SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN | + (priv->card_is_sdio ? 0 : SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN) | sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL)); return 0; @@ -778,6 +777,14 @@ static bool renesas_sdhi_manual_correction(struct tmio_mmc_host *host, bool use_ if (bad_taps & BIT(new_tap % priv->tap_num)) return test_bit(error_tap % priv->tap_num, priv->smpcmp); } else { + if (!priv->card_is_sdio && + !(val & SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR)) { + u32 smpcmp = sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_SMPCMP); + + /* DAT1 is unmatched because of an SDIO irq */ + if (smpcmp & (BIT(17) | BIT(1))) + return false; + } if (val & SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR) return true; /* need retune */ else if (val & SH_MOBILE_SDHI_SCC_RVSREQ_REQTAPUP) @@ -828,11 +835,14 @@ static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host, if (mmc_doing_tune(host->mmc)) return false; - if (((mrq->cmd->error == -ETIMEDOUT) || - (mrq->data && mrq->data->error == -ETIMEDOUT)) && - ((host->mmc->caps & MMC_CAP_NONREMOVABLE) || - (host->ops.get_cd && host->ops.get_cd(host->mmc)))) - ret |= true; + /* mrq can be NULL to check SCC error on SDIO irq without any request */ + if (mrq) { + if (((mrq->cmd->error == -ETIMEDOUT) || + (mrq->data && mrq->data->error == -ETIMEDOUT)) && + ((host->mmc->caps & MMC_CAP_NONREMOVABLE) || + (host->ops.get_cd && host->ops.get_cd(host->mmc)))) + ret |= true; + } if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) & SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN) @@ -843,6 +853,28 @@ static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host, return ret; } +static void renesas_sdhi_init_card(struct mmc_host *mmc, struct mmc_card *card) +{ + struct tmio_mmc_host *host = mmc_priv(mmc); + struct renesas_sdhi *priv = host_to_priv(host); + + /* + * This controller cannot do auto-retune with SDIO irqs, so we + * then need to enforce manual correction. However, when tuning, + * mmc->card is not populated yet, so we don't know if the card + * is SDIO. init_card provides this information earlier, so we + * keep a copy of it. + */ + priv->card_is_sdio = mmc_card_sdio(card); +} + +static void renesas_sdhi_sdio_irq(struct tmio_mmc_host *host) +{ + /* This controller requires retune when an SDIO irq occurs */ + if (renesas_sdhi_check_scc_error(host, NULL)) + mmc_retune_needed(host->mmc); +} + static int renesas_sdhi_wait_idle(struct tmio_mmc_host *host, u32 bit) { int timeout = 1000; @@ -1112,7 +1144,7 @@ int renesas_sdhi_probe(struct platform_device *pdev, host->mmc->caps2 &= ~(MMC_CAP2_HS400 | MMC_CAP2_HS400_ES); /* For some SoC, we disable internal WP. GPIO may override this */ - if (mmc_can_gpio_ro(host->mmc)) + if (mmc_host_can_gpio_ro(host->mmc)) mmc_data->capabilities2 &= ~MMC_CAP2_NO_WRITE_PROTECT; /* SDR speeds are only available on Gen2+ */ @@ -1164,14 +1196,9 @@ int renesas_sdhi_probe(struct platform_device *pdev, ret = renesas_sdhi_clk_enable(host); if (ret) - goto efree; - - rcfg.of_node = of_get_child_by_name(dev->of_node, "vqmmc-regulator"); - if (!of_device_is_available(rcfg.of_node)) { - of_node_put(rcfg.of_node); - rcfg.of_node = NULL; - } + return ret; + rcfg.of_node = of_get_available_child_by_name(dev->of_node, "vqmmc-regulator"); if (rcfg.of_node) { rcfg.driver_data = priv->host; rdev = devm_regulator_register(dev, &renesas_sdhi_vqmmc_regulator, &rcfg); @@ -1232,6 +1259,8 @@ int renesas_sdhi_probe(struct platform_device *pdev, dev_warn(&host->pdev->dev, "Unknown clock rate for tuning\n"); host->check_retune = renesas_sdhi_check_scc_error; + host->sdio_irq = renesas_sdhi_sdio_irq; + host->ops.init_card = renesas_sdhi_init_card; host->ops.execute_tuning = renesas_sdhi_execute_tuning; host->ops.prepare_hs400_tuning = renesas_sdhi_prepare_hs400_tuning; host->ops.hs400_downgrade = renesas_sdhi_disable_scc; @@ -1240,15 +1269,10 @@ int renesas_sdhi_probe(struct platform_device *pdev, sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, host->sdcard_irq_mask_all); - num_irqs = platform_irq_count(pdev); - if (num_irqs < 0) { - ret = num_irqs; - goto edisclk; - } - /* There must be at least one IRQ source */ - if (!num_irqs) { - ret = -ENXIO; + num_irqs = platform_irq_count(pdev); + if (num_irqs <= 0) { + ret = num_irqs ?: -ENOENT; goto edisclk; } @@ -1276,9 +1300,6 @@ int renesas_sdhi_probe(struct platform_device *pdev, edisclk: renesas_sdhi_clk_disable(host); -efree: - tmio_mmc_host_free(host); - return ret; } EXPORT_SYMBOL_GPL(renesas_sdhi_probe); @@ -1289,7 +1310,6 @@ void renesas_sdhi_remove(struct platform_device *pdev) tmio_mmc_host_remove(host); renesas_sdhi_clk_disable(host); - tmio_mmc_host_free(host); } EXPORT_SYMBOL_GPL(renesas_sdhi_remove); diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index 0c6eb60a95fd..dc2587ff8519 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -1498,7 +1498,7 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) dev_dbg(&(pdev->dev), ": Realtek PCI-E SDMMC controller found\n"); - mmc = mmc_alloc_host(sizeof(*host), &pdev->dev); + mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(*host)); if (!mmc) return -ENOMEM; @@ -1529,7 +1529,6 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) if (ret) { pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_disable(&pdev->dev); - mmc_free_host(mmc); return ret; } @@ -1572,8 +1571,6 @@ static void rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev) pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_disable(&pdev->dev); - mmc_free_host(mmc); - dev_dbg(&(pdev->dev), ": Realtek PCI-E SDMMC controller has been removed\n"); } diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c index d229c2b83ea9..c5f6b9df066b 100644 --- a/drivers/mmc/host/rtsx_usb_sdmmc.c +++ b/drivers/mmc/host/rtsx_usb_sdmmc.c @@ -1010,29 +1010,45 @@ static int sd_power_off(struct rtsx_usb_sdmmc *host) return sd_pull_ctl_disable_qfn24(ucr); } -static int sd_set_power_mode(struct rtsx_usb_sdmmc *host, +static void sd_set_power_mode(struct rtsx_usb_sdmmc *host, unsigned char power_mode) { int err; - - if (power_mode != MMC_POWER_OFF) - power_mode = MMC_POWER_ON; + struct rtsx_ucr *ucr = host->ucr; if (power_mode == host->power_mode) - return 0; + return; - if (power_mode == MMC_POWER_OFF) { + switch (power_mode) { + case MMC_POWER_OFF: err = sd_power_off(host); + if (err) + dev_dbg(sdmmc_dev(host), "power-off (err = %d)\n", err); pm_runtime_put_noidle(sdmmc_dev(host)); - } else { + break; + + case MMC_POWER_UP: pm_runtime_get_noresume(sdmmc_dev(host)); err = sd_power_on(host); - } + if (err) + dev_dbg(sdmmc_dev(host), "power-on (err = %d)\n", err); + /* issue the clock signals to card at least 74 clocks */ + rtsx_usb_write_register(ucr, SD_BUS_STAT, SD_CLK_TOGGLE_EN, SD_CLK_TOGGLE_EN); + break; - if (!err) - host->power_mode = power_mode; + case MMC_POWER_ON: + /* stop to send the clock signals */ + rtsx_usb_write_register(ucr, SD_BUS_STAT, SD_CLK_TOGGLE_EN, 0x00); + break; - return err; + case MMC_POWER_UNDEFINED: + break; + + default: + break; + } + + host->power_mode = power_mode; } static int sd_set_timing(struct rtsx_usb_sdmmc *host, @@ -1334,7 +1350,7 @@ static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev) dev_dbg(&(pdev->dev), ": Realtek USB SD/MMC controller found\n"); - mmc = mmc_alloc_host(sizeof(*host), &pdev->dev); + mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(*host)); if (!mmc) return -ENOMEM; @@ -1368,7 +1384,6 @@ static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev) #ifdef RTSX_USB_USE_LEDS_CLASS led_classdev_unregister(&host->led); #endif - mmc_free_host(mmc); pm_runtime_disable(&pdev->dev); return ret; } @@ -1406,7 +1421,6 @@ static void rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev) led_classdev_unregister(&host->led); #endif - mmc_free_host(mmc); pm_runtime_disable(&pdev->dev); platform_set_drvdata(pdev, NULL); diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index e6c5c82f64fa..2d46d4854fa1 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -948,7 +948,6 @@ err_free: if (c->slot && c->slot->free_slot) c->slot->free_slot(pdev); - sdhci_free_host(c->host); return err; } @@ -972,8 +971,6 @@ static void sdhci_acpi_remove(struct platform_device *pdev) if (c->slot && c->slot->free_slot) c->slot->free_slot(pdev); - - sdhci_free_host(c->host); } static void __maybe_unused sdhci_acpi_reset_signal_voltage_if_needed( @@ -1028,14 +1025,11 @@ static int sdhci_acpi_runtime_suspend(struct device *dev) { struct sdhci_acpi_host *c = dev_get_drvdata(dev); struct sdhci_host *host = c->host; - int ret; if (host->tuning_mode != SDHCI_TUNING_MODE_3) mmc_retune_needed(host->mmc); - ret = sdhci_runtime_suspend_host(host); - if (ret) - return ret; + sdhci_runtime_suspend_host(host); sdhci_acpi_reset_signal_voltage_if_needed(dev); return 0; @@ -1047,7 +1041,8 @@ static int sdhci_acpi_runtime_resume(struct device *dev) sdhci_acpi_byt_setting(&c->pdev->dev); - return sdhci_runtime_resume_host(c->host, 0); + sdhci_runtime_resume_host(c->host, 0); + return 0; } #endif diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c index fda911fb28e5..0f2a84f769b6 100644 --- a/drivers/mmc/host/sdhci-bcm-kona.c +++ b/drivers/mmc/host/sdhci-bcm-kona.c @@ -304,8 +304,6 @@ err_clk_disable: clk_disable_unprepare(pltfm_priv->clk); err_pltfm_free: - sdhci_pltfm_free(pdev); - dev_err(dev, "Probing of sdhci-pltfm failed: %d\n", ret); return ret; } diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c index 48cdcba0f39c..efc2f3bdc631 100644 --- a/drivers/mmc/host/sdhci-brcmstb.c +++ b/drivers/mmc/host/sdhci-brcmstb.c @@ -485,7 +485,6 @@ add_host: return res; err: - sdhci_pltfm_free(pdev); clk_disable_unprepare(base_clk); return res; } diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c index a94b297fcf2a..2d823e158c59 100644 --- a/drivers/mmc/host/sdhci-cadence.c +++ b/drivers/mmc/host/sdhci-cadence.c @@ -144,7 +144,7 @@ static unsigned int sdhci_cdns_phy_param_count(struct device_node *np) int i; for (i = 0; i < ARRAY_SIZE(sdhci_cdns_phy_cfgs); i++) - if (of_property_read_bool(np, sdhci_cdns_phy_cfgs[i].property)) + if (of_property_present(np, sdhci_cdns_phy_cfgs[i].property)) count++; return count; @@ -433,6 +433,13 @@ static const struct sdhci_cdns_drv_data sdhci_elba_drv_data = { }, }; +static const struct sdhci_cdns_drv_data sdhci_eyeq_drv_data = { + .pltfm_data = { + .ops = &sdhci_cdns_ops, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + }, +}; + static const struct sdhci_cdns_drv_data sdhci_cdns_drv_data = { .pltfm_data = { .ops = &sdhci_cdns_ops, @@ -515,7 +522,7 @@ static int sdhci_cdns_probe(struct platform_device *pdev) if (data->init) { ret = data->init(pdev); if (ret) - goto free; + return ret; } sdhci_enable_v4_mode(host); __sdhci_read_caps(host, &version, NULL, NULL); @@ -524,33 +531,24 @@ static int sdhci_cdns_probe(struct platform_device *pdev) ret = mmc_of_parse(host->mmc); if (ret) - goto free; + return ret; sdhci_cdns_phy_param_parse(dev->of_node, priv); ret = sdhci_cdns_phy_init(priv); if (ret) - goto free; + return ret; if (host->mmc->caps & MMC_CAP_HW_RESET) { priv->rst_hw = devm_reset_control_get_optional_exclusive(dev, NULL); - if (IS_ERR(priv->rst_hw)) { - ret = dev_err_probe(mmc_dev(host->mmc), PTR_ERR(priv->rst_hw), + if (IS_ERR(priv->rst_hw)) + return dev_err_probe(mmc_dev(host->mmc), PTR_ERR(priv->rst_hw), "reset controller error\n"); - goto free; - } if (priv->rst_hw) host->mmc_host_ops.card_hw_reset = sdhci_cdns_mmc_hw_reset; } - ret = sdhci_add_host(host); - if (ret) - goto free; - - return 0; -free: - sdhci_pltfm_free(pdev); - return ret; + return sdhci_add_host(host); } #ifdef CONFIG_PM_SLEEP @@ -595,6 +593,10 @@ static const struct of_device_id sdhci_cdns_match[] = { .compatible = "amd,pensando-elba-sd4hc", .data = &sdhci_elba_drv_data, }, + { + .compatible = "mobileye,eyeq-sd4hc", + .data = &sdhci_eyeq_drv_data, + }, { .compatible = "cdns,sd4hc" }, { /* sentinel */ } }; diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c index 77034b13fa66..dbfaee4a5ada 100644 --- a/drivers/mmc/host/sdhci-dove.c +++ b/drivers/mmc/host/sdhci-dove.c @@ -79,17 +79,9 @@ static int sdhci_dove_probe(struct platform_device *pdev) ret = mmc_of_parse(host->mmc); if (ret) - goto err_sdhci_add; + return ret; - ret = sdhci_add_host(host); - if (ret) - goto err_sdhci_add; - - return 0; - -err_sdhci_add: - sdhci_pltfm_free(pdev); - return ret; + return sdhci_add_host(host); } static const struct of_device_id sdhci_dove_of_match_table[] = { diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index ff78a7c6a04c..a040c0896a7b 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -31,7 +31,9 @@ #include "cqhci.h" #define ESDHC_SYS_CTRL_DTOCV_MASK GENMASK(19, 16) +#define ESDHC_SYS_CTRL_RST_FIFO BIT(22) #define ESDHC_SYS_CTRL_IPP_RST_N BIT(23) +#define ESDHC_SYS_CTRL_RESET_TUNING BIT(28) #define ESDHC_CTRL_D3CD 0x08 #define ESDHC_BURST_LEN_EN_INCR (1 << 27) /* VENDOR SPEC register */ @@ -81,7 +83,11 @@ #define ESDHC_TUNE_CTRL_STEP 1 #define ESDHC_TUNE_CTRL_MIN 0 #define ESDHC_TUNE_CTRL_MAX ((1 << 7) - 1) - +#define ESDHC_TUNE_CTRL_STATUS_TAP_SEL_MASK GENMASK(30, 16) +#define ESDHC_TUNE_CTRL_STATUS_TAP_SEL_PRE_MASK GENMASK(30, 24) +#define ESDHC_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK GENMASK(14, 8) +#define ESDHC_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT_MASK GENMASK(7, 4) +#define ESDHC_TUNE_CTRL_STATUS_DLY_CELL_SET_POST_MASK GENMASK(3, 0) /* strobe dll register */ #define ESDHC_STROBE_DLL_CTRL 0x70 #define ESDHC_STROBE_DLL_CTRL_ENABLE (1 << 0) @@ -104,6 +110,7 @@ #define ESDHC_TUNING_CTRL 0xcc #define ESDHC_STD_TUNING_EN (1 << 24) +#define ESDHC_TUNING_WINDOW_MASK GENMASK(22, 20) /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ #define ESDHC_TUNING_START_TAP_DEFAULT 0x1 #define ESDHC_TUNING_START_TAP_MASK 0x7f @@ -205,6 +212,11 @@ /* The IP does not have GPIO CD wake capabilities */ #define ESDHC_FLAG_SKIP_CD_WAKE BIT(18) +/* the controller has dummy pad for clock loopback */ +#define ESDHC_FLAG_DUMMY_PAD BIT(19) + +#define ESDHC_AUTO_TUNING_WINDOW 3 + enum wp_types { ESDHC_WP_NONE, /* no WP, neither controller nor gpio */ ESDHC_WP_CONTROLLER, /* mmc controller internal WP */ @@ -235,6 +247,8 @@ struct esdhc_platform_data { unsigned int tuning_step; /* The delay cell steps in tuning procedure */ unsigned int tuning_start_tap; /* The start delay cell point in tuning procedure */ unsigned int strobe_dll_delay_target; /* The delay cell for strobe pad (read clock) */ + unsigned int saved_tuning_delay_cell; /* save the value of tuning delay cell */ + unsigned int saved_auto_tuning_window; /* save the auto tuning window width */ }; struct esdhc_soc_data { @@ -264,35 +278,35 @@ static const struct esdhc_soc_data usdhc_imx6q_data = { }; static const struct esdhc_soc_data usdhc_imx6sl_data = { - .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_ERR004536 | ESDHC_FLAG_HS200 | ESDHC_FLAG_BROKEN_AUTO_CMD23, }; static const struct esdhc_soc_data usdhc_imx6sll_data = { - .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 | ESDHC_FLAG_HS400 | ESDHC_FLAG_STATE_LOST_IN_LPMODE, }; static const struct esdhc_soc_data usdhc_imx6sx_data = { - .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 | ESDHC_FLAG_STATE_LOST_IN_LPMODE | ESDHC_FLAG_BROKEN_AUTO_CMD23, }; static const struct esdhc_soc_data usdhc_imx6ull_data = { - .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 | ESDHC_FLAG_ERR010450 | ESDHC_FLAG_STATE_LOST_IN_LPMODE, }; static const struct esdhc_soc_data usdhc_imx7d_data = { - .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 | ESDHC_FLAG_HS400 | ESDHC_FLAG_STATE_LOST_IN_LPMODE @@ -308,7 +322,7 @@ static struct esdhc_soc_data usdhc_s32g2_data = { }; static struct esdhc_soc_data usdhc_imx7ulp_data = { - .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 | ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400 | ESDHC_FLAG_STATE_LOST_IN_LPMODE, @@ -321,7 +335,7 @@ static struct esdhc_soc_data usdhc_imxrt1050_data = { }; static struct esdhc_soc_data usdhc_imx8qxp_data = { - .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES | ESDHC_FLAG_STATE_LOST_IN_LPMODE @@ -330,13 +344,22 @@ static struct esdhc_soc_data usdhc_imx8qxp_data = { }; static struct esdhc_soc_data usdhc_imx8mm_data = { - .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES | ESDHC_FLAG_STATE_LOST_IN_LPMODE, .quirks = SDHCI_QUIRK_NO_LED, }; +static struct esdhc_soc_data usdhc_imx95_data = { + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_MAN_TUNING + | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 + | ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES + | ESDHC_FLAG_STATE_LOST_IN_LPMODE + | ESDHC_FLAG_DUMMY_PAD, + .quirks = SDHCI_QUIRK_NO_LED, +}; + struct pltfm_imx_data { u32 scratchpad; struct pinctrl *pinctrl; @@ -381,6 +404,8 @@ static const struct of_device_id imx_esdhc_dt_ids[] = { { .compatible = "fsl,imx7ulp-usdhc", .data = &usdhc_imx7ulp_data, }, { .compatible = "fsl,imx8qxp-usdhc", .data = &usdhc_imx8qxp_data, }, { .compatible = "fsl,imx8mm-usdhc", .data = &usdhc_imx8mm_data, }, + { .compatible = "fsl,imx94-usdhc", .data = &usdhc_imx95_data, }, + { .compatible = "fsl,imx95-usdhc", .data = &usdhc_imx95_data, }, { .compatible = "fsl,imxrt1050-usdhc", .data = &usdhc_imxrt1050_data, }, { .compatible = "nxp,s32g2-usdhc", .data = &usdhc_s32g2_data, }, { /* sentinel */ } @@ -717,23 +742,17 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { u32 v = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); - u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); - if (val & SDHCI_CTRL_TUNED_CLK) { + if (val & SDHCI_CTRL_TUNED_CLK) v |= ESDHC_MIX_CTRL_SMPCLK_SEL; - } else { + else v &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; - m &= ~ESDHC_MIX_CTRL_FBCLK_SEL; - } - if (val & SDHCI_CTRL_EXEC_TUNING) { + if (val & SDHCI_CTRL_EXEC_TUNING) v |= ESDHC_MIX_CTRL_EXE_TUNE; - m |= ESDHC_MIX_CTRL_FBCLK_SEL; - } else { + else v &= ~ESDHC_MIX_CTRL_EXE_TUNE; - } writel(v, host->ioaddr + SDHCI_AUTO_CMD_STATUS); - writel(m, host->ioaddr + ESDHC_MIX_CTRL); } return; case SDHCI_TRANSFER_MODE: @@ -870,6 +889,11 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) esdhc_clrset_le(host, mask, new_val, reg); return; + case SDHCI_TIMEOUT_CONTROL: + esdhc_clrset_le(host, ESDHC_SYS_CTRL_DTOCV_MASK, + FIELD_PREP(ESDHC_SYS_CTRL_DTOCV_MASK, val), + ESDHC_SYSTEM_CONTROL); + return; case SDHCI_SOFTWARE_RESET: if (val & SDHCI_RESET_DATA) new_val = readl(host->ioaddr + SDHCI_HOST_CONTROL); @@ -1057,7 +1081,7 @@ static void esdhc_reset_tuning(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); - u32 ctrl; + u32 ctrl, tuning_ctrl, sys_ctrl; int ret; /* Reset the tuning circuit */ @@ -1066,11 +1090,25 @@ static void esdhc_reset_tuning(struct sdhci_host *host) ctrl &= ~ESDHC_MIX_CTRL_AUTO_TUNE_EN; if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; - ctrl &= ~ESDHC_MIX_CTRL_FBCLK_SEL; writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL); writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL); + /* + * enable the std tuning just in case it cleared in + * sdhc_esdhc_tuning_restore. + */ + tuning_ctrl = readl(host->ioaddr + ESDHC_TUNING_CTRL); + if (!(tuning_ctrl & ESDHC_STD_TUNING_EN)) { + tuning_ctrl |= ESDHC_STD_TUNING_EN; + writel(tuning_ctrl, host->ioaddr + ESDHC_TUNING_CTRL); + } + + /* set the reset tuning bit */ + sys_ctrl = readl(host->ioaddr + ESDHC_SYSTEM_CONTROL); + sys_ctrl |= ESDHC_SYS_CTRL_RESET_TUNING; + writel(sys_ctrl, host->ioaddr + ESDHC_SYSTEM_CONTROL); + ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS); ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; ctrl &= ~ESDHC_MIX_CTRL_EXE_TUNE; @@ -1130,7 +1168,7 @@ static int usdhc_execute_tuning(struct mmc_host *mmc, u32 opcode) static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) { - u32 reg; + u32 reg, sys_ctrl; u8 sw_rst; int ret; @@ -1146,13 +1184,23 @@ static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) "warning! RESET_ALL never complete before sending tuning command\n"); reg = readl(host->ioaddr + ESDHC_MIX_CTRL); - reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL | - ESDHC_MIX_CTRL_FBCLK_SEL; + reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL; writel(reg, host->ioaddr + ESDHC_MIX_CTRL); - writel(val << 8, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); + writel(FIELD_PREP(ESDHC_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK, val), + host->ioaddr + ESDHC_TUNE_CTRL_STATUS); dev_dbg(mmc_dev(host->mmc), "tuning with delay 0x%x ESDHC_TUNE_CTRL_STATUS 0x%x\n", val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS)); + + /* set RST_FIFO to reset the async FIFO, and wat it to self-clear */ + sys_ctrl = readl(host->ioaddr + ESDHC_SYSTEM_CONTROL); + sys_ctrl |= ESDHC_SYS_CTRL_RST_FIFO; + writel(sys_ctrl, host->ioaddr + ESDHC_SYSTEM_CONTROL); + ret = readl_poll_timeout(host->ioaddr + ESDHC_SYSTEM_CONTROL, sys_ctrl, + !(sys_ctrl & ESDHC_SYS_CTRL_RST_FIFO), 10, 100); + if (ret == -ETIMEDOUT) + dev_warn(mmc_dev(host->mmc), + "warning! RST_FIFO not clear in 100us\n"); } static void esdhc_post_tuning(struct sdhci_host *host) @@ -1172,9 +1220,10 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) { int min, max, avg, ret; int win_length, target_min, target_max, target_win_length; + u32 clk_tune_ctrl_status, temp; - min = ESDHC_TUNE_CTRL_MIN; - max = ESDHC_TUNE_CTRL_MIN; + min = target_min = ESDHC_TUNE_CTRL_MIN; + max = target_max = ESDHC_TUNE_CTRL_MIN; target_win_length = 0; while (max < ESDHC_TUNE_CTRL_MAX) { /* find the mininum delay first which can pass tuning */ @@ -1211,6 +1260,30 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) /* use average delay to get the best timing */ avg = (target_min + target_max) / 2; esdhc_prepare_tuning(host, avg); + + /* + * adjust the delay according to tuning window, make preparation + * for the auto-tuning logic. According to hardware suggest, need + * to config the auto tuning window width to 3, to make the auto + * tuning logic have enough space to handle the sample point shift + * caused by temperature change. + */ + clk_tune_ctrl_status = FIELD_PREP(ESDHC_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK, + avg - ESDHC_AUTO_TUNING_WINDOW) | + FIELD_PREP(ESDHC_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT_MASK, + ESDHC_AUTO_TUNING_WINDOW) | + FIELD_PREP(ESDHC_TUNE_CTRL_STATUS_DLY_CELL_SET_POST_MASK, + ESDHC_AUTO_TUNING_WINDOW); + + writel(clk_tune_ctrl_status, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); + ret = readl_poll_timeout(host->ioaddr + ESDHC_TUNE_CTRL_STATUS, temp, + clk_tune_ctrl_status == + FIELD_GET(ESDHC_TUNE_CTRL_STATUS_TAP_SEL_MASK, temp), + 1, 10); + if (ret == -ETIMEDOUT) + dev_warn(mmc_dev(host->mmc), + "clock tuning control status not set in 10us\n"); + ret = mmc_send_tuning(host->mmc, opcode, NULL); esdhc_post_tuning(host); @@ -1365,6 +1438,16 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing) break; } + if (!(imx_data->socdata->flags & ESDHC_FLAG_DUMMY_PAD) && + (timing == MMC_TIMING_UHS_SDR104 || + timing == MMC_TIMING_MMC_HS200 || + timing == MMC_TIMING_MMC_HS400)) + m |= ESDHC_MIX_CTRL_FBCLK_SEL; + else + m &= ~ESDHC_MIX_CTRL_FBCLK_SEL; + + writel(m, host->ioaddr + ESDHC_MIX_CTRL); + esdhc_change_pinstate(host, timing); } @@ -1385,17 +1468,6 @@ static unsigned int esdhc_get_max_timeout_count(struct sdhci_host *host) return esdhc_is_usdhc(imx_data) ? 1 << 29 : 1 << 27; } -static void esdhc_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) -{ - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); - - /* use maximum timeout counter */ - esdhc_clrset_le(host, ESDHC_SYS_CTRL_DTOCV_MASK, - esdhc_is_usdhc(imx_data) ? 0xF0000 : 0xE0000, - ESDHC_SYSTEM_CONTROL); -} - static u32 esdhc_cqhci_irq(struct sdhci_host *host, u32 intmask) { int cmd_error = 0; @@ -1432,7 +1504,6 @@ static struct sdhci_ops sdhci_esdhc_ops = { .get_min_clock = esdhc_pltfm_get_min_clock, .get_max_timeout_count = esdhc_get_max_timeout_count, .get_ro = esdhc_pltfm_get_ro, - .set_timeout = esdhc_set_timeout, .set_bus_width = esdhc_pltfm_set_bus_width, .set_uhs_signaling = esdhc_set_uhs_signaling, .reset = esdhc_reset, @@ -1529,6 +1600,16 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) << ESDHC_TUNING_STEP_SHIFT; } + /* + * Config the tuning window to the hardware suggested value 3. + * This tuning window is used for auto tuning logic. The default + * tuning window is 2, here change to 3 make the window a bit + * wider, give auto tuning enough space to handle the sample + * point shift cause by temperature change. + */ + tmp &= ~ESDHC_TUNING_WINDOW_MASK; + tmp |= FIELD_PREP(ESDHC_TUNING_WINDOW_MASK, ESDHC_AUTO_TUNING_WINDOW); + /* Disable the CMD CRC check for tuning, if not, need to * add some delay after every tuning command, because * hardware standard tuning logic will directly go to next @@ -1569,6 +1650,65 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host) } } +#ifdef CONFIG_PM_SLEEP +static void sdhc_esdhc_tuning_save(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); + u32 reg; + + /* + * SD/eMMC do not need this tuning save because it will re-init + * after system resume back. + * Here save the tuning delay value for SDIO device since it may + * keep power during system PM. And for usdhc, only SDR50 and + * SDR104 mode for SDIO device need to do tuning, and need to + * save/restore. + */ + if (host->timing == MMC_TIMING_UHS_SDR50 || + host->timing == MMC_TIMING_UHS_SDR104) { + reg = readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS); + reg = FIELD_GET(ESDHC_TUNE_CTRL_STATUS_TAP_SEL_PRE_MASK, reg); + imx_data->boarddata.saved_tuning_delay_cell = reg; + } +} + +static void sdhc_esdhc_tuning_restore(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); + u32 reg; + + if (host->timing == MMC_TIMING_UHS_SDR50 || + host->timing == MMC_TIMING_UHS_SDR104) { + /* + * restore the tuning delay value actually is a + * manual tuning method, so clear the standard + * tuning enable bit here. Will set back this + * ESDHC_STD_TUNING_EN in esdhc_reset_tuning() + * when trigger re-tuning. + */ + reg = readl(host->ioaddr + ESDHC_TUNING_CTRL); + reg &= ~ESDHC_STD_TUNING_EN; + writel(reg, host->ioaddr + ESDHC_TUNING_CTRL); + + reg = readl(host->ioaddr + ESDHC_MIX_CTRL); + reg |= ESDHC_MIX_CTRL_SMPCLK_SEL; + if (!(imx_data->socdata->flags & ESDHC_FLAG_DUMMY_PAD)) + reg |= ESDHC_MIX_CTRL_FBCLK_SEL; + writel(reg, host->ioaddr + ESDHC_MIX_CTRL); + + writel(FIELD_PREP(ESDHC_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK, + imx_data->boarddata.saved_tuning_delay_cell) | + FIELD_PREP(ESDHC_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT_MASK, + ESDHC_AUTO_TUNING_WINDOW) | + FIELD_PREP(ESDHC_TUNE_CTRL_STATUS_DLY_CELL_SET_POST_MASK, + ESDHC_AUTO_TUNING_WINDOW), + host->ioaddr + ESDHC_TUNE_CTRL_STATUS); + } +} +#endif + static void esdhc_cqe_enable(struct mmc_host *mmc) { struct sdhci_host *host = mmc_priv(mmc); @@ -1777,6 +1917,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) * to distinguish the card type. */ host->mmc_host_ops.init_card = usdhc_init_card; + + host->max_timeout_count = 0xF; } if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) @@ -1849,7 +1991,6 @@ disable_per_clk: free_sdhci: if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) cpu_latency_qos_remove_request(&imx_data->pm_qos_req); - sdhci_pltfm_free(pdev); return err; } @@ -1873,8 +2014,6 @@ static void sdhci_esdhc_imx_remove(struct platform_device *pdev) if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) cpu_latency_qos_remove_request(&imx_data->pm_qos_req); - - sdhci_pltfm_free(pdev); } #ifdef CONFIG_PM_SLEEP @@ -1885,11 +2024,14 @@ static int sdhci_esdhc_suspend(struct device *dev) struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); int ret; - if (host->mmc->caps2 & MMC_CAP2_CQE) { - ret = cqhci_suspend(host->mmc); - if (ret) - return ret; - } + /* + * Switch to runtime resume for two reasons: + * 1, there is register access (e.g., wakeup control register), so + * need to make sure gate on ipg clock. + * 2, make sure the pm_runtime_force_resume() in sdhci_esdhc_resume() really + * invoke its ->runtime_resume callback (needs_force_resume = 1). + */ + pm_runtime_get_sync(dev); if ((imx_data->socdata->flags & ESDHC_FLAG_STATE_LOST_IN_LPMODE) && (host->tuning_mode != SDHCI_TUNING_MODE_1)) { @@ -1897,43 +2039,76 @@ static int sdhci_esdhc_suspend(struct device *dev) mmc_retune_needed(host->mmc); } - if (host->tuning_mode != SDHCI_TUNING_MODE_3) - mmc_retune_needed(host->mmc); - - ret = sdhci_suspend_host(host); - if (ret) - return ret; - - ret = pinctrl_pm_select_sleep_state(dev); - if (ret) - return ret; + /* + * For the device need to keep power during system PM, need + * to save the tuning delay value just in case the usdhc + * lost power during system PM. + */ + if (mmc_card_keep_power(host->mmc) && mmc_card_wake_sdio_irq(host->mmc) && + esdhc_is_usdhc(imx_data)) + sdhc_esdhc_tuning_save(host); + + if (device_may_wakeup(dev)) { + /* The irqs of imx are not shared. It is safe to disable */ + disable_irq(host->irq); + ret = sdhci_enable_irq_wakeups(host); + if (!ret) + dev_warn(dev, "Failed to enable irq wakeup\n"); + } else { + /* + * For the device which works as wakeup source, no need + * to change the pinctrl to sleep state. + * e.g. For SDIO device, the interrupt share with data pin, + * but the pinctrl sleep state may config the data pin to + * other function like GPIO function to save power in PM, + * which finally block the SDIO wakeup function. + */ + ret = pinctrl_pm_select_sleep_state(dev); + if (ret) + return ret; + } ret = mmc_gpio_set_cd_wake(host->mmc, true); + /* + * Make sure invoke runtime_suspend to gate off clock. + * uSDHC IP supports in-band SDIO wakeup even without clock. + */ + pm_runtime_force_suspend(dev); + return ret; } static int sdhci_esdhc_resume(struct device *dev) { struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); int ret; - ret = pinctrl_pm_select_default_state(dev); + pm_runtime_force_resume(dev); + + ret = mmc_gpio_set_cd_wake(host->mmc, false); if (ret) return ret; /* re-initialize hw state in case it's lost in low power mode */ sdhci_esdhc_imx_hwinit(host); - ret = sdhci_resume_host(host); - if (ret) - return ret; + if (host->irq_wake_enabled) { + sdhci_disable_irq_wakeups(host); + enable_irq(host->irq); + } - if (host->mmc->caps2 & MMC_CAP2_CQE) - ret = cqhci_resume(host->mmc); + /* + * restore the saved tuning delay value for the device which keep + * power during system PM. + */ + if (mmc_card_keep_power(host->mmc) && mmc_card_wake_sdio_irq(host->mmc) && + esdhc_is_usdhc(imx_data)) + sdhc_esdhc_tuning_restore(host); - if (!ret) - ret = mmc_gpio_set_cd_wake(host->mmc, false); + pm_runtime_put_autosuspend(dev); return ret; } @@ -1953,9 +2128,7 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev) return ret; } - ret = sdhci_runtime_suspend_host(host); - if (ret) - return ret; + sdhci_runtime_suspend_host(host); if (host->tuning_mode != SDHCI_TUNING_MODE_3) mmc_retune_needed(host->mmc); @@ -1969,7 +2142,7 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev) if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS) cpu_latency_qos_remove_request(&imx_data->pm_qos_req); - return ret; + return 0; } static int sdhci_esdhc_runtime_resume(struct device *dev) @@ -1999,17 +2172,13 @@ static int sdhci_esdhc_runtime_resume(struct device *dev) esdhc_pltfm_set_clock(host, imx_data->actual_clock); - err = sdhci_runtime_resume_host(host, 0); - if (err) - goto disable_ipg_clk; + sdhci_runtime_resume_host(host, 0); if (host->mmc->caps2 & MMC_CAP2_CQE) err = cqhci_resume(host->mmc); return err; -disable_ipg_clk: - clk_disable_unprepare(imx_data->clk_ipg); disable_per_clk: clk_disable_unprepare(imx_data->clk_per); disable_ahb_clk: diff --git a/drivers/mmc/host/sdhci-esdhc-mcf.c b/drivers/mmc/host/sdhci-esdhc-mcf.c index 327662ba5bd9..375fce5639d7 100644 --- a/drivers/mmc/host/sdhci-esdhc-mcf.c +++ b/drivers/mmc/host/sdhci-esdhc-mcf.c @@ -426,28 +426,22 @@ static int sdhci_esdhc_mcf_probe(struct platform_device *pdev) host->flags |= SDHCI_AUTO_CMD12; mcf_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); - if (IS_ERR(mcf_data->clk_ipg)) { - err = PTR_ERR(mcf_data->clk_ipg); - goto err_exit; - } + if (IS_ERR(mcf_data->clk_ipg)) + return PTR_ERR(mcf_data->clk_ipg); mcf_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); - if (IS_ERR(mcf_data->clk_ahb)) { - err = PTR_ERR(mcf_data->clk_ahb); - goto err_exit; - } + if (IS_ERR(mcf_data->clk_ahb)) + return PTR_ERR(mcf_data->clk_ahb); mcf_data->clk_per = devm_clk_get(&pdev->dev, "per"); - if (IS_ERR(mcf_data->clk_per)) { - err = PTR_ERR(mcf_data->clk_per); - goto err_exit; - } + if (IS_ERR(mcf_data->clk_per)) + return PTR_ERR(mcf_data->clk_per); pltfm_host->clk = mcf_data->clk_per; pltfm_host->clock = clk_get_rate(pltfm_host->clk); err = clk_prepare_enable(mcf_data->clk_per); if (err) - goto err_exit; + return err; err = clk_prepare_enable(mcf_data->clk_ipg); if (err) @@ -485,9 +479,6 @@ unprep_ipg: clk_disable_unprepare(mcf_data->clk_ipg); unprep_per: clk_disable_unprepare(mcf_data->clk_per); -err_exit: - sdhci_pltfm_free(pdev); - return err; } @@ -502,8 +493,6 @@ static void sdhci_esdhc_mcf_remove(struct platform_device *pdev) clk_disable_unprepare(mcf_data->clk_ipg); clk_disable_unprepare(mcf_data->clk_ahb); clk_disable_unprepare(mcf_data->clk_per); - - sdhci_pltfm_free(pdev); } static struct platform_driver sdhci_esdhc_mcf_driver = { diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index 80b2567a488b..35ef5c5f5146 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -379,7 +379,7 @@ static int sdhci_iproc_probe(struct platform_device *pdev) ret = mmc_of_parse(host->mmc); if (ret) - goto err; + return ret; sdhci_get_property(pdev); @@ -387,10 +387,8 @@ static int sdhci_iproc_probe(struct platform_device *pdev) if (dev->of_node) { pltfm_host->clk = devm_clk_get_enabled(dev, NULL); - if (IS_ERR(pltfm_host->clk)) { - ret = PTR_ERR(pltfm_host->clk); - goto err; - } + if (IS_ERR(pltfm_host->clk)) + return PTR_ERR(pltfm_host->clk); } if (iproc_host->data->missing_caps) { @@ -399,15 +397,7 @@ static int sdhci_iproc_probe(struct platform_device *pdev) &iproc_host->data->caps1); } - ret = sdhci_add_host(host); - if (ret) - goto err; - - return 0; - -err: - sdhci_pltfm_free(pdev); - return ret; + return sdhci_add_host(host); } static void sdhci_iproc_shutdown(struct platform_device *pdev) diff --git a/drivers/mmc/host/sdhci-milbeaut.c b/drivers/mmc/host/sdhci-milbeaut.c index a4675456f9c7..bda71d5966dc 100644 --- a/drivers/mmc/host/sdhci-milbeaut.c +++ b/drivers/mmc/host/sdhci-milbeaut.c @@ -258,7 +258,7 @@ static int sdhci_milbeaut_probe(struct platform_device *pdev) ret = mmc_of_parse(host->mmc); if (ret) - goto err; + return ret; platform_set_drvdata(pdev, host); @@ -267,23 +267,19 @@ static int sdhci_milbeaut_probe(struct platform_device *pdev) host->irq = irq; host->ioaddr = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(host->ioaddr)) { - ret = PTR_ERR(host->ioaddr); - goto err; - } + if (IS_ERR(host->ioaddr)) + return PTR_ERR(host->ioaddr); if (dev_of_node(dev)) { sdhci_get_of_property(pdev); priv->clk_iface = devm_clk_get(&pdev->dev, "iface"); - if (IS_ERR(priv->clk_iface)) { - ret = PTR_ERR(priv->clk_iface); - goto err; - } + if (IS_ERR(priv->clk_iface)) + return PTR_ERR(priv->clk_iface); ret = clk_prepare_enable(priv->clk_iface); if (ret) - goto err; + return ret; priv->clk = devm_clk_get(&pdev->dev, "core"); if (IS_ERR(priv->clk)) { @@ -308,8 +304,6 @@ err_add_host: clk_disable_unprepare(priv->clk); err_clk: clk_disable_unprepare(priv->clk_iface); -err: - sdhci_free_host(host); return ret; } @@ -324,7 +318,6 @@ static void sdhci_milbeaut_remove(struct platform_device *pdev) clk_disable_unprepare(priv->clk_iface); clk_disable_unprepare(priv->clk); - sdhci_free_host(host); platform_set_drvdata(pdev, NULL); } diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 57bd49eea777..9d8e20dc8ca1 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -1564,6 +1564,7 @@ static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + struct mmc_host *mmc = host->mmc; bool done = false; u32 val = SWITCHABLE_SIGNALING_VOLTAGE; const struct sdhci_msm_offset *msm_offset = @@ -1621,6 +1622,12 @@ static void sdhci_msm_check_power_status(struct sdhci_host *host, u32 req_type) "%s: pwr_irq for req: (%d) timed out\n", mmc_hostname(host->mmc), req_type); } + + if ((req_type & REQ_BUS_ON) && mmc->card && !mmc->ops->get_cd(mmc)) { + sdhci_writeb(host, 0, SDHCI_POWER_CONTROL); + host->pwr = 0; + } + pr_debug("%s: %s: request %d done\n", mmc_hostname(host->mmc), __func__, req_type); } @@ -1679,6 +1686,13 @@ static void sdhci_msm_handle_pwr_irq(struct sdhci_host *host, int irq) udelay(10); } + if ((irq_status & CORE_PWRCTL_BUS_ON) && mmc->card && + !mmc->ops->get_cd(mmc)) { + msm_host_writel(msm_host, CORE_PWRCTL_BUS_FAIL, host, + msm_offset->core_pwrctl_ctl); + return; + } + /* Handle BUS ON/OFF*/ if (irq_status & CORE_PWRCTL_BUS_ON) { pwr_state = REQ_BUS_ON; @@ -1882,6 +1896,11 @@ static int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host, if (IS_ERR_OR_NULL(ice)) return PTR_ERR_OR_ZERO(ice); + if (qcom_ice_get_supported_key_type(ice) != BLK_CRYPTO_KEY_TYPE_RAW) { + dev_warn(dev, "Wrapped keys not supported. Disabling inline encryption support.\n"); + return 0; + } + msm_host->ice = ice; /* Initialize the blk_crypto_profile */ @@ -1962,16 +1981,7 @@ static int sdhci_msm_ice_keyslot_program(struct blk_crypto_profile *profile, struct sdhci_msm_host *msm_host = sdhci_msm_host_from_crypto_profile(profile); - /* Only AES-256-XTS has been tested so far. */ - if (key->crypto_cfg.crypto_mode != BLK_ENCRYPTION_MODE_AES_256_XTS) - return -EOPNOTSUPP; - - return qcom_ice_program_key(msm_host->ice, - QCOM_ICE_CRYPTO_ALG_AES_XTS, - QCOM_ICE_CRYPTO_KEY_SIZE_256, - key->bytes, - key->crypto_cfg.data_unit_size / 512, - slot); + return qcom_ice_program_key(msm_host->ice, slot, key); } static int sdhci_msm_ice_keyslot_evict(struct blk_crypto_profile *profile, @@ -2530,7 +2540,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) ret = mmc_of_parse(host->mmc); if (ret) - goto pltfm_free; + return ret; /* * Based on the compatible string, load the required msm host info from @@ -2552,7 +2562,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) ret = sdhci_msm_gcc_reset(&pdev->dev, host); if (ret) - goto pltfm_free; + return ret; /* Setup SDCC bus voter clock. */ msm_host->bus_clk = devm_clk_get(&pdev->dev, "bus"); @@ -2560,10 +2570,10 @@ static int sdhci_msm_probe(struct platform_device *pdev) /* Vote for max. clk rate for max. performance */ ret = clk_set_rate(msm_host->bus_clk, INT_MAX); if (ret) - goto pltfm_free; + return ret; ret = clk_prepare_enable(msm_host->bus_clk); if (ret) - goto pltfm_free; + return ret; } /* Setup main peripheral bus clock */ @@ -2754,7 +2764,6 @@ static int sdhci_msm_probe(struct platform_device *pdev) if (ret) goto pm_runtime_disable; - pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev); return 0; @@ -2769,8 +2778,6 @@ clk_disable: bus_clk_disable: if (!IS_ERR(msm_host->bus_clk)) clk_disable_unprepare(msm_host->bus_clk); -pltfm_free: - sdhci_pltfm_free(pdev); return ret; } @@ -2792,7 +2799,6 @@ static void sdhci_msm_remove(struct platform_device *pdev) msm_host->bulk_clks); if (!IS_ERR(msm_host->bus_clk)) clk_disable_unprepare(msm_host->bus_clk); - sdhci_pltfm_free(pdev); } static __maybe_unused int sdhci_msm_runtime_suspend(struct device *dev) diff --git a/drivers/mmc/host/sdhci-npcm.c b/drivers/mmc/host/sdhci-npcm.c index bee0585ba5c1..71b635dfdf1d 100644 --- a/drivers/mmc/host/sdhci-npcm.c +++ b/drivers/mmc/host/sdhci-npcm.c @@ -48,8 +48,7 @@ static int npcm_sdhci_probe(struct platform_device *pdev) pltfm_host->clk = devm_clk_get_optional_enabled(dev, NULL); if (IS_ERR(pltfm_host->clk)) { - ret = PTR_ERR(pltfm_host->clk); - goto err_sdhci; + return PTR_ERR(pltfm_host->clk); } caps = sdhci_readl(host, SDHCI_CAPABILITIES); @@ -58,17 +57,9 @@ static int npcm_sdhci_probe(struct platform_device *pdev) ret = mmc_of_parse(host->mmc); if (ret) - goto err_sdhci; + return ret; - ret = sdhci_add_host(host); - if (ret) - goto err_sdhci; - - return 0; - -err_sdhci: - sdhci_pltfm_free(pdev); - return ret; + return sdhci_add_host(host); } static const struct of_device_id npcm_sdhci_of_match[] = { diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index 8c29676ab662..42878474e56e 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -1883,34 +1883,26 @@ static int sdhci_arasan_probe(struct platform_device *pdev) sdhci_arasan->soc_ctl_base = syscon_node_to_regmap(node); of_node_put(node); - if (IS_ERR(sdhci_arasan->soc_ctl_base)) { - ret = dev_err_probe(dev, + if (IS_ERR(sdhci_arasan->soc_ctl_base)) + return dev_err_probe(dev, PTR_ERR(sdhci_arasan->soc_ctl_base), "Can't get syscon\n"); - goto err_pltfm_free; - } } sdhci_get_of_property(pdev); sdhci_arasan->clk_ahb = devm_clk_get(dev, "clk_ahb"); - if (IS_ERR(sdhci_arasan->clk_ahb)) { - ret = dev_err_probe(dev, PTR_ERR(sdhci_arasan->clk_ahb), + if (IS_ERR(sdhci_arasan->clk_ahb)) + return dev_err_probe(dev, PTR_ERR(sdhci_arasan->clk_ahb), "clk_ahb clock not found.\n"); - goto err_pltfm_free; - } clk_xin = devm_clk_get(dev, "clk_xin"); - if (IS_ERR(clk_xin)) { - ret = dev_err_probe(dev, PTR_ERR(clk_xin), "clk_xin clock not found.\n"); - goto err_pltfm_free; - } + if (IS_ERR(clk_xin)) + return dev_err_probe(dev, PTR_ERR(clk_xin), "clk_xin clock not found.\n"); ret = clk_prepare_enable(sdhci_arasan->clk_ahb); - if (ret) { - dev_err(dev, "Unable to enable AHB clock.\n"); - goto err_pltfm_free; - } + if (ret) + return dev_err_probe(dev, ret, "Unable to enable AHB clock.\n"); /* If clock-frequency property is set, use the provided value */ if (pltfm_host->clock && @@ -2029,8 +2021,6 @@ clk_disable_all: clk_disable_unprepare(clk_xin); clk_dis_ahb: clk_disable_unprepare(sdhci_arasan->clk_ahb); -err_pltfm_free: - sdhci_pltfm_free(pdev); return ret; } diff --git a/drivers/mmc/host/sdhci-of-aspeed.c b/drivers/mmc/host/sdhci-of-aspeed.c index d6de010551b9..ca97b01996b1 100644 --- a/drivers/mmc/host/sdhci-of-aspeed.c +++ b/drivers/mmc/host/sdhci-of-aspeed.c @@ -425,10 +425,8 @@ static int aspeed_sdhci_probe(struct platform_device *pdev) return PTR_ERR(pltfm_host->clk); ret = clk_prepare_enable(pltfm_host->clk); - if (ret) { - dev_err(&pdev->dev, "Unable to enable SDIO clock\n"); - goto err_pltfm_free; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "Unable to enable SDIO clock\n"); ret = mmc_of_parse(host->mmc); if (ret) @@ -445,8 +443,6 @@ static int aspeed_sdhci_probe(struct platform_device *pdev) err_sdhci_add: clk_disable_unprepare(pltfm_host->clk); -err_pltfm_free: - sdhci_pltfm_free(pdev); return ret; } @@ -461,8 +457,6 @@ static void aspeed_sdhci_remove(struct platform_device *pdev) sdhci_remove_host(host, 0); clk_disable_unprepare(pltfm_host->clk); - - sdhci_pltfm_free(pdev); } static const struct aspeed_sdhci_pdata ast2400_sdhci_pdata = { diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index 97988ed37467..1ba2effaf376 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -251,9 +251,8 @@ static int sdhci_at91_runtime_suspend(struct device *dev) struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_at91_priv *priv = sdhci_pltfm_priv(pltfm_host); - int ret; - ret = sdhci_runtime_suspend_host(host); + sdhci_runtime_suspend_host(host); if (host->tuning_mode != SDHCI_TUNING_MODE_3) mmc_retune_needed(host->mmc); @@ -262,7 +261,7 @@ static int sdhci_at91_runtime_suspend(struct device *dev) clk_disable_unprepare(priv->hclock); clk_disable_unprepare(priv->mainck); - return ret; + return 0; } static int sdhci_at91_runtime_resume(struct device *dev) @@ -300,7 +299,8 @@ static int sdhci_at91_runtime_resume(struct device *dev) } out: - return sdhci_runtime_resume_host(host, 0); + sdhci_runtime_resume_host(host, 0); + return 0; } #endif /* CONFIG_PM */ @@ -333,32 +333,26 @@ static int sdhci_at91_probe(struct platform_device *pdev) priv->mainck = devm_clk_get(&pdev->dev, "baseclk"); if (IS_ERR(priv->mainck)) { - if (soc_data->baseclk_is_generated_internally) { + if (soc_data->baseclk_is_generated_internally) priv->mainck = NULL; - } else { - dev_err(&pdev->dev, "failed to get baseclk\n"); - ret = PTR_ERR(priv->mainck); - goto sdhci_pltfm_free; - } + else + return dev_err_probe(&pdev->dev, PTR_ERR(priv->mainck), + "failed to get baseclk\n"); } priv->hclock = devm_clk_get(&pdev->dev, "hclock"); - if (IS_ERR(priv->hclock)) { - dev_err(&pdev->dev, "failed to get hclock\n"); - ret = PTR_ERR(priv->hclock); - goto sdhci_pltfm_free; - } + if (IS_ERR(priv->hclock)) + return dev_err_probe(&pdev->dev, PTR_ERR(priv->hclock), + "failed to get hclock\n"); priv->gck = devm_clk_get(&pdev->dev, "multclk"); - if (IS_ERR(priv->gck)) { - dev_err(&pdev->dev, "failed to get multclk\n"); - ret = PTR_ERR(priv->gck); - goto sdhci_pltfm_free; - } + if (IS_ERR(priv->gck)) + return dev_err_probe(&pdev->dev, PTR_ERR(priv->gck), + "failed to get multclk\n"); ret = sdhci_at91_set_clks_presets(&pdev->dev); if (ret) - goto sdhci_pltfm_free; + return ret; priv->restore_needed = false; @@ -438,8 +432,6 @@ clocks_disable_unprepare: clk_disable_unprepare(priv->gck); clk_disable_unprepare(priv->mainck); clk_disable_unprepare(priv->hclock); -sdhci_pltfm_free: - sdhci_pltfm_free(pdev); return ret; } diff --git a/drivers/mmc/host/sdhci-of-dwcmshc.c b/drivers/mmc/host/sdhci-of-dwcmshc.c index a20d03fdd6a9..ee6b1096f709 100644 --- a/drivers/mmc/host/sdhci-of-dwcmshc.c +++ b/drivers/mmc/host/sdhci-of-dwcmshc.c @@ -1387,14 +1387,13 @@ static int dwcmshc_probe(struct platform_device *pdev) if (dev->of_node) { pltfm_host->clk = devm_clk_get(dev, "core"); - if (IS_ERR(pltfm_host->clk)) { - err = PTR_ERR(pltfm_host->clk); - dev_err(dev, "failed to get core clk: %d\n", err); - goto free_pltfm; - } + if (IS_ERR(pltfm_host->clk)) + return dev_err_probe(dev, PTR_ERR(pltfm_host->clk), + "failed to get core clk\n"); + err = clk_prepare_enable(pltfm_host->clk); if (err) - goto free_pltfm; + return err; priv->bus_clk = devm_clk_get(dev, "bus"); if (!IS_ERR(priv->bus_clk)) @@ -1467,8 +1466,6 @@ err_clk: clk_disable_unprepare(pltfm_host->clk); clk_disable_unprepare(priv->bus_clk); clk_bulk_disable_unprepare(priv->num_other_clks, priv->other_clks); -free_pltfm: - sdhci_pltfm_free(pdev); return err; } @@ -1500,7 +1497,6 @@ static void dwcmshc_remove(struct platform_device *pdev) clk_disable_unprepare(pltfm_host->clk); clk_disable_unprepare(priv->bus_clk); clk_bulk_disable_unprepare(priv->num_other_clks, priv->other_clks); - sdhci_pltfm_free(pdev); } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 002d0d59b992..c6ee0099ead0 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -1499,18 +1499,11 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) /* call to generic mmc_of_parse to support additional capabilities */ ret = mmc_of_parse(host->mmc); if (ret) - goto err; + return ret; mmc_of_parse_voltage(host->mmc, &host->ocr_mask); - ret = sdhci_add_host(host); - if (ret) - goto err; - - return 0; - err: - sdhci_pltfm_free(pdev); - return ret; + return sdhci_add_host(host); } static struct platform_driver sdhci_esdhc_driver = { diff --git a/drivers/mmc/host/sdhci-of-k1.c b/drivers/mmc/host/sdhci-of-k1.c new file mode 100644 index 000000000000..0cc97e23a2f9 --- /dev/null +++ b/drivers/mmc/host/sdhci-of-k1.c @@ -0,0 +1,308 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2023-2025 SpacemiT (Hangzhou) Technology Co. Ltd + * Copyright (c) 2025 Yixun Lan <dlan@gentoo.org> + */ + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <linux/init.h> +#include <linux/mmc/card.h> +#include <linux/mmc/host.h> +#include <linux/mmc/mmc.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> + +#include "sdhci.h" +#include "sdhci-pltfm.h" + +#define SPACEMIT_SDHC_MMC_CTRL_REG 0x114 +#define SDHC_MISC_INT_EN BIT(1) +#define SDHC_MISC_INT BIT(2) +#define SDHC_ENHANCE_STROBE_EN BIT(8) +#define SDHC_MMC_HS400 BIT(9) +#define SDHC_MMC_HS200 BIT(10) +#define SDHC_MMC_CARD_MODE BIT(12) + +#define SPACEMIT_SDHC_TX_CFG_REG 0x11C +#define SDHC_TX_INT_CLK_SEL BIT(30) +#define SDHC_TX_MUX_SEL BIT(31) + +#define SPACEMIT_SDHC_PHY_CTRL_REG 0x160 +#define SDHC_PHY_FUNC_EN BIT(0) +#define SDHC_PHY_PLL_LOCK BIT(1) +#define SDHC_HOST_LEGACY_MODE BIT(31) + +#define SPACEMIT_SDHC_PHY_FUNC_REG 0x164 +#define SDHC_PHY_TEST_EN BIT(7) +#define SDHC_HS200_USE_RFIFO BIT(15) + +#define SPACEMIT_SDHC_PHY_DLLCFG 0x168 +#define SDHC_DLL_PREDLY_NUM GENMASK(3, 2) +#define SDHC_DLL_FULLDLY_RANGE GENMASK(5, 4) +#define SDHC_DLL_VREG_CTRL GENMASK(7, 6) +#define SDHC_DLL_ENABLE BIT(31) + +#define SPACEMIT_SDHC_PHY_DLLCFG1 0x16C +#define SDHC_DLL_REG1_CTRL GENMASK(7, 0) +#define SDHC_DLL_REG2_CTRL GENMASK(15, 8) +#define SDHC_DLL_REG3_CTRL GENMASK(23, 16) +#define SDHC_DLL_REG4_CTRL GENMASK(31, 24) + +#define SPACEMIT_SDHC_PHY_DLLSTS 0x170 +#define SDHC_DLL_LOCK_STATE BIT(0) + +#define SPACEMIT_SDHC_PHY_PADCFG_REG 0x178 +#define SDHC_PHY_DRIVE_SEL GENMASK(2, 0) +#define SDHC_RX_BIAS_CTRL BIT(5) + +struct spacemit_sdhci_host { + struct clk *clk_core; + struct clk *clk_io; +}; + +/* All helper functions will update clr/set while preserve rest bits */ +static inline void spacemit_sdhci_setbits(struct sdhci_host *host, u32 val, int reg) +{ + sdhci_writel(host, sdhci_readl(host, reg) | val, reg); +} + +static inline void spacemit_sdhci_clrbits(struct sdhci_host *host, u32 val, int reg) +{ + sdhci_writel(host, sdhci_readl(host, reg) & ~val, reg); +} + +static inline void spacemit_sdhci_clrsetbits(struct sdhci_host *host, u32 clr, u32 set, int reg) +{ + u32 val = sdhci_readl(host, reg); + + val = (val & ~clr) | set; + sdhci_writel(host, val, reg); +} + +static void spacemit_sdhci_reset(struct sdhci_host *host, u8 mask) +{ + sdhci_reset(host, mask); + + if (mask != SDHCI_RESET_ALL) + return; + + spacemit_sdhci_setbits(host, SDHC_PHY_FUNC_EN | SDHC_PHY_PLL_LOCK, + SPACEMIT_SDHC_PHY_CTRL_REG); + + spacemit_sdhci_clrsetbits(host, SDHC_PHY_DRIVE_SEL, + SDHC_RX_BIAS_CTRL | FIELD_PREP(SDHC_PHY_DRIVE_SEL, 4), + SPACEMIT_SDHC_PHY_PADCFG_REG); + + if (!(host->mmc->caps2 & MMC_CAP2_NO_MMC)) + spacemit_sdhci_setbits(host, SDHC_MMC_CARD_MODE, SPACEMIT_SDHC_MMC_CTRL_REG); +} + +static void spacemit_sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned int timing) +{ + if (timing == MMC_TIMING_MMC_HS200) + spacemit_sdhci_setbits(host, SDHC_MMC_HS200, SPACEMIT_SDHC_MMC_CTRL_REG); + + if (timing == MMC_TIMING_MMC_HS400) + spacemit_sdhci_setbits(host, SDHC_MMC_HS400, SPACEMIT_SDHC_MMC_CTRL_REG); + + sdhci_set_uhs_signaling(host, timing); + + if (!(host->mmc->caps2 & MMC_CAP2_NO_SDIO)) + spacemit_sdhci_setbits(host, SDHCI_CTRL_VDD_180, SDHCI_HOST_CONTROL2); +} + +static void spacemit_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) +{ + struct mmc_host *mmc = host->mmc; + + if (mmc->ios.timing <= MMC_TIMING_UHS_SDR50) + spacemit_sdhci_setbits(host, SDHC_TX_INT_CLK_SEL, SPACEMIT_SDHC_TX_CFG_REG); + else + spacemit_sdhci_clrbits(host, SDHC_TX_INT_CLK_SEL, SPACEMIT_SDHC_TX_CFG_REG); + + sdhci_set_clock(host, clock); +}; + +static void spacemit_sdhci_phy_dll_init(struct sdhci_host *host) +{ + u32 state; + int ret; + + spacemit_sdhci_clrsetbits(host, SDHC_DLL_PREDLY_NUM | + SDHC_DLL_FULLDLY_RANGE | + SDHC_DLL_VREG_CTRL, + FIELD_PREP(SDHC_DLL_PREDLY_NUM, 1) | + FIELD_PREP(SDHC_DLL_FULLDLY_RANGE, 1) | + FIELD_PREP(SDHC_DLL_VREG_CTRL, 1), + SPACEMIT_SDHC_PHY_DLLCFG); + + spacemit_sdhci_clrsetbits(host, SDHC_DLL_REG1_CTRL, + FIELD_PREP(SDHC_DLL_REG1_CTRL, 0x92), + SPACEMIT_SDHC_PHY_DLLCFG1); + + spacemit_sdhci_setbits(host, SDHC_DLL_ENABLE, SPACEMIT_SDHC_PHY_DLLCFG); + + ret = readl_poll_timeout(host->ioaddr + SPACEMIT_SDHC_PHY_DLLSTS, state, + state & SDHC_DLL_LOCK_STATE, 2, 100); + if (ret == -ETIMEDOUT) + dev_warn(mmc_dev(host->mmc), "fail to lock phy dll in 100us!\n"); +} + +static void spacemit_sdhci_hs400_enhanced_strobe(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct sdhci_host *host = mmc_priv(mmc); + + if (!ios->enhanced_strobe) { + spacemit_sdhci_clrbits(host, SDHC_ENHANCE_STROBE_EN, SPACEMIT_SDHC_MMC_CTRL_REG); + return; + } + + spacemit_sdhci_setbits(host, SDHC_ENHANCE_STROBE_EN, SPACEMIT_SDHC_MMC_CTRL_REG); + spacemit_sdhci_phy_dll_init(host); +} + +static unsigned int spacemit_sdhci_clk_get_max_clock(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + + return clk_get_rate(pltfm_host->clk); +} + +static int spacemit_sdhci_pre_select_hs400(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + + spacemit_sdhci_setbits(host, SDHC_MMC_HS400, SPACEMIT_SDHC_MMC_CTRL_REG); + + return 0; +} + +static void spacemit_sdhci_post_select_hs400(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + + spacemit_sdhci_phy_dll_init(host); +} + +static void spacemit_sdhci_pre_hs400_to_hs200(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + + spacemit_sdhci_clrbits(host, SDHC_PHY_FUNC_EN | SDHC_PHY_PLL_LOCK, + SPACEMIT_SDHC_PHY_CTRL_REG); + spacemit_sdhci_clrbits(host, SDHC_MMC_HS400 | SDHC_MMC_HS200 | SDHC_ENHANCE_STROBE_EN, + SPACEMIT_SDHC_MMC_CTRL_REG); + spacemit_sdhci_clrbits(host, SDHC_HS200_USE_RFIFO, SPACEMIT_SDHC_PHY_FUNC_REG); + + udelay(5); + + spacemit_sdhci_setbits(host, SDHC_PHY_FUNC_EN | SDHC_PHY_PLL_LOCK, + SPACEMIT_SDHC_PHY_CTRL_REG); +} + +static inline int spacemit_sdhci_get_clocks(struct device *dev, + struct sdhci_pltfm_host *pltfm_host) +{ + struct spacemit_sdhci_host *sdhst = sdhci_pltfm_priv(pltfm_host); + + sdhst->clk_core = devm_clk_get_enabled(dev, "core"); + if (IS_ERR(sdhst->clk_core)) + return -EINVAL; + + sdhst->clk_io = devm_clk_get_enabled(dev, "io"); + if (IS_ERR(sdhst->clk_io)) + return -EINVAL; + + pltfm_host->clk = sdhst->clk_io; + + return 0; +} + +static const struct sdhci_ops spacemit_sdhci_ops = { + .get_max_clock = spacemit_sdhci_clk_get_max_clock, + .reset = spacemit_sdhci_reset, + .set_bus_width = sdhci_set_bus_width, + .set_clock = spacemit_sdhci_set_clock, + .set_uhs_signaling = spacemit_sdhci_set_uhs_signaling, +}; + +static const struct sdhci_pltfm_data spacemit_sdhci_k1_pdata = { + .ops = &spacemit_sdhci_ops, + .quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | + SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | + SDHCI_QUIRK_32BIT_ADMA_SIZE | + SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | + SDHCI_QUIRK_BROKEN_CARD_DETECTION | + SDHCI_QUIRK_BROKEN_TIMEOUT_VAL, + .quirks2 = SDHCI_QUIRK2_BROKEN_64_BIT_DMA | + SDHCI_QUIRK2_PRESET_VALUE_BROKEN, +}; + +static const struct of_device_id spacemit_sdhci_of_match[] = { + { .compatible = "spacemit,k1-sdhci" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, spacemit_sdhci_of_match); + +static int spacemit_sdhci_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct spacemit_sdhci_host *sdhst; + struct sdhci_pltfm_host *pltfm_host; + struct sdhci_host *host; + struct mmc_host_ops *mops; + int ret; + + host = sdhci_pltfm_init(pdev, &spacemit_sdhci_k1_pdata, sizeof(*sdhst)); + if (IS_ERR(host)) + return PTR_ERR(host); + + pltfm_host = sdhci_priv(host); + + ret = mmc_of_parse(host->mmc); + if (ret) + goto err_pltfm; + + sdhci_get_of_property(pdev); + + if (!(host->mmc->caps2 & MMC_CAP2_NO_MMC)) { + mops = &host->mmc_host_ops; + mops->hs400_prepare_ddr = spacemit_sdhci_pre_select_hs400; + mops->hs400_complete = spacemit_sdhci_post_select_hs400; + mops->hs400_downgrade = spacemit_sdhci_pre_hs400_to_hs200; + mops->hs400_enhanced_strobe = spacemit_sdhci_hs400_enhanced_strobe; + } + + host->mmc->caps |= MMC_CAP_NEED_RSP_BUSY; + + ret = spacemit_sdhci_get_clocks(dev, pltfm_host); + if (ret) + goto err_pltfm; + + ret = sdhci_add_host(host); + if (ret) + goto err_pltfm; + + return 0; + +err_pltfm: + return ret; +} + +static struct platform_driver spacemit_sdhci_driver = { + .driver = { + .name = "sdhci-spacemit", + .of_match_table = spacemit_sdhci_of_match, + }, + .probe = spacemit_sdhci_probe, + .remove = sdhci_pltfm_remove, +}; +module_platform_driver(spacemit_sdhci_driver); + +MODULE_DESCRIPTION("SpacemiT SDHCI platform driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/host/sdhci-of-ma35d1.c b/drivers/mmc/host/sdhci-of-ma35d1.c index 1e6d180100ad..287026422616 100644 --- a/drivers/mmc/host/sdhci-of-ma35d1.c +++ b/drivers/mmc/host/sdhci-of-ma35d1.c @@ -211,20 +211,18 @@ static int ma35_probe(struct platform_device *pdev) priv = sdhci_pltfm_priv(pltfm_host); pltfm_host->clk = devm_clk_get_optional_enabled(dev, NULL); - if (IS_ERR(pltfm_host->clk)) { - err = dev_err_probe(dev, PTR_ERR(pltfm_host->clk), "failed to get clk\n"); - goto err_sdhci; - } + if (IS_ERR(pltfm_host->clk)) + return dev_err_probe(dev, PTR_ERR(pltfm_host->clk), + "failed to get clk\n"); err = mmc_of_parse(host->mmc); if (err) - goto err_sdhci; + return err; priv->rst = devm_reset_control_get_exclusive(dev, NULL); - if (IS_ERR(priv->rst)) { - err = dev_err_probe(dev, PTR_ERR(priv->rst), "failed to get reset control\n"); - goto err_sdhci; - } + if (IS_ERR(priv->rst)) + return dev_err_probe(dev, PTR_ERR(priv->rst), + "failed to get reset control\n"); sdhci_get_of_property(pdev); @@ -255,7 +253,7 @@ static int ma35_probe(struct platform_device *pdev) err = sdhci_add_host(host); if (err) - goto err_sdhci; + return err; /* * Split data into chunks of 16 or 8 bytes for transmission. @@ -268,10 +266,6 @@ static int ma35_probe(struct platform_device *pdev) sdhci_writew(host, ctl, MA35_SDHCI_MBIUCTL); return 0; - -err_sdhci: - sdhci_pltfm_free(pdev); - return err; } static void ma35_disable_card_clk(struct sdhci_host *host) @@ -291,7 +285,6 @@ static void ma35_remove(struct platform_device *pdev) sdhci_remove_host(host, 0); ma35_disable_card_clk(host); - sdhci_pltfm_free(pdev); } static const struct of_device_id sdhci_ma35_dt_ids[] = { diff --git a/drivers/mmc/host/sdhci-of-sparx5.c b/drivers/mmc/host/sdhci-of-sparx5.c index d2aa684e786f..b3db1e2c4c0e 100644 --- a/drivers/mmc/host/sdhci-of-sparx5.c +++ b/drivers/mmc/host/sdhci-of-sparx5.c @@ -185,11 +185,9 @@ static int sdhci_sparx5_probe(struct platform_device *pdev) sdhci_sparx5->host = host; pltfm_host->clk = devm_clk_get_enabled(&pdev->dev, "core"); - if (IS_ERR(pltfm_host->clk)) { - ret = PTR_ERR(pltfm_host->clk); - dev_err(&pdev->dev, "failed to get and enable core clk: %d\n", ret); - goto free_pltfm; - } + if (IS_ERR(pltfm_host->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(pltfm_host->clk), + "failed to get and enable core clk\n"); if (!of_property_read_u32(np, "microchip,clock-delay", &value) && (value > 0 && value <= MSHC_DLY_CC_MAX)) @@ -199,14 +197,12 @@ static int sdhci_sparx5_probe(struct platform_device *pdev) ret = mmc_of_parse(host->mmc); if (ret) - goto free_pltfm; + return ret; sdhci_sparx5->cpu_ctrl = syscon_regmap_lookup_by_compatible(syscon); - if (IS_ERR(sdhci_sparx5->cpu_ctrl)) { - dev_err(&pdev->dev, "No CPU syscon regmap !\n"); - ret = PTR_ERR(sdhci_sparx5->cpu_ctrl); - goto free_pltfm; - } + if (IS_ERR(sdhci_sparx5->cpu_ctrl)) + return dev_err_probe(&pdev->dev, PTR_ERR(sdhci_sparx5->cpu_ctrl), + "No CPU syscon regmap !\n"); if (sdhci_sparx5->delay_clock >= 0) sparx5_set_delay(host, sdhci_sparx5->delay_clock); @@ -222,7 +218,7 @@ static int sdhci_sparx5_probe(struct platform_device *pdev) ret = sdhci_add_host(host); if (ret) - goto free_pltfm; + return ret; /* Set AXI bus master to use un-cached access (for DMA) */ if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA) && @@ -235,10 +231,6 @@ static int sdhci_sparx5_probe(struct platform_device *pdev) mmc_hostname(host->mmc), sdhci_readl(host, MSHC2_TYPE)); return ret; - -free_pltfm: - sdhci_pltfm_free(pdev); - return ret; } static const struct of_device_id sdhci_sparx5_of_match[] = { diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 26a9a8b5682a..cdb09605e009 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -1257,7 +1257,7 @@ static int sdhci_omap_probe(struct platform_device *pdev) sdhci_get_of_property(pdev); ret = mmc_of_parse(mmc); if (ret) - goto err_pltfm_free; + return ret; soc = soc_device_match(sdhci_omap_soc_devices); if (soc) { @@ -1270,26 +1270,23 @@ static int sdhci_omap_probe(struct platform_device *pdev) mmc->f_max = 48000000; } - if (!mmc_can_gpio_ro(mmc)) + if (!mmc_host_can_gpio_ro(mmc)) mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT; pltfm_host->clk = devm_clk_get(dev, "fck"); - if (IS_ERR(pltfm_host->clk)) { - ret = PTR_ERR(pltfm_host->clk); - goto err_pltfm_free; - } + if (IS_ERR(pltfm_host->clk)) + return PTR_ERR(pltfm_host->clk); ret = clk_set_rate(pltfm_host->clk, mmc->f_max); - if (ret) { - dev_err(dev, "failed to set clock to %d\n", mmc->f_max); - goto err_pltfm_free; - } + if (ret) + return dev_err_probe(dev, ret, + "failed to set clock to %d\n", mmc->f_max); omap_host->pbias = devm_regulator_get_optional(dev, "pbias"); if (IS_ERR(omap_host->pbias)) { ret = PTR_ERR(omap_host->pbias); if (ret != -ENODEV) - goto err_pltfm_free; + return ret; dev_dbg(dev, "unable to get pbias regulator %d\n", ret); } omap_host->pbias_enabled = false; @@ -1373,7 +1370,6 @@ static int sdhci_omap_probe(struct platform_device *pdev) host->mmc->pm_caps |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ; } - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; @@ -1382,14 +1378,10 @@ err_cleanup_host: sdhci_cleanup_host(host); err_rpm_put: - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); err_rpm_disable: pm_runtime_dont_use_autosuspend(dev); pm_runtime_disable(dev); - -err_pltfm_free: - sdhci_pltfm_free(pdev); return ret; } @@ -1406,7 +1398,6 @@ static void sdhci_omap_remove(struct platform_device *pdev) pm_runtime_put_sync(dev); /* Ensure device gets disabled despite userspace sysfs config */ pm_runtime_force_suspend(dev); - sdhci_pltfm_free(pdev); } #ifdef CONFIG_PM diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 13a84b9309e0..826958992dfe 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -152,18 +152,15 @@ static int sdhci_pci_runtime_suspend_host(struct sdhci_pci_chip *chip) { struct sdhci_pci_slot *slot; struct sdhci_host *host; - int i, ret; - for (i = 0; i < chip->num_slots; i++) { + for (int i = 0; i < chip->num_slots; i++) { slot = chip->slots[i]; if (!slot) continue; host = slot->host; - ret = sdhci_runtime_suspend_host(host); - if (ret) - goto err_pci_runtime_suspend; + sdhci_runtime_suspend_host(host); if (chip->rpm_retune && host->tuning_mode != SDHCI_TUNING_MODE_3) @@ -171,26 +168,18 @@ static int sdhci_pci_runtime_suspend_host(struct sdhci_pci_chip *chip) } return 0; - -err_pci_runtime_suspend: - while (--i >= 0) - sdhci_runtime_resume_host(chip->slots[i]->host, 0); - return ret; } static int sdhci_pci_runtime_resume_host(struct sdhci_pci_chip *chip) { struct sdhci_pci_slot *slot; - int i, ret; - for (i = 0; i < chip->num_slots; i++) { + for (int i = 0; i < chip->num_slots; i++) { slot = chip->slots[i]; if (!slot) continue; - ret = sdhci_runtime_resume_host(slot->host, 0); - if (ret) - return ret; + sdhci_runtime_resume_host(slot->host, 0); } return 0; @@ -913,7 +902,8 @@ static bool glk_broken_cqhci(struct sdhci_pci_slot *slot) { return slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_GLK_EMMC && (dmi_match(DMI_BIOS_VENDOR, "LENOVO") || - dmi_match(DMI_SYS_VENDOR, "IRBIS")); + dmi_match(DMI_SYS_VENDOR, "IRBIS") || + dmi_match(DMI_SYS_VENDOR, "Positivo Tecnologia SA")); } static bool jsl_broken_hs400es(struct sdhci_pci_slot *slot) @@ -2173,7 +2163,7 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( ret = pcim_iomap_regions(pdev, BIT(bar), mmc_hostname(host->mmc)); if (ret) { dev_err(&pdev->dev, "cannot request region\n"); - goto cleanup; + return ERR_PTR(ret); } host->ioaddr = pcim_iomap_table(pdev)[bar]; @@ -2181,7 +2171,7 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( if (chip->fixes && chip->fixes->probe_slot) { ret = chip->fixes->probe_slot(slot); if (ret) - goto cleanup; + return ERR_PTR(ret); } host->mmc->pm_caps = MMC_PM_KEEP_POWER; @@ -2242,9 +2232,6 @@ remove: if (chip->fixes && chip->fixes->remove_slot) chip->fixes->remove_slot(slot, 0); -cleanup: - sdhci_free_host(host); - return ERR_PTR(ret); } @@ -2265,8 +2252,6 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot) if (slot->chip->fixes && slot->chip->fixes->remove_slot) slot->chip->fixes->remove_slot(slot, dead); - - sdhci_free_host(slot->host); } int sdhci_pci_uhs2_add_host(struct sdhci_pci_slot *slot) diff --git a/drivers/mmc/host/sdhci-pic32.c b/drivers/mmc/host/sdhci-pic32.c index d6a299f49900..7ddac0befed8 100644 --- a/drivers/mmc/host/sdhci-pic32.c +++ b/drivers/mmc/host/sdhci-pic32.c @@ -157,20 +157,20 @@ static int pic32_sdhci_probe(struct platform_device *pdev) ret = plat_data->setup_dma(ADMA_FIFO_RD_THSHLD, ADMA_FIFO_WR_THSHLD); if (ret) - goto err_host; + goto err; } sdhci_pdata->sys_clk = devm_clk_get(&pdev->dev, "sys_clk"); if (IS_ERR(sdhci_pdata->sys_clk)) { ret = PTR_ERR(sdhci_pdata->sys_clk); dev_err(&pdev->dev, "Error getting clock\n"); - goto err_host; + goto err; } ret = clk_prepare_enable(sdhci_pdata->sys_clk); if (ret) { dev_err(&pdev->dev, "Error enabling clock\n"); - goto err_host; + goto err; } sdhci_pdata->base_clk = devm_clk_get(&pdev->dev, "base_clk"); @@ -203,8 +203,6 @@ err_base_clk: clk_disable_unprepare(sdhci_pdata->base_clk); err_sys_clk: clk_disable_unprepare(sdhci_pdata->sys_clk); -err_host: - sdhci_pltfm_free(pdev); err: dev_err(&pdev->dev, "pic32-sdhci probe failed: %d\n", ret); return ret; @@ -220,7 +218,6 @@ static void pic32_sdhci_remove(struct platform_device *pdev) sdhci_remove_host(host, scratch == (u32)~0); clk_disable_unprepare(sdhci_pdata->base_clk); clk_disable_unprepare(sdhci_pdata->sys_clk); - sdhci_pltfm_free(pdev); } static const struct of_device_id pic32_sdhci_id_table[] = { diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index 62753d72198a..7f6ac636f040 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -146,20 +146,11 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(sdhci_pltfm_init); -void sdhci_pltfm_free(struct platform_device *pdev) -{ - struct sdhci_host *host = platform_get_drvdata(pdev); - - sdhci_free_host(host); -} -EXPORT_SYMBOL_GPL(sdhci_pltfm_free); - int sdhci_pltfm_init_and_add_host(struct platform_device *pdev, const struct sdhci_pltfm_data *pdata, size_t priv_size) { struct sdhci_host *host; - int ret = 0; host = sdhci_pltfm_init(pdev, pdata, priv_size); if (IS_ERR(host)) @@ -167,11 +158,7 @@ int sdhci_pltfm_init_and_add_host(struct platform_device *pdev, sdhci_get_property(pdev); - ret = sdhci_add_host(host); - if (ret) - sdhci_pltfm_free(pdev); - - return ret; + return sdhci_add_host(host); } EXPORT_SYMBOL_GPL(sdhci_pltfm_init_and_add_host); @@ -181,7 +168,6 @@ void sdhci_pltfm_remove(struct platform_device *pdev) int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); sdhci_remove_host(host, dead); - sdhci_pltfm_free(pdev); } EXPORT_SYMBOL_GPL(sdhci_pltfm_remove); diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h index b81d5b0fd616..9c32e8a289d6 100644 --- a/drivers/mmc/host/sdhci-pltfm.h +++ b/drivers/mmc/host/sdhci-pltfm.h @@ -97,7 +97,6 @@ static inline void sdhci_get_of_property(struct platform_device *pdev) extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, const struct sdhci_pltfm_data *pdata, size_t priv_size); -extern void sdhci_pltfm_free(struct platform_device *pdev); extern int sdhci_pltfm_init_and_add_host(struct platform_device *pdev, const struct sdhci_pltfm_data *pdata, diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index 45b6f0891c47..76346353dc55 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -258,7 +258,6 @@ static int sdhci_pxav2_probe(struct platform_device *pdev) struct sdhci_host *host = NULL; const struct sdhci_pxa_variant *variant; - int ret; struct clk *clk, *clk_core; host = sdhci_pltfm_init(pdev, NULL, sizeof(*pxav2_host)); @@ -271,19 +270,14 @@ static int sdhci_pxav2_probe(struct platform_device *pdev) clk = devm_clk_get_optional_enabled(dev, "io"); if (!clk) clk = devm_clk_get_enabled(dev, NULL); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - dev_err_probe(dev, ret, "failed to get io clock\n"); - goto free; - } + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "failed to get io clock\n"); pltfm_host->clk = clk; clk_core = devm_clk_get_optional_enabled(dev, "core"); - if (IS_ERR(clk_core)) { - ret = PTR_ERR(clk_core); - dev_err_probe(dev, ret, "failed to enable core clock\n"); - goto free; - } + if (IS_ERR(clk_core)) + return dev_err_probe(dev, PTR_ERR(clk_core), + "failed to enable core clock\n"); host->quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL @@ -332,15 +326,7 @@ static int sdhci_pxav2_probe(struct platform_device *pdev) pxav2_host->pinctrl = NULL; } - ret = sdhci_add_host(host); - if (ret) - goto free; - - return 0; - -free: - sdhci_pltfm_free(pdev); - return ret; + return sdhci_add_host(host); } static struct platform_driver sdhci_pxav2_driver = { diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index 3fb56face3d8..1371960e34eb 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -389,8 +389,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) pxa->clk_io = devm_clk_get(dev, NULL); if (IS_ERR(pxa->clk_io)) { dev_err(dev, "failed to get io clock\n"); - ret = PTR_ERR(pxa->clk_io); - goto err_clk_get; + return PTR_ERR(pxa->clk_io); } pltfm_host->clk = pxa->clk_io; clk_prepare_enable(pxa->clk_io); @@ -466,8 +465,6 @@ err_of_parse: err_mbus_win: clk_disable_unprepare(pxa->clk_io); clk_disable_unprepare(pxa->clk_core); -err_clk_get: - sdhci_pltfm_free(pdev); return ret; } @@ -485,8 +482,6 @@ static void sdhci_pxav3_remove(struct platform_device *pdev) clk_disable_unprepare(pxa->clk_io); clk_disable_unprepare(pxa->clk_core); - - sdhci_pltfm_free(pdev); } #ifdef CONFIG_PM_SLEEP @@ -499,7 +494,6 @@ static int sdhci_pxav3_suspend(struct device *dev) if (host->tuning_mode != SDHCI_TUNING_MODE_3) mmc_retune_needed(host->mmc); ret = sdhci_suspend_host(host); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -512,7 +506,6 @@ static int sdhci_pxav3_resume(struct device *dev) pm_runtime_get_sync(dev); ret = sdhci_resume_host(host); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -525,11 +518,8 @@ static int sdhci_pxav3_runtime_suspend(struct device *dev) struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pxa *pxa = sdhci_pltfm_priv(pltfm_host); - int ret; - ret = sdhci_runtime_suspend_host(host); - if (ret) - return ret; + sdhci_runtime_suspend_host(host); if (host->tuning_mode != SDHCI_TUNING_MODE_3) mmc_retune_needed(host->mmc); @@ -551,7 +541,8 @@ static int sdhci_pxav3_runtime_resume(struct device *dev) if (!IS_ERR(pxa->clk_core)) clk_prepare_enable(pxa->clk_core); - return sdhci_runtime_resume_host(host, 0); + sdhci_runtime_resume_host(host, 0); + return 0; } #endif diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index bdf4dc0d6b77..40857fc2e21b 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -507,15 +507,13 @@ static int sdhci_s3c_probe(struct platform_device *pdev) sc = sdhci_priv(host); pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) { - ret = -ENOMEM; - goto err_pdata_io_clk; - } + if (!pdata) + return -ENOMEM; if (pdev->dev.of_node) { ret = sdhci_s3c_parse_dt(&pdev->dev, host, pdata); if (ret) - goto err_pdata_io_clk; + return ret; } else { memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata)); } @@ -532,8 +530,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev) sc->clk_io = devm_clk_get(dev, "hsmmc"); if (IS_ERR(sc->clk_io)) { dev_err(dev, "failed to get io clock\n"); - ret = PTR_ERR(sc->clk_io); - goto err_pdata_io_clk; + return PTR_ERR(sc->clk_io); } /* enable the local io clock and keep it running for the moment. */ @@ -661,9 +658,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev) err_no_busclks: clk_disable_unprepare(sc->clk_io); - err_pdata_io_clk: - sdhci_free_host(host); - return ret; } @@ -685,8 +679,6 @@ static void sdhci_s3c_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); clk_disable_unprepare(sc->clk_io); - - sdhci_free_host(host); } #ifdef CONFIG_PM_SLEEP @@ -714,9 +706,8 @@ static int sdhci_s3c_runtime_suspend(struct device *dev) struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_s3c *ourhost = to_s3c(host); struct clk *busclk = ourhost->clk_io; - int ret; - ret = sdhci_runtime_suspend_host(host); + sdhci_runtime_suspend_host(host); if (host->tuning_mode != SDHCI_TUNING_MODE_3) mmc_retune_needed(host->mmc); @@ -724,7 +715,7 @@ static int sdhci_s3c_runtime_suspend(struct device *dev) if (ourhost->cur_clk >= 0) clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]); clk_disable_unprepare(busclk); - return ret; + return 0; } static int sdhci_s3c_runtime_resume(struct device *dev) @@ -732,13 +723,12 @@ static int sdhci_s3c_runtime_resume(struct device *dev) struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_s3c *ourhost = to_s3c(host); struct clk *busclk = ourhost->clk_io; - int ret; clk_prepare_enable(busclk); if (ourhost->cur_clk >= 0) clk_prepare_enable(ourhost->clk_bus[ourhost->cur_clk]); - ret = sdhci_runtime_resume_host(host, 0); - return ret; + sdhci_runtime_resume_host(host, 0); + return 0; } #endif diff --git a/drivers/mmc/host/sdhci-spear.c b/drivers/mmc/host/sdhci-spear.c index 770dc12b9ae9..fa0f8aeb7ee0 100644 --- a/drivers/mmc/host/sdhci-spear.c +++ b/drivers/mmc/host/sdhci-spear.c @@ -59,7 +59,7 @@ static int sdhci_probe(struct platform_device *pdev) if (IS_ERR(host->ioaddr)) { ret = PTR_ERR(host->ioaddr); dev_dbg(&pdev->dev, "unable to map iomem: %d\n", ret); - goto err_host; + goto err; } host->hw_name = "sdhci"; @@ -67,7 +67,7 @@ static int sdhci_probe(struct platform_device *pdev) host->irq = platform_get_irq(pdev, 0); if (host->irq < 0) { ret = host->irq; - goto err_host; + goto err; } host->quirks = SDHCI_QUIRK_BROKEN_ADMA; @@ -78,13 +78,13 @@ static int sdhci_probe(struct platform_device *pdev) if (IS_ERR(sdhci->clk)) { ret = PTR_ERR(sdhci->clk); dev_dbg(&pdev->dev, "Error getting clock\n"); - goto err_host; + goto err; } ret = clk_prepare_enable(sdhci->clk); if (ret) { dev_dbg(&pdev->dev, "Error enabling clock\n"); - goto err_host; + goto err; } ret = clk_set_rate(sdhci->clk, 50000000); @@ -110,8 +110,6 @@ static int sdhci_probe(struct platform_device *pdev) disable_clk: clk_disable_unprepare(sdhci->clk); -err_host: - sdhci_free_host(host); err: dev_err(&pdev->dev, "spear-sdhci probe failed: %d\n", ret); return ret; @@ -130,7 +128,6 @@ static void sdhci_remove(struct platform_device *pdev) sdhci_remove_host(host, dead); clk_disable_unprepare(sdhci->clk); - sdhci_free_host(host); } #ifdef CONFIG_PM_SLEEP diff --git a/drivers/mmc/host/sdhci-sprd.c b/drivers/mmc/host/sdhci-sprd.c index db5e253b0f79..fe2fe52b23b2 100644 --- a/drivers/mmc/host/sdhci-sprd.c +++ b/drivers/mmc/host/sdhci-sprd.c @@ -764,7 +764,7 @@ static int sdhci_sprd_probe(struct platform_device *pdev) ret = mmc_of_parse(host->mmc); if (ret) - goto pltfm_free; + return ret; if (!mmc_card_is_removable(host->mmc)) host->mmc_host_ops.request_atomic = sdhci_sprd_request_atomic; @@ -778,34 +778,26 @@ static int sdhci_sprd_probe(struct platform_device *pdev) if (!IS_ERR(sprd_host->pinctrl)) { sprd_host->pins_uhs = pinctrl_lookup_state(sprd_host->pinctrl, "state_uhs"); - if (IS_ERR(sprd_host->pins_uhs)) { - ret = PTR_ERR(sprd_host->pins_uhs); - goto pltfm_free; - } + if (IS_ERR(sprd_host->pins_uhs)) + return PTR_ERR(sprd_host->pins_uhs); sprd_host->pins_default = pinctrl_lookup_state(sprd_host->pinctrl, "default"); - if (IS_ERR(sprd_host->pins_default)) { - ret = PTR_ERR(sprd_host->pins_default); - goto pltfm_free; - } + if (IS_ERR(sprd_host->pins_default)) + return PTR_ERR(sprd_host->pins_default); } clk = devm_clk_get(&pdev->dev, "sdio"); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - goto pltfm_free; - } + if (IS_ERR(clk)) + return PTR_ERR(clk); sprd_host->clk_sdio = clk; sprd_host->base_rate = clk_get_rate(sprd_host->clk_sdio); if (!sprd_host->base_rate) sprd_host->base_rate = SDHCI_SPRD_CLK_DEF_RATE; clk = devm_clk_get(&pdev->dev, "enable"); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - goto pltfm_free; - } + if (IS_ERR(clk)) + return PTR_ERR(clk); sprd_host->clk_enable = clk; clk = devm_clk_get(&pdev->dev, "2x_enable"); @@ -814,7 +806,7 @@ static int sdhci_sprd_probe(struct platform_device *pdev) ret = clk_prepare_enable(sprd_host->clk_sdio); if (ret) - goto pltfm_free; + return ret; ret = clk_prepare_enable(sprd_host->clk_enable); if (ret) @@ -871,7 +863,6 @@ static int sdhci_sprd_probe(struct platform_device *pdev) if (ret) goto err_cleanup_host; - pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev); return 0; @@ -891,9 +882,6 @@ clk_disable2: clk_disable: clk_disable_unprepare(sprd_host->clk_sdio); - -pltfm_free: - sdhci_pltfm_free(pdev); return ret; } @@ -907,8 +895,6 @@ static void sdhci_sprd_remove(struct platform_device *pdev) clk_disable_unprepare(sprd_host->clk_sdio); clk_disable_unprepare(sprd_host->clk_enable); clk_disable_unprepare(sprd_host->clk_2x_enable); - - sdhci_pltfm_free(pdev); } static const struct of_device_id sdhci_sprd_of_match[] = { diff --git a/drivers/mmc/host/sdhci-st.c b/drivers/mmc/host/sdhci-st.c index 4973e08a98f8..9157342ff7a4 100644 --- a/drivers/mmc/host/sdhci-st.c +++ b/drivers/mmc/host/sdhci-st.c @@ -380,13 +380,13 @@ static int sdhci_st_probe(struct platform_device *pdev) ret = mmc_of_parse(host->mmc); if (ret) { dev_err(&pdev->dev, "Failed mmc_of_parse\n"); - goto err_of; + goto err_pltfm_init; } ret = clk_prepare_enable(clk); if (ret) { dev_err(&pdev->dev, "Failed to prepare clock\n"); - goto err_of; + goto err_pltfm_init; } ret = clk_prepare_enable(icnclk); @@ -423,8 +423,6 @@ err_out: clk_disable_unprepare(icnclk); err_icnclk: clk_disable_unprepare(clk); -err_of: - sdhci_pltfm_free(pdev); err_pltfm_init: reset_control_assert(rstc); diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index b2f5c3f8b839..c811297185d8 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -1693,7 +1693,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev) rc = mmc_of_parse(host->mmc); if (rc) - goto err_parse_dt; + return rc; if (tegra_host->soc_data->nvquirks & NVQUIRK_ENABLE_DDR50) host->mmc->caps |= MMC_CAP_1_8V_DDR; @@ -1739,7 +1739,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev) if (IS_ERR(clk)) { rc = PTR_ERR(clk); if (rc == -EPROBE_DEFER) - goto err_power_req; + return rc; dev_warn(&pdev->dev, "failed to get tmclk: %d\n", rc); clk = NULL; @@ -1750,7 +1750,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev) if (rc) { dev_err(&pdev->dev, "failed to enable tmclk: %d\n", rc); - goto err_power_req; + return rc; } tegra_host->tmclk = clk; @@ -1811,8 +1811,6 @@ err_rst_get: err_clk_get: clk_disable_unprepare(tegra_host->tmclk); err_power_req: -err_parse_dt: - sdhci_pltfm_free(pdev); return rc; } @@ -1831,7 +1829,6 @@ static void sdhci_tegra_remove(struct platform_device *pdev) pm_runtime_force_suspend(&pdev->dev); clk_disable_unprepare(tegra_host->tmclk); - sdhci_pltfm_free(pdev); } static int __maybe_unused sdhci_tegra_runtime_suspend(struct device *dev) diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c index c53b64d50c0d..0efeb9d0c376 100644 --- a/drivers/mmc/host/sdhci-uhs2.c +++ b/drivers/mmc/host/sdhci-uhs2.c @@ -99,8 +99,8 @@ void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask) /* hw clears the bit when it's done */ if (read_poll_timeout_atomic(sdhci_readw, val, !(val & mask), 10, UHS2_RESET_TIMEOUT_100MS, true, host, SDHCI_UHS2_SW_RESET)) { - pr_warn("%s: %s: Reset 0x%x never completed. %s: clean reset bit.\n", __func__, - mmc_hostname(host->mmc), (int)mask, mmc_hostname(host->mmc)); + pr_debug("%s: %s: Reset 0x%x never completed. %s: clean reset bit.\n", __func__, + mmc_hostname(host->mmc), (int)mask, mmc_hostname(host->mmc)); sdhci_writeb(host, 0, SDHCI_UHS2_SW_RESET); return; } @@ -335,8 +335,8 @@ static int sdhci_uhs2_interface_detect(struct sdhci_host *host) if (read_poll_timeout(sdhci_readl, val, (val & SDHCI_UHS2_IF_DETECT), 100, UHS2_INTERFACE_DETECT_TIMEOUT_100MS, true, host, SDHCI_PRESENT_STATE)) { - pr_warn("%s: not detect UHS2 interface in 100ms.\n", mmc_hostname(host->mmc)); - sdhci_dumpregs(host); + pr_debug("%s: not detect UHS2 interface in 100ms.\n", mmc_hostname(host->mmc)); + sdhci_dbg_dumpregs(host, "UHS2 interface detect timeout in 100ms"); return -EIO; } @@ -345,8 +345,8 @@ static int sdhci_uhs2_interface_detect(struct sdhci_host *host) if (read_poll_timeout(sdhci_readl, val, (val & SDHCI_UHS2_LANE_SYNC), 100, UHS2_LANE_SYNC_TIMEOUT_150MS, true, host, SDHCI_PRESENT_STATE)) { - pr_warn("%s: UHS2 Lane sync fail in 150ms.\n", mmc_hostname(host->mmc)); - sdhci_dumpregs(host); + pr_debug("%s: UHS2 Lane sync fail in 150ms.\n", mmc_hostname(host->mmc)); + sdhci_dbg_dumpregs(host, "UHS2 Lane sync fail in 150ms"); return -EIO; } @@ -417,12 +417,12 @@ static int sdhci_uhs2_do_detect_init(struct mmc_host *mmc) host->ops->uhs2_pre_detect_init(host); if (sdhci_uhs2_interface_detect(host)) { - pr_warn("%s: cannot detect UHS2 interface.\n", mmc_hostname(host->mmc)); + pr_debug("%s: cannot detect UHS2 interface.\n", mmc_hostname(host->mmc)); return -EIO; } if (sdhci_uhs2_init(host)) { - pr_warn("%s: UHS2 init fail.\n", mmc_hostname(host->mmc)); + pr_debug("%s: UHS2 init fail.\n", mmc_hostname(host->mmc)); return -EIO; } @@ -504,8 +504,8 @@ static int sdhci_uhs2_check_dormant(struct sdhci_host *host) if (read_poll_timeout(sdhci_readl, val, (val & SDHCI_UHS2_IN_DORMANT_STATE), 100, UHS2_CHECK_DORMANT_TIMEOUT_100MS, true, host, SDHCI_PRESENT_STATE)) { - pr_warn("%s: UHS2 IN_DORMANT fail in 100ms.\n", mmc_hostname(host->mmc)); - sdhci_dumpregs(host); + pr_debug("%s: UHS2 IN_DORMANT fail in 100ms.\n", mmc_hostname(host->mmc)); + sdhci_dbg_dumpregs(host, "UHS2 IN_DORMANT fail in 100ms"); return -EIO; } return 0; diff --git a/drivers/mmc/host/sdhci-xenon.c b/drivers/mmc/host/sdhci-xenon.c index 098f0ea45cbe..b12bee8342bd 100644 --- a/drivers/mmc/host/sdhci-xenon.c +++ b/drivers/mmc/host/sdhci-xenon.c @@ -532,14 +532,13 @@ static int xenon_probe(struct platform_device *pdev) if (dev->of_node) { pltfm_host->clk = devm_clk_get(&pdev->dev, "core"); - if (IS_ERR(pltfm_host->clk)) { - err = PTR_ERR(pltfm_host->clk); - dev_err(&pdev->dev, "Failed to setup input clk: %d\n", err); - goto free_pltfm; - } + if (IS_ERR(pltfm_host->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(pltfm_host->clk), + "Failed to setup input clk.\n"); + err = clk_prepare_enable(pltfm_host->clk); if (err) - goto free_pltfm; + return err; priv->axi_clk = devm_clk_get(&pdev->dev, "axi"); if (IS_ERR(priv->axi_clk)) { @@ -603,8 +602,6 @@ err_clk_axi: clk_disable_unprepare(priv->axi_clk); err_clk: clk_disable_unprepare(pltfm_host->clk); -free_pltfm: - sdhci_pltfm_free(pdev); return err; } @@ -623,8 +620,6 @@ static void xenon_remove(struct platform_device *pdev) xenon_sdhc_unprepare(host); clk_disable_unprepare(priv->axi_clk); clk_disable_unprepare(pltfm_host->clk); - - sdhci_pltfm_free(pdev); } #ifdef CONFIG_PM_SLEEP @@ -648,11 +643,8 @@ static int xenon_runtime_suspend(struct device *dev) struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host); - int ret; - ret = sdhci_runtime_suspend_host(host); - if (ret) - return ret; + sdhci_runtime_suspend_host(host); if (host->tuning_mode != SDHCI_TUNING_MODE_3) mmc_retune_needed(host->mmc); @@ -687,9 +679,7 @@ static int xenon_runtime_resume(struct device *dev) priv->restore_needed = false; } - ret = sdhci_runtime_resume_host(host, 0); - if (ret) - goto out; + sdhci_runtime_resume_host(host, 0); return 0; out: clk_disable_unprepare(pltfm_host->clk); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 5f78be7ae16d..3a17821efa5c 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -158,7 +158,7 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable) u32 present; if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) || - !mmc_card_is_removable(host->mmc) || mmc_can_gpio_cd(host->mmc)) + !mmc_card_is_removable(host->mmc) || mmc_host_can_gpio_cd(host->mmc)) return; if (enable) { @@ -2065,15 +2065,10 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) host->mmc->actual_clock = 0; - clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); - if (clk & SDHCI_CLOCK_CARD_EN) - sdhci_writew(host, clk & ~SDHCI_CLOCK_CARD_EN, - SDHCI_CLOCK_CONTROL); + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); - if (clock == 0) { - sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + if (clock == 0) return; - } clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); sdhci_enable_clk(host, clk); @@ -2571,7 +2566,7 @@ int sdhci_get_ro(struct mmc_host *mmc) is_readonly = 0; } else if (host->ops->get_ro) { is_readonly = host->ops->get_ro(host); - } else if (mmc_can_gpio_ro(mmc)) { + } else if (mmc_host_can_gpio_ro(mmc)) { is_readonly = mmc_gpio_get_ro(mmc); /* Do not invert twice */ allow_invert = !(mmc->caps2 & MMC_CAP2_RO_ACTIVE_HIGH); @@ -3245,7 +3240,7 @@ static void sdhci_timeout_timer(struct timer_list *t) struct sdhci_host *host; unsigned long flags; - host = from_timer(host, t, timer); + host = timer_container_of(host, t, timer); spin_lock_irqsave(&host->lock, flags); @@ -3267,7 +3262,7 @@ static void sdhci_timeout_data_timer(struct timer_list *t) struct sdhci_host *host; unsigned long flags; - host = from_timer(host, t, data_timer); + host = timer_container_of(host, t, data_timer); spin_lock_irqsave(&host->lock, flags); @@ -3744,7 +3739,7 @@ static bool sdhci_cd_irq_can_wakeup(struct sdhci_host *host) { return mmc_card_is_removable(host->mmc) && !(host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) && - !mmc_can_gpio_cd(host->mmc); + !mmc_host_can_gpio_cd(host->mmc); } /* @@ -3755,7 +3750,7 @@ static bool sdhci_cd_irq_can_wakeup(struct sdhci_host *host) * sdhci_disable_irq_wakeups() since it will be set by * sdhci_enable_card_detection() or sdhci_init(). */ -static bool sdhci_enable_irq_wakeups(struct sdhci_host *host) +bool sdhci_enable_irq_wakeups(struct sdhci_host *host) { u8 mask = SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE | SDHCI_WAKE_ON_INT; @@ -3787,8 +3782,9 @@ static bool sdhci_enable_irq_wakeups(struct sdhci_host *host) return host->irq_wake_enabled; } +EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups); -static void sdhci_disable_irq_wakeups(struct sdhci_host *host) +void sdhci_disable_irq_wakeups(struct sdhci_host *host) { u8 val; u8 mask = SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE @@ -3802,6 +3798,7 @@ static void sdhci_disable_irq_wakeups(struct sdhci_host *host) host->irq_wake_enabled = false; } +EXPORT_SYMBOL_GPL(sdhci_disable_irq_wakeups); int sdhci_suspend_host(struct sdhci_host *host) { @@ -3861,7 +3858,7 @@ int sdhci_resume_host(struct sdhci_host *host) EXPORT_SYMBOL_GPL(sdhci_resume_host); -int sdhci_runtime_suspend_host(struct sdhci_host *host) +void sdhci_runtime_suspend_host(struct sdhci_host *host) { unsigned long flags; @@ -3878,12 +3875,10 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host) spin_lock_irqsave(&host->lock, flags); host->runtime_suspended = true; spin_unlock_irqrestore(&host->lock, flags); - - return 0; } EXPORT_SYMBOL_GPL(sdhci_runtime_suspend_host); -int sdhci_runtime_resume_host(struct sdhci_host *host, int soft_reset) +void sdhci_runtime_resume_host(struct sdhci_host *host, int soft_reset) { struct mmc_host *mmc = host->mmc; unsigned long flags; @@ -3929,8 +3924,6 @@ int sdhci_runtime_resume_host(struct sdhci_host *host, int soft_reset) sdhci_enable_card_detection(host); spin_unlock_irqrestore(&host->lock, flags); - - return 0; } EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host); @@ -4074,7 +4067,7 @@ struct sdhci_host *sdhci_alloc_host(struct device *dev, WARN_ON(dev == NULL); - mmc = mmc_alloc_host(sizeof(struct sdhci_host) + priv_size, dev); + mmc = devm_mmc_alloc_host(dev, sizeof(struct sdhci_host) + priv_size); if (!mmc) return ERR_PTR(-ENOMEM); @@ -4998,13 +4991,6 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) EXPORT_SYMBOL_GPL(sdhci_remove_host); -void sdhci_free_host(struct sdhci_host *host) -{ - mmc_free_host(host->mmc); -} - -EXPORT_SYMBOL_GPL(sdhci_free_host); - /*****************************************************************************\ * * * Driver init/exit * diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index cd0e35a80542..58fcbeaf281e 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -811,7 +811,6 @@ static inline u8 sdhci_readb(struct sdhci_host *host, int reg) #endif /* CONFIG_MMC_SDHCI_IO_ACCESSORS */ struct sdhci_host *sdhci_alloc_host(struct device *dev, size_t priv_size); -void sdhci_free_host(struct sdhci_host *host); static inline void *sdhci_priv(struct sdhci_host *host) { @@ -875,10 +874,12 @@ void sdhci_adma_write_desc(struct sdhci_host *host, void **desc, dma_addr_t addr, int len, unsigned int cmd); #ifdef CONFIG_PM +bool sdhci_enable_irq_wakeups(struct sdhci_host *host); +void sdhci_disable_irq_wakeups(struct sdhci_host *host); int sdhci_suspend_host(struct sdhci_host *host); int sdhci_resume_host(struct sdhci_host *host); -int sdhci_runtime_suspend_host(struct sdhci_host *host); -int sdhci_runtime_resume_host(struct sdhci_host *host, int soft_reset); +void sdhci_runtime_suspend_host(struct sdhci_host *host); +void sdhci_runtime_resume_host(struct sdhci_host *host, int soft_reset); #endif void sdhci_cqe_enable(struct mmc_host *mmc); @@ -898,4 +899,20 @@ void sdhci_switch_external_dma(struct sdhci_host *host, bool en); void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable); void __sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd); +#if defined(CONFIG_DYNAMIC_DEBUG) || \ + (defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE)) +#define SDHCI_DBG_ANYWAY 0 +#elif defined(DEBUG) +#define SDHCI_DBG_ANYWAY 1 +#else +#define SDHCI_DBG_ANYWAY 0 +#endif + +#define sdhci_dbg_dumpregs(host, fmt) \ +do { \ + DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ + if (DYNAMIC_DEBUG_BRANCH(descriptor) || SDHCI_DBG_ANYWAY) \ + sdhci_dumpregs(host); \ +} while (0) + #endif /* __SDHCI_HW_H */ diff --git a/drivers/mmc/host/sdhci_am654.c b/drivers/mmc/host/sdhci_am654.c index 73385ff4c0f3..e4fc345be7e5 100644 --- a/drivers/mmc/host/sdhci_am654.c +++ b/drivers/mmc/host/sdhci_am654.c @@ -613,7 +613,8 @@ static const struct sdhci_ops sdhci_am654_ops = { static const struct sdhci_pltfm_data sdhci_am654_pdata = { .ops = &sdhci_am654_ops, .quirks = SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12, - .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_DISABLE_HW_TIMEOUT, }; static const struct sdhci_am654_driver_data sdhci_am654_sr1_drvdata = { @@ -643,7 +644,8 @@ static const struct sdhci_ops sdhci_j721e_8bit_ops = { static const struct sdhci_pltfm_data sdhci_j721e_8bit_pdata = { .ops = &sdhci_j721e_8bit_ops, .quirks = SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12, - .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_DISABLE_HW_TIMEOUT, }; static const struct sdhci_am654_driver_data sdhci_j721e_8bit_drvdata = { @@ -667,7 +669,8 @@ static const struct sdhci_ops sdhci_j721e_4bit_ops = { static const struct sdhci_pltfm_data sdhci_j721e_4bit_pdata = { .ops = &sdhci_j721e_4bit_ops, .quirks = SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12, - .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | + SDHCI_QUIRK2_DISABLE_HW_TIMEOUT, }; static const struct sdhci_am654_driver_data sdhci_j721e_4bit_drvdata = { @@ -942,35 +945,30 @@ static int sdhci_am654_probe(struct platform_device *pdev) clk_xin = devm_clk_get(dev, "clk_xin"); if (IS_ERR(clk_xin)) { dev_err(dev, "clk_xin clock not found.\n"); - ret = PTR_ERR(clk_xin); - goto err_pltfm_free; + return PTR_ERR(clk_xin); } pltfm_host->clk = clk_xin; base = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(base)) { - ret = PTR_ERR(base); - goto err_pltfm_free; + return PTR_ERR(base); } sdhci_am654->base = devm_regmap_init_mmio(dev, base, &sdhci_am654_regmap_config); if (IS_ERR(sdhci_am654->base)) { dev_err(dev, "Failed to initialize regmap\n"); - ret = PTR_ERR(sdhci_am654->base); - goto err_pltfm_free; + return PTR_ERR(sdhci_am654->base); } ret = sdhci_am654_get_of_property(pdev, sdhci_am654); if (ret) - goto err_pltfm_free; + return ret; ret = mmc_of_parse(host->mmc); - if (ret) { - dev_err_probe(dev, ret, "parsing dt failed\n"); - goto err_pltfm_free; - } + if (ret) + return dev_err_probe(dev, ret, "parsing dt failed\n"); host->mmc_host_ops.start_signal_voltage_switch = sdhci_am654_start_signal_voltage_switch; host->mmc_host_ops.execute_tuning = sdhci_am654_execute_tuning; @@ -991,7 +989,6 @@ static int sdhci_am654_probe(struct platform_device *pdev) /* Setting up autosuspend */ pm_runtime_set_autosuspend_delay(dev, SDHCI_AM654_AUTOSUSPEND_DELAY); pm_runtime_use_autosuspend(dev); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; @@ -1001,8 +998,6 @@ pm_disable: pm_runtime_disable(dev); pm_put: pm_runtime_put_noidle(dev); -err_pltfm_free: - sdhci_pltfm_free(pdev); return ret; } @@ -1021,7 +1016,6 @@ static void sdhci_am654_remove(struct platform_device *pdev) clk_disable_unprepare(pltfm_host->clk); pm_runtime_disable(dev); pm_runtime_put_noidle(dev); - sdhci_pltfm_free(pdev); } #ifdef CONFIG_PM @@ -1082,9 +1076,7 @@ static int sdhci_am654_runtime_suspend(struct device *dev) if (ret) return ret; - ret = sdhci_runtime_suspend_host(host); - if (ret) - return ret; + sdhci_runtime_suspend_host(host); /* disable the clock */ clk_disable_unprepare(pltfm_host->clk); @@ -1106,9 +1098,7 @@ static int sdhci_am654_runtime_resume(struct device *dev) if (ret) return ret; - ret = sdhci_runtime_resume_host(host, 0); - if (ret) - return ret; + sdhci_runtime_resume_host(host, 0); ret = cqhci_resume(host->mmc); if (ret) diff --git a/drivers/mmc/host/sdhci_f_sdh30.c b/drivers/mmc/host/sdhci_f_sdh30.c index ee66e4f3683d..e9b934e159ad 100644 --- a/drivers/mmc/host/sdhci_f_sdh30.c +++ b/drivers/mmc/host/sdhci_f_sdh30.c @@ -133,20 +133,18 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev) ret = mmc_of_parse(host->mmc); if (ret) - goto err; + return ret; if (dev_of_node(dev)) { sdhci_get_of_property(pdev); priv->clk_iface = devm_clk_get(&pdev->dev, "iface"); - if (IS_ERR(priv->clk_iface)) { - ret = PTR_ERR(priv->clk_iface); - goto err; - } + if (IS_ERR(priv->clk_iface)) + return PTR_ERR(priv->clk_iface); ret = clk_prepare_enable(priv->clk_iface); if (ret) - goto err; + return ret; priv->clk = devm_clk_get(&pdev->dev, "core"); if (IS_ERR(priv->clk)) { @@ -200,9 +198,6 @@ err_rst: clk_disable_unprepare(priv->clk); err_clk: clk_disable_unprepare(priv->clk_iface); -err: - sdhci_pltfm_free(pdev); - return ret; } diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c index 57b8c1a96756..481cb552c2b4 100644 --- a/drivers/mmc/host/sdricoh_cs.c +++ b/drivers/mmc/host/sdricoh_cs.c @@ -403,9 +403,9 @@ static int sdricoh_init_mmc(struct pci_dev *pci_dev, } /* allocate privdata */ mmc = pcmcia_dev->priv = - mmc_alloc_host(sizeof(struct sdricoh_host), &pcmcia_dev->dev); + devm_mmc_alloc_host(&pcmcia_dev->dev, sizeof(*host)); if (!mmc) { - dev_err(dev, "mmc_alloc_host failed\n"); + dev_err(dev, "devm_mmc_alloc_host failed\n"); result = -ENOMEM; goto unmap_io; } @@ -431,7 +431,7 @@ static int sdricoh_init_mmc(struct pci_dev *pci_dev, if (sdricoh_reset(host)) { dev_dbg(dev, "could not reset\n"); result = -EIO; - goto free_host; + goto unmap_io; } result = mmc_add_host(mmc); @@ -440,8 +440,6 @@ static int sdricoh_init_mmc(struct pci_dev *pci_dev, dev_dbg(dev, "mmc host registered\n"); return 0; } -free_host: - mmc_free_host(mmc); unmap_io: pci_iounmap(pci_dev, iobase); return result; @@ -483,10 +481,8 @@ static void sdricoh_pcmcia_detach(struct pcmcia_device *link) mmc_remove_host(mmc); pci_iounmap(host->pci_dev, host->iobase); pci_dev_put(host->pci_dev); - mmc_free_host(mmc); } pcmcia_disable_device(link); - } #ifdef CONFIG_PM diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index ce60cec26b98..19f84584ecfa 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1444,13 +1444,13 @@ static int sh_mmcif_probe(struct platform_device *pdev) if (IS_ERR(reg)) return PTR_ERR(reg); - mmc = mmc_alloc_host(sizeof(struct sh_mmcif_host), dev); + mmc = devm_mmc_alloc_host(dev, sizeof(*host)); if (!mmc) return -ENOMEM; ret = mmc_of_parse(mmc); if (ret < 0) - goto err_host; + return ret; host = mmc_priv(mmc); host->mmc = mmc; @@ -1481,15 +1481,13 @@ static int sh_mmcif_probe(struct platform_device *pdev) platform_set_drvdata(pdev, host); 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_host; - } + if (IS_ERR(host->clk)) + return dev_err_probe(dev, PTR_ERR(host->clk), + "cannot get clock\n"); ret = clk_prepare_enable(host->clk); if (ret < 0) - goto err_host; + return ret; sh_mmcif_clk_setup(host); @@ -1542,8 +1540,6 @@ err_clk: clk_disable_unprepare(host->clk); pm_runtime_put_sync(dev); pm_runtime_disable(dev); -err_host: - mmc_free_host(mmc); return ret; } @@ -1568,7 +1564,6 @@ static void sh_mmcif_remove(struct platform_device *pdev) cancel_delayed_work_sync(&host->timeout_work); clk_disable_unprepare(host->clk); - mmc_free_host(host->mmc); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); } diff --git a/drivers/mmc/host/sunplus-mmc.c b/drivers/mmc/host/sunplus-mmc.c index 1cddea615a27..63279760239c 100644 --- a/drivers/mmc/host/sunplus-mmc.c +++ b/drivers/mmc/host/sunplus-mmc.c @@ -791,7 +791,7 @@ static int spmmc_get_cd(struct mmc_host *mmc) { int ret = 0; - if (mmc_can_gpio_cd(mmc)) + if (mmc_host_can_gpio_cd(mmc)) ret = mmc_gpio_get_cd(mmc); if (ret < 0) diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index 1508eead5d01..ee4a65b0a22d 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -1369,11 +1369,10 @@ static int sunxi_mmc_probe(struct platform_device *pdev) struct mmc_host *mmc; int ret; - mmc = mmc_alloc_host(sizeof(struct sunxi_mmc_host), &pdev->dev); - if (!mmc) { - dev_err(&pdev->dev, "mmc alloc host failed\n"); - return -ENOMEM; - } + mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(*host)); + if (!mmc) + return dev_err_probe(&pdev->dev, -ENOMEM, + "mmc alloc host failed\n"); platform_set_drvdata(pdev, mmc); host = mmc_priv(mmc); @@ -1383,15 +1382,13 @@ static int sunxi_mmc_probe(struct platform_device *pdev) ret = sunxi_mmc_resource_request(host, pdev); if (ret) - goto error_free_host; + return ret; host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); - if (!host->sg_cpu) { - dev_err(&pdev->dev, "Failed to allocate DMA descriptor mem\n"); - ret = -ENOMEM; - goto error_free_host; - } + if (!host->sg_cpu) + return dev_err_probe(&pdev->dev, -ENOMEM, + "Failed to allocate DMA descriptor mem\n"); if (host->cfg->ccu_has_timings_switch) { /* @@ -1481,8 +1478,6 @@ static int sunxi_mmc_probe(struct platform_device *pdev) error_free_dma: dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); -error_free_host: - mmc_free_host(mmc); return ret; } @@ -1498,7 +1493,6 @@ static void sunxi_mmc_remove(struct platform_device *pdev) sunxi_mmc_disable(host); } dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); - mmc_free_host(mmc); } #ifdef CONFIG_PM diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index 713223f2d377..ac636efd911d 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -777,7 +777,7 @@ static void tifm_sd_end_cmd(struct work_struct *t) static void tifm_sd_abort(struct timer_list *t) { - struct tifm_sd *host = from_timer(host, t, timer); + struct tifm_sd *host = timer_container_of(host, t, timer); pr_err("%s : card failed to respond for a long period of time " "(%x, %x)\n", @@ -947,7 +947,7 @@ static int tifm_sd_probe(struct tifm_dev *sock) return rc; } - mmc = mmc_alloc_host(sizeof(struct tifm_sd), &sock->dev); + mmc = devm_mmc_alloc_host(&sock->dev, sizeof(*host)); if (!mmc) return -ENOMEM; @@ -982,10 +982,7 @@ static int tifm_sd_probe(struct tifm_dev *sock) if (!rc) rc = mmc_add_host(mmc); - if (!rc) - return 0; - mmc_free_host(mmc); return rc; } @@ -1015,8 +1012,6 @@ static void tifm_sd_remove(struct tifm_dev *sock) spin_unlock_irqrestore(&sock->lock, flags); mmc_remove_host(mmc); dev_dbg(&sock->dev, "after remove\n"); - - mmc_free_host(mmc); } #ifdef CONFIG_PM diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 41787ea77a13..d730b7633ae1 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h @@ -193,13 +193,13 @@ struct tmio_mmc_host { bool (*check_retune)(struct tmio_mmc_host *host, struct mmc_request *mrq); void (*fixup_request)(struct tmio_mmc_host *host, struct mmc_request *mrq); unsigned int (*get_timeout_cycles)(struct tmio_mmc_host *host); + void (*sdio_irq)(struct tmio_mmc_host *host); const struct tmio_mmc_dma_ops *dma_ops; }; struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev, struct tmio_mmc_data *pdata); -void tmio_mmc_host_free(struct tmio_mmc_host *host); int tmio_mmc_host_probe(struct tmio_mmc_host *host); void tmio_mmc_host_remove(struct tmio_mmc_host *host); void tmio_mmc_do_data_irq(struct tmio_mmc_host *host); diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 04c1c54df791..21c2f9095bac 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -160,7 +160,6 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable) sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask); host->sdio_irq_enabled = false; - pm_runtime_mark_last_busy(mmc_dev(mmc)); pm_runtime_put_autosuspend(mmc_dev(mmc)); } } @@ -696,8 +695,11 @@ static bool __tmio_mmc_sdio_irq(struct tmio_mmc_host *host) sd_ctrl_write16(host, CTL_SDIO_STATUS, sdio_status); - if (mmc->caps & MMC_CAP_SDIO_IRQ && ireg & TMIO_SDIO_STAT_IOIRQ) + if (mmc->caps & MMC_CAP_SDIO_IRQ && ireg & TMIO_SDIO_STAT_IOIRQ) { + if (host->sdio_irq) + host->sdio_irq(host); mmc_signal_sdio_irq(mmc); + } return ireg; } @@ -1097,7 +1099,7 @@ struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev, if (IS_ERR(ctl)) return ERR_CAST(ctl); - mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &pdev->dev); + mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(*host)); if (!mmc) return ERR_PTR(-ENOMEM); @@ -1110,29 +1112,17 @@ struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev, mmc->ops = &host->ops; ret = mmc_of_parse(host->mmc); - if (ret) { - host = ERR_PTR(ret); - goto free; - } + if (ret) + return ERR_PTR(ret); tmio_mmc_of_parse(pdev, mmc); platform_set_drvdata(pdev, host); return host; -free: - mmc_free_host(mmc); - - return host; } EXPORT_SYMBOL_GPL(tmio_mmc_host_alloc); -void tmio_mmc_host_free(struct tmio_mmc_host *host) -{ - mmc_free_host(host->mmc); -} -EXPORT_SYMBOL_GPL(tmio_mmc_host_free); - int tmio_mmc_host_probe(struct tmio_mmc_host *_host) { struct platform_device *pdev = _host->pdev; @@ -1176,14 +1166,14 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) dma_max_mapping_size(&pdev->dev)); mmc->max_seg_size = mmc->max_req_size; - if (mmc_can_gpio_ro(mmc)) + if (mmc_host_can_gpio_ro(mmc)) _host->ops.get_ro = mmc_gpio_get_ro; - if (mmc_can_gpio_cd(mmc)) + if (mmc_host_can_gpio_cd(mmc)) _host->ops.get_cd = mmc_gpio_get_cd; /* must be set before tmio_mmc_reset() */ - _host->native_hotplug = !(mmc_can_gpio_cd(mmc) || + _host->native_hotplug = !(mmc_host_can_gpio_cd(mmc) || mmc->caps & MMC_CAP_NEEDS_POLL || !mmc_card_is_removable(mmc)); diff --git a/drivers/mmc/host/toshsd.c b/drivers/mmc/host/toshsd.c index 497791ffada6..e5f7f8abafc0 100644 --- a/drivers/mmc/host/toshsd.c +++ b/drivers/mmc/host/toshsd.c @@ -612,7 +612,7 @@ static int toshsd_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (ret) return ret; - mmc = mmc_alloc_host(sizeof(struct toshsd_host), &pdev->dev); + mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(*host)); if (!mmc) { ret = -ENOMEM; goto err; @@ -669,7 +669,6 @@ unmap: release: pci_release_regions(pdev); free: - mmc_free_host(mmc); pci_set_drvdata(pdev, NULL); err: pci_disable_device(pdev); @@ -685,7 +684,6 @@ static void toshsd_remove(struct pci_dev *pdev) free_irq(pdev->irq, host); pci_iounmap(pdev, host->ioaddr); pci_release_regions(pdev); - mmc_free_host(host->mmc); pci_set_drvdata(pdev, NULL); pci_disable_device(pdev); } diff --git a/drivers/mmc/host/uniphier-sd.c b/drivers/mmc/host/uniphier-sd.c index 4ad02cfdc238..1eae2f4b6c1f 100644 --- a/drivers/mmc/host/uniphier-sd.c +++ b/drivers/mmc/host/uniphier-sd.c @@ -663,8 +663,7 @@ static int uniphier_sd_probe(struct platform_device *pdev) priv->rst_hw = devm_reset_control_get_exclusive(dev, "hw"); if (IS_ERR(priv->rst_hw)) { dev_err(dev, "failed to get hw reset\n"); - ret = PTR_ERR(priv->rst_hw); - goto free_host; + return PTR_ERR(priv->rst_hw); } host->ops.card_hw_reset = uniphier_sd_hw_reset; } @@ -694,7 +693,7 @@ static int uniphier_sd_probe(struct platform_device *pdev) ret = uniphier_sd_clk_enable(host); if (ret) - goto free_host; + return ret; uniphier_sd_host_init(host); @@ -720,8 +719,6 @@ static int uniphier_sd_probe(struct platform_device *pdev) disable_clk: uniphier_sd_clk_disable(host); -free_host: - tmio_mmc_host_free(host); return ret; } @@ -732,7 +729,6 @@ static void uniphier_sd_remove(struct platform_device *pdev) tmio_mmc_host_remove(host); uniphier_sd_clk_disable(host); - tmio_mmc_host_free(host); } static const struct of_device_id uniphier_sd_match[] = { diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index 49efb960a052..85b49c07918b 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -1762,17 +1762,17 @@ static int usdhi6_probe(struct platform_device *pdev) if (irq_sdio < 0) return irq_sdio; - mmc = mmc_alloc_host(sizeof(struct usdhi6_host), dev); + mmc = devm_mmc_alloc_host(dev, sizeof(*host)); if (!mmc) return -ENOMEM; ret = mmc_regulator_get_supply(mmc); if (ret) - goto e_free_mmc; + return ret; ret = mmc_of_parse(mmc); if (ret < 0) - goto e_free_mmc; + return ret; host = mmc_priv(mmc); host->mmc = mmc; @@ -1785,30 +1785,24 @@ static int usdhi6_probe(struct platform_device *pdev) mmc->max_busy_timeout = USDHI6_REQ_TIMEOUT_MS; host->pinctrl = devm_pinctrl_get(&pdev->dev); - if (IS_ERR(host->pinctrl)) { - ret = PTR_ERR(host->pinctrl); - goto e_free_mmc; - } + if (IS_ERR(host->pinctrl)) + return PTR_ERR(host->pinctrl); host->pins_uhs = pinctrl_lookup_state(host->pinctrl, "state_uhs"); host->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); - if (IS_ERR(host->base)) { - ret = PTR_ERR(host->base); - goto e_free_mmc; - } + if (IS_ERR(host->base)) + return PTR_ERR(host->base); host->clk = devm_clk_get(dev, NULL); - if (IS_ERR(host->clk)) { - ret = PTR_ERR(host->clk); - goto e_free_mmc; - } + if (IS_ERR(host->clk)) + return PTR_ERR(host->clk); host->imclk = clk_get_rate(host->clk); ret = clk_prepare_enable(host->clk); if (ret < 0) - goto e_free_mmc; + return ret; version = usdhi6_read(host, USDHI6_VERSION); if ((version & 0xfff) != 0xa0d) { @@ -1878,9 +1872,6 @@ e_release_dma: usdhi6_dma_release(host); e_clk_off: clk_disable_unprepare(host->clk); -e_free_mmc: - mmc_free_host(mmc); - return ret; } @@ -1894,7 +1885,6 @@ static void usdhi6_remove(struct platform_device *pdev) cancel_delayed_work_sync(&host->timeout_work); usdhi6_dma_release(host); clk_disable_unprepare(host->clk); - mmc_free_host(host->mmc); } static struct platform_driver usdhi6_driver = { diff --git a/drivers/mmc/host/ushc.c b/drivers/mmc/host/ushc.c index 9a6358fd9512..2b7456e942f7 100644 --- a/drivers/mmc/host/ushc.c +++ b/drivers/mmc/host/ushc.c @@ -404,8 +404,6 @@ static void ushc_clean_up(struct ushc_data *ushc) kfree(ushc->int_data); kfree(ushc->cbw); kfree(ushc->csw); - - mmc_free_host(ushc->mmc); } static const struct mmc_host_ops ushc_ops = { @@ -425,7 +423,7 @@ static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id if (intf->cur_altsetting->desc.bNumEndpoints < 1) return -ENODEV; - mmc = mmc_alloc_host(sizeof(struct ushc_data), &intf->dev); + mmc = devm_mmc_alloc_host(&intf->dev, sizeof(*ushc)); if (mmc == NULL) return -ENOMEM; ushc = mmc_priv(mmc); diff --git a/drivers/mmc/host/via-sdmmc.c b/drivers/mmc/host/via-sdmmc.c index 909d80a02824..3bd49f64899d 100644 --- a/drivers/mmc/host/via-sdmmc.c +++ b/drivers/mmc/host/via-sdmmc.c @@ -937,7 +937,7 @@ static void via_sdc_timeout(struct timer_list *t) struct via_crdr_mmc_host *sdhost; unsigned long flags; - sdhost = from_timer(sdhost, t, timer); + sdhost = timer_container_of(sdhost, t, timer); spin_lock_irqsave(&sdhost->lock, flags); @@ -1100,7 +1100,7 @@ static int via_sd_probe(struct pci_dev *pcidev, pci_write_config_byte(pcidev, VIA_CRDR_PCI_WORK_MODE, 0); pci_write_config_byte(pcidev, VIA_CRDR_PCI_DBG_MODE, 0); - mmc = mmc_alloc_host(sizeof(struct via_crdr_mmc_host), &pcidev->dev); + mmc = devm_mmc_alloc_host(&pcidev->dev, sizeof(*sdhost)); if (!mmc) { ret = -ENOMEM; goto release; @@ -1115,7 +1115,7 @@ static int via_sd_probe(struct pci_dev *pcidev, sdhost->mmiobase = ioremap(base, len); if (!sdhost->mmiobase) { ret = -ENOMEM; - goto free_mmc_host; + goto release; } sdhost->sdhc_mmiobase = @@ -1160,8 +1160,6 @@ static int via_sd_probe(struct pci_dev *pcidev, unmap: iounmap(sdhost->mmiobase); -free_mmc_host: - mmc_free_host(mmc); release: pci_release_regions(pcidev); disable: @@ -1212,7 +1210,6 @@ static void via_sd_remove(struct pci_dev *pcidev) writeb(gatt, sdhost->pcictrl_mmiobase + VIA_CRDR_PCICLKGATT); iounmap(sdhost->mmiobase); - mmc_free_host(sdhost->mmc); pci_release_regions(pcidev); pci_disable_device(pcidev); diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index dd71e5b8e1a5..ff49d0770506 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -369,13 +369,11 @@ struct vub300_mmc_host { static void vub300_delete(struct kref *kref) { /* kref callback - softirq */ struct vub300_mmc_host *vub300 = kref_to_vub300_mmc_host(kref); - struct mmc_host *mmc = vub300->mmc; usb_free_urb(vub300->command_out_urb); vub300->command_out_urb = NULL; usb_free_urb(vub300->command_res_urb); vub300->command_res_urb = NULL; usb_put_dev(vub300->udev); - mmc_free_host(mmc); /* * and hence also frees vub300 * which is contained at the end of struct mmc @@ -740,8 +738,8 @@ static void vub300_deadwork_thread(struct work_struct *work) static void vub300_inactivity_timer_expired(struct timer_list *t) { /* softirq */ - struct vub300_mmc_host *vub300 = from_timer(vub300, t, - inactivity_timer); + struct vub300_mmc_host *vub300 = timer_container_of(vub300, t, + inactivity_timer); if (!vub300->interface) { kref_put(&vub300->kref, vub300_delete); } else if (vub300->cmd) { @@ -1180,8 +1178,8 @@ static void send_command(struct vub300_mmc_host *vub300) */ static void vub300_sg_timed_out(struct timer_list *t) { - struct vub300_mmc_host *vub300 = from_timer(vub300, t, - sg_transfer_timer); + struct vub300_mmc_host *vub300 = timer_container_of(vub300, t, + sg_transfer_timer); vub300->usb_timed_out = 1; usb_sg_cancel(&vub300->sg_request); usb_unlink_urb(vub300->command_out_urb); @@ -2114,7 +2112,7 @@ static int vub300_probe(struct usb_interface *interface, goto error1; } /* this also allocates memory for our VUB300 mmc host device */ - mmc = mmc_alloc_host(sizeof(struct vub300_mmc_host), &udev->dev); + mmc = devm_mmc_alloc_host(&udev->dev, sizeof(*vub300)); if (!mmc) { retval = -ENOMEM; dev_err(&udev->dev, "not enough memory for the mmc_host\n"); @@ -2271,7 +2269,7 @@ static int vub300_probe(struct usb_interface *interface, dev_err(&vub300->udev->dev, "Could not find two sets of bulk-in/out endpoint pairs\n"); retval = -EINVAL; - goto error5; + goto error4; } retval = usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0), @@ -2280,14 +2278,14 @@ static int vub300_probe(struct usb_interface *interface, 0x0000, 0x0000, &vub300->hc_info, sizeof(vub300->hc_info), 1000); if (retval < 0) - goto error5; + goto error4; retval = usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0), SET_ROM_WAIT_STATES, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, firmware_rom_wait_states, 0x0000, NULL, 0, 1000); if (retval < 0) - goto error5; + goto error4; dev_info(&vub300->udev->dev, "operating_mode = %s %s %d MHz %s %d byte USB packets\n", (mmc->caps & MMC_CAP_SDIO_IRQ) ? "IRQs" : "POLL", @@ -2302,7 +2300,7 @@ static int vub300_probe(struct usb_interface *interface, 0x0000, 0x0000, &vub300->system_port_status, sizeof(vub300->system_port_status), 1000); if (retval < 0) { - goto error5; + goto error4; } else if (sizeof(vub300->system_port_status) == retval) { vub300->card_present = (0x0001 & vub300->system_port_status.port_flags) ? 1 : 0; @@ -2310,7 +2308,7 @@ static int vub300_probe(struct usb_interface *interface, (0x0010 & vub300->system_port_status.port_flags) ? 1 : 0; } else { retval = -EINVAL; - goto error5; + goto error4; } usb_set_intfdata(interface, vub300); INIT_DELAYED_WORK(&vub300->pollwork, vub300_pollwork_thread); @@ -2340,8 +2338,6 @@ static int vub300_probe(struct usb_interface *interface, return 0; error6: timer_delete_sync(&vub300->inactivity_timer); -error5: - mmc_free_host(mmc); /* * and hence also frees vub300 * which is contained at the end of struct mmc diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index d5974b355a5a..c33a0223ce7f 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -947,7 +947,7 @@ static const struct mmc_host_ops wbsd_ops = { static void wbsd_reset_ignore(struct timer_list *t) { - struct wbsd_host *host = from_timer(host, t, ignore_timer); + struct wbsd_host *host = timer_container_of(host, t, ignore_timer); BUG_ON(host == NULL); @@ -1190,7 +1190,7 @@ static int wbsd_alloc_mmc(struct device *dev) /* * Allocate MMC structure. */ - mmc = mmc_alloc_host(sizeof(struct wbsd_host), dev); + mmc = devm_mmc_alloc_host(dev, sizeof(*host)); if (!mmc) return -ENOMEM; @@ -1262,8 +1262,6 @@ static void wbsd_free_mmc(struct device *dev) BUG_ON(host == NULL); timer_delete_sync(&host->ignore_timer); - - mmc_free_host(mmc); } /* diff --git a/drivers/mmc/host/wmt-sdmmc.c b/drivers/mmc/host/wmt-sdmmc.c index cdb36a9f9e38..0d2929cfe397 100644 --- a/drivers/mmc/host/wmt-sdmmc.c +++ b/drivers/mmc/host/wmt-sdmmc.c @@ -774,7 +774,7 @@ static int wmt_mci_probe(struct platform_device *pdev) goto fail1; } - mmc = mmc_alloc_host(sizeof(struct wmt_mci_priv), &pdev->dev); + mmc = devm_mmc_alloc_host(&pdev->dev, sizeof(*priv)); if (!mmc) { dev_err(&pdev->dev, "Failed to allocate mmc_host\n"); ret = -ENOMEM; @@ -808,7 +808,7 @@ static int wmt_mci_probe(struct platform_device *pdev) if (!priv->sdmmc_base) { dev_err(&pdev->dev, "Failed to map IO space\n"); ret = -ENOMEM; - goto fail2; + goto fail1; } priv->irq_regular = regular_irq; @@ -873,8 +873,6 @@ fail4: free_irq(regular_irq, priv); fail3: iounmap(priv->sdmmc_base); -fail2: - mmc_free_host(mmc); fail1: return ret; } @@ -910,8 +908,6 @@ static void wmt_mci_remove(struct platform_device *pdev) clk_disable_unprepare(priv->clk_sdmmc); clk_put(priv->clk_sdmmc); - mmc_free_host(mmc); - dev_info(&pdev->dev, "WMT MCI device removed\n"); } |