diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-18 15:54:05 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-18 15:54:05 -0700 |
| commit | bbd60bffaf780464298cb7a39852f7f1065f1726 (patch) | |
| tree | 1338cf7dd93214382127a53b88969e870fbb837a /drivers | |
| parent | 307797159ac25fe5a2048bf5c6a5718298edca57 (diff) | |
| parent | 7f38abf220e2c800a2c451372e9f07ed5fd0ea49 (diff) | |
| download | linux-bbd60bffaf780464298cb7a39852f7f1065f1726.tar.gz linux-bbd60bffaf780464298cb7a39852f7f1065f1726.tar.bz2 linux-bbd60bffaf780464298cb7a39852f7f1065f1726.zip | |
Merge tag 'mmc-v4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson:
"Updates for MMC for v4.19.
MMC core:
- Add some fine-grained hooks to further support HS400 tuning
- Improve error path for bus width setting for HS400es
- Use a common method when checking R1 status
MMC host:
- renesas_sdhi: Add r8a77990 support
- renesas_sdhi: Add eMMC HS400 mode support
- tmio/renesas_sdhi: Improve tuning/clock management
- tmio: Add eMMC HS400 mode support
- sunxi: Add support for 3.3V eMMC DDR mode
- mmci: Initial support to manage variant specific callbacks
- sdhci: Don't try 3.3V I/O voltage if not supported
- sdhci-pci-dwc-mshc: Add driver to support Synopsys dwc mshc SDHCI PCI
- sdhci-of-dwcmshc: Add driver to support Synopsys DWC MSHC SDHCI
- sdhci-msm: Add support for new version sdcc V5
- sdhci-pci-o2micro: Add support for O2 eMMC HS200 mode
- sdhci-pci-o2micro: Add support for O2 hardware tuning
- sdhci-pci-o2micro: Add MSI interrupt support for O2 SD host
- sdhci-pci: Add support for Intel ICP
- sdhci-tegra: Prevent ACMD23 and HS200 mode on Tegra 3
- sdhci-tegra: Fix eMMC DDR52 mode
- sdhci-tegra: Improve clock management
- dw_mmc-rockchip: Document compatible string for px30
- sdhci-esdhc-imx: Add support for 3.3V eMMC DDR mode
- sdhci-of-esdhc: Set proper DMA mask for ls104x chips
- sdhci-of-esdhc: Improve clock management
- sdhci-of-arasan: Add a quirk to manage unstable clocks
- dw_mmc-exynos: Address potential external abort during system resume
- pxamci: Add support for common MMC DT bindings
- pxamci: Several cleanups and improvements
- pxamci: Merge immutable branch for pxa to switch to DMA slave maps"
* tag 'mmc-v4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (56 commits)
mmc: core: improve reasonableness of bus width setting for HS400es
mmc: tmio: remove unneeded variable in tmio_mmc_start_command()
mmc: renesas_sdhi: Fix sampling clock position selecting
mmc: tmio: Fix tuning flow
mmc: sunxi: remove output of virtual base address
dt-bindings: mmc: rockchip-dw-mshc: add description for px30
mmc: renesas_sdhi: Add r8a77990 support
mmc: sunxi: allow 3.3V DDR when DDR is available
mmc: mmci: Add and implement a ->dma_setup() callback for qcom dml
mmc: mmci: Initial support to manage variant specific callbacks
mmc: tegra: Force correct divider calculation on DDR50/52
mmc: sdhci: Add MSI interrupt support for O2 SD host
mmc: sdhci: Add support for O2 hardware tuning
mmc: sdhci: Export sdhci tuning function symbol
mmc: sdhci: Change O2 Host HS200 mode clock frequency to 200MHz
mmc: sdhci: Add support for O2 eMMC HS200 mode
mmc: tegra: Add and use tegra_sdhci_get_max_clock()
mmc: sdhci-esdhc-imx: fix indent
mmc: sdhci-esdhc-imx: disable clocks before changing frequency
mmc: tegra: prevent ACMD23 on Tegra 3
...
Diffstat (limited to 'drivers')
32 files changed, 1322 insertions, 484 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 281826d1fcca..50a5c340307b 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2078,7 +2078,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; /* Do not retry else we can't see errors */ err = mmc_wait_for_cmd(card->host, &cmd, 0); - if (err || (cmd.resp[0] & 0xFDF92000)) { + if (err || R1_STATUS(cmd.resp[0])) { pr_err("error %d requesting status %#x\n", err, cmd.resp[0]); err = -EIO; @@ -2716,52 +2716,6 @@ void mmc_stop_host(struct mmc_host *host) mmc_release_host(host); } -int mmc_power_save_host(struct mmc_host *host) -{ - int ret = 0; - - pr_debug("%s: %s: powering down\n", mmc_hostname(host), __func__); - - mmc_bus_get(host); - - if (!host->bus_ops || host->bus_dead) { - mmc_bus_put(host); - return -EINVAL; - } - - if (host->bus_ops->power_save) - ret = host->bus_ops->power_save(host); - - mmc_bus_put(host); - - mmc_power_off(host); - - return ret; -} -EXPORT_SYMBOL(mmc_power_save_host); - -int mmc_power_restore_host(struct mmc_host *host) -{ - int ret; - - pr_debug("%s: %s: powering up\n", mmc_hostname(host), __func__); - - mmc_bus_get(host); - - if (!host->bus_ops || host->bus_dead) { - mmc_bus_put(host); - return -EINVAL; - } - - mmc_power_up(host, host->card->ocr); - ret = host->bus_ops->power_restore(host); - - mmc_bus_put(host); - - return ret; -} -EXPORT_SYMBOL(mmc_power_restore_host); - #ifdef CONFIG_PM_SLEEP /* Do the card removal on suspend if card is assumed removeable * Do that in pm notifier while userspace isn't yet frozen, so we will be able diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 9d8f09ac0821..087ba68b2920 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -28,8 +28,6 @@ struct mmc_bus_ops { int (*resume)(struct mmc_host *); int (*runtime_suspend)(struct mmc_host *); int (*runtime_resume)(struct mmc_host *); - int (*power_save)(struct mmc_host *); - int (*power_restore)(struct mmc_host *); int (*alive)(struct mmc_host *); int (*shutdown)(struct mmc_host *); int (*hw_reset)(struct mmc_host *); diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 4466f5de54d4..bc1bd2c25613 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1169,6 +1169,10 @@ static int mmc_select_hs400(struct mmc_card *card) /* Set host controller to HS timing */ mmc_set_timing(card->host, MMC_TIMING_MMC_HS); + /* Prepare host to downgrade to HS timing */ + if (host->ops->hs400_downgrade) + host->ops->hs400_downgrade(host); + /* Reduce frequency to HS frequency */ max_dtr = card->ext_csd.hs_max_dtr; mmc_set_clock(host, max_dtr); @@ -1209,6 +1213,9 @@ static int mmc_select_hs400(struct mmc_card *card) if (err) goto out_err; + if (host->ops->hs400_complete) + host->ops->hs400_complete(host); + return 0; out_err: @@ -1256,6 +1263,9 @@ int mmc_hs400_to_hs200(struct mmc_card *card) mmc_set_timing(host, MMC_TIMING_MMC_HS); + if (host->ops->hs400_downgrade) + host->ops->hs400_downgrade(host); + err = mmc_switch_status(card); if (err) goto out_err; @@ -1338,8 +1348,12 @@ static int mmc_select_hs400es(struct mmc_card *card) goto out_err; err = mmc_select_bus_width(card); - if (err < 0) + if (err != MMC_BUS_WIDTH_8) { + pr_err("%s: switch to 8bit bus width failed, err:%d\n", + mmc_hostname(host), err); + err = err < 0 ? err : -ENOTSUPP; goto out_err; + } /* Switch card to HS mode */ err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 42d6aa89a48a..873b2aa0c155 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -417,7 +417,7 @@ static int mmc_switch_status_error(struct mmc_host *host, u32 status) if (status & R1_SPI_ILLEGAL_COMMAND) return -EBADMSG; } else { - if (status & 0xFDFFA000) + if (R1_STATUS(status)) pr_warn("%s: unexpected status %#x after switch\n", mmc_hostname(host), status); if (status & R1_SWITCH_ERROR) diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index a86490dbca70..d8e17ea6126d 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -1076,7 +1076,6 @@ static const struct mmc_bus_ops mmc_sdio_ops = { .resume = mmc_sdio_resume, .runtime_suspend = mmc_sdio_runtime_suspend, .runtime_resume = mmc_sdio_runtime_resume, - .power_restore = mmc_sdio_power_restore, .alive = mmc_sdio_alive, .hw_reset = mmc_sdio_hw_reset, .sw_reset = mmc_sdio_sw_reset, diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 0581c199c996..694d0828215d 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -176,6 +176,17 @@ config MMC_SDHCI_OF_HLWD If unsure, say N. +config MMC_SDHCI_OF_DWCMSHC + tristate "SDHCI OF support for the Synopsys DWC MSHC" + depends on MMC_SDHCI_PLTFM + depends on OF + depends on COMMON_CLK + help + This selects Synopsys DesignWare Cores Mobile Storage Controller + support. + If you have a controller with this interface, say Y or M here. + If unsure, say N. + config MMC_SDHCI_CADENCE tristate "SDHCI support for the Cadence SD/SDIO/eMMC controller" depends on MMC_SDHCI_PLTFM diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index 85dc1322c3de..ce8398e6f2c0 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -11,7 +11,8 @@ obj-$(CONFIG_MMC_MXC) += mxcmmc.o obj-$(CONFIG_MMC_MXS) += mxs-mmc.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o -sdhci-pci-y += sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o +sdhci-pci-y += sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \ + sdhci-pci-dwc-mshc.o obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o @@ -82,6 +83,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_ARASAN) += sdhci-of-arasan.o 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_BCM_KONA) += sdhci-bcm-kona.o obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index a84aa3f1ae85..ab47b018716a 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -175,6 +175,20 @@ static int dw_mci_exynos_runtime_resume(struct device *dev) return ret; } +#endif /* CONFIG_PM */ + +#ifdef CONFIG_PM_SLEEP +/** + * dw_mci_exynos_suspend_noirq - Exynos-specific suspend code + * + * This ensures that device will be in runtime active state in + * dw_mci_exynos_resume_noirq after calling pm_runtime_force_resume() + */ +static int dw_mci_exynos_suspend_noirq(struct device *dev) +{ + pm_runtime_get_noresume(dev); + return pm_runtime_force_suspend(dev); +} /** * dw_mci_exynos_resume_noirq - Exynos-specific resume code @@ -186,12 +200,16 @@ static int dw_mci_exynos_runtime_resume(struct device *dev) * * We run this code on all exynos variants because it doesn't hurt. */ - static int dw_mci_exynos_resume_noirq(struct device *dev) { struct dw_mci *host = dev_get_drvdata(dev); struct dw_mci_exynos_priv_data *priv = host->priv; u32 clksel; + int ret; + + ret = pm_runtime_force_resume(dev); + if (ret) + return ret; if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) @@ -207,11 +225,11 @@ static int dw_mci_exynos_resume_noirq(struct device *dev) mci_writel(host, CLKSEL, clksel); } + pm_runtime_put(dev); + return 0; } -#else -#define dw_mci_exynos_resume_noirq NULL -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */ static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing) { @@ -553,14 +571,11 @@ static int dw_mci_exynos_remove(struct platform_device *pdev) } static const struct dev_pm_ops dw_mci_exynos_pmops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend_noirq, + dw_mci_exynos_resume_noirq) SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend, dw_mci_exynos_runtime_resume, NULL) - .resume_noirq = dw_mci_exynos_resume_noirq, - .thaw_noirq = dw_mci_exynos_resume_noirq, - .restore_noirq = dw_mci_exynos_resume_noirq, }; static struct platform_driver dw_mci_exynos_pltfm_driver = { diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index f1849775e47e..1841d250e9e2 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -48,78 +48,6 @@ static unsigned int fmax = 515633; -/** - * struct variant_data - MMCI variant-specific quirks - * @clkreg: default value for MCICLOCK register - * @clkreg_enable: enable value for MMCICLOCK register - * @clkreg_8bit_bus_enable: enable value for 8 bit bus - * @clkreg_neg_edge_enable: enable value for inverted data/cmd output - * @datalength_bits: number of bits in the MMCIDATALENGTH register - * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY - * is asserted (likewise for RX) - * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY - * is asserted (likewise for RX) - * @data_cmd_enable: enable value for data commands. - * @st_sdio: enable ST specific SDIO logic - * @st_clkdiv: true if using a ST-specific clock divider algorithm - * @datactrl_mask_ddrmode: ddr mode mask in datactrl register. - * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register - * @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl - * register - * @datactrl_mask_sdio: SDIO enable mask in datactrl register - * @pwrreg_powerup: power up value for MMCIPOWER register - * @f_max: maximum clk frequency supported by the controller. - * @signal_direction: input/out direction of bus signals can be indicated - * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock - * @busy_detect: true if the variant supports busy detection on DAT0. - * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM - * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register - * indicating that the card is busy - * @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for - * getting busy end detection interrupts - * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply - * @explicit_mclk_control: enable explicit mclk control in driver. - * @qcom_fifo: enables qcom specific fifo pio read logic. - * @qcom_dml: enables qcom specific dma glue for dma transfers. - * @reversed_irq_handling: handle data irq before cmd irq. - * @mmcimask1: true if variant have a MMCIMASK1 register. - * @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS - * register. - * @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register - */ -struct variant_data { - unsigned int clkreg; - unsigned int clkreg_enable; - unsigned int clkreg_8bit_bus_enable; - unsigned int clkreg_neg_edge_enable; - unsigned int datalength_bits; - unsigned int fifosize; - unsigned int fifohalfsize; - unsigned int data_cmd_enable; - unsigned int datactrl_mask_ddrmode; - unsigned int datactrl_mask_sdio; - bool st_sdio; - bool st_clkdiv; - bool blksz_datactrl16; - bool blksz_datactrl4; - u32 pwrreg_powerup; - u32 f_max; - bool signal_direction; - bool pwrreg_clkgate; - bool busy_detect; - u32 busy_dpsm_flag; - u32 busy_detect_flag; - u32 busy_detect_mask; - bool pwrreg_nopower; - bool explicit_mclk_control; - bool qcom_fifo; - bool qcom_dml; - bool reversed_irq_handling; - bool mmcimask1; - u32 start_err; - u32 opendrain; -}; - static struct variant_data variant_arm = { .fifosize = 16 * 4, .fifohalfsize = 8 * 4, @@ -280,6 +208,7 @@ static struct variant_data variant_qcom = { .mmcimask1 = true, .start_err = MCI_STARTBITERR, .opendrain = MCI_ROD, + .init = qcom_variant_init, }; /* Busy detection for the ST Micro variant */ @@ -489,7 +418,6 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) static void mmci_dma_setup(struct mmci_host *host) { const char *rxname, *txname; - struct variant_data *variant = host->variant; host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx"); host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx"); @@ -537,9 +465,8 @@ static void mmci_dma_setup(struct mmci_host *host) host->mmc->max_seg_size = max_seg_size; } - if (variant->qcom_dml && host->dma_rx_channel && host->dma_tx_channel) - if (dml_hw_init(host, host->mmc->parent->of_node)) - variant->qcom_dml = false; + if (host->ops && host->ops->dma_setup) + host->ops->dma_setup(host); } /* @@ -1706,6 +1633,9 @@ static int mmci_probe(struct amba_device *dev, goto clk_disable; } + if (variant->init) + variant->init(host); + /* * The ARM and ST versions of the block have slightly different * clock divider equations which means that the minimum divider diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index f91cdf7f6dae..517591d219e9 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -195,8 +195,86 @@ #define MMCI_PINCTRL_STATE_OPENDRAIN "opendrain" struct clk; -struct variant_data; struct dma_chan; +struct mmci_host; + +/** + * struct variant_data - MMCI variant-specific quirks + * @clkreg: default value for MCICLOCK register + * @clkreg_enable: enable value for MMCICLOCK register + * @clkreg_8bit_bus_enable: enable value for 8 bit bus + * @clkreg_neg_edge_enable: enable value for inverted data/cmd output + * @datalength_bits: number of bits in the MMCIDATALENGTH register + * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY + * is asserted (likewise for RX) + * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY + * is asserted (likewise for RX) + * @data_cmd_enable: enable value for data commands. + * @st_sdio: enable ST specific SDIO logic + * @st_clkdiv: true if using a ST-specific clock divider algorithm + * @datactrl_mask_ddrmode: ddr mode mask in datactrl register. + * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register + * @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl + * register + * @datactrl_mask_sdio: SDIO enable mask in datactrl register + * @pwrreg_powerup: power up value for MMCIPOWER register + * @f_max: maximum clk frequency supported by the controller. + * @signal_direction: input/out direction of bus signals can be indicated + * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock + * @busy_detect: true if the variant supports busy detection on DAT0. + * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM + * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register + * indicating that the card is busy + * @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for + * getting busy end detection interrupts + * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply + * @explicit_mclk_control: enable explicit mclk control in driver. + * @qcom_fifo: enables qcom specific fifo pio read logic. + * @qcom_dml: enables qcom specific dma glue for dma transfers. + * @reversed_irq_handling: handle data irq before cmd irq. + * @mmcimask1: true if variant have a MMCIMASK1 register. + * @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS + * register. + * @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register + */ +struct variant_data { + unsigned int clkreg; + unsigned int clkreg_enable; + unsigned int clkreg_8bit_bus_enable; + unsigned int clkreg_neg_edge_enable; + unsigned int datalength_bits; + unsigned int fifosize; + unsigned int fifohalfsize; + unsigned int data_cmd_enable; + unsigned int datactrl_mask_ddrmode; + unsigned int datactrl_mask_sdio; + bool st_sdio; + bool st_clkdiv; + bool blksz_datactrl16; + bool blksz_datactrl4; + u32 pwrreg_powerup; + u32 f_max; + bool signal_direction; + bool pwrreg_clkgate; + bool busy_detect; + u32 busy_dpsm_flag; + u32 busy_detect_flag; + u32 busy_detect_mask; + bool pwrreg_nopower; + bool explicit_mclk_control; + bool qcom_fifo; + bool qcom_dml; + bool reversed_irq_handling; + bool mmcimask1; + u32 start_err; + u32 opendrain; + void (*init)(struct mmci_host *host); +}; + +/* mmci variant callbacks */ +struct mmci_host_ops { + void (*dma_setup)(struct mmci_host *host); +}; struct mmci_host_next { struct dma_async_tx_descriptor *dma_desc; @@ -228,6 +306,7 @@ struct mmci_host { u32 mask1_reg; bool vqmmc_enabled; struct mmci_platform_data *plat; + struct mmci_host_ops *ops; struct variant_data *variant; struct pinctrl *pinctrl; struct pinctrl_state *pins_default; diff --git a/drivers/mmc/host/mmci_qcom_dml.c b/drivers/mmc/host/mmci_qcom_dml.c index 00750c9d3514..be3fab5db83f 100644 --- a/drivers/mmc/host/mmci_qcom_dml.c +++ b/drivers/mmc/host/mmci_qcom_dml.c @@ -119,17 +119,20 @@ static int of_get_dml_pipe_index(struct device_node *np, const char *name) } /* Initialize the dml hardware connected to SD Card controller */ -int dml_hw_init(struct mmci_host *host, struct device_node *np) +static void qcom_dma_setup(struct mmci_host *host) { u32 config; void __iomem *base; int consumer_id, producer_id; + struct device_node *np = host->mmc->parent->of_node; consumer_id = of_get_dml_pipe_index(np, "tx"); producer_id = of_get_dml_pipe_index(np, "rx"); - if (producer_id < 0 || consumer_id < 0) - return -ENODEV; + if (producer_id < 0 || consumer_id < 0) { + host->variant->qcom_dml = false; + return; + } base = host->base + DML_OFFSET; @@ -172,6 +175,13 @@ int dml_hw_init(struct mmci_host *host, struct device_node *np) /* Make sure dml initialization is finished */ mb(); +} - return 0; +static struct mmci_host_ops qcom_variant_ops = { + .dma_setup = qcom_dma_setup, +}; + +void qcom_variant_init(struct mmci_host *host) +{ + host->ops = &qcom_variant_ops; } diff --git a/drivers/mmc/host/mmci_qcom_dml.h b/drivers/mmc/host/mmci_qcom_dml.h index 6e405d09d534..fa16f6f4d4ad 100644 --- a/drivers/mmc/host/mmci_qcom_dml.h +++ b/drivers/mmc/host/mmci_qcom_dml.h @@ -16,12 +16,11 @@ #define __MMC_QCOM_DML_H__ #ifdef CONFIG_MMC_QCOM_DML -int dml_hw_init(struct mmci_host *host, struct device_node *np); +void qcom_variant_init(struct mmci_host *host); void dml_start_xfer(struct mmci_host *host, struct mmc_data *data); #else -static inline int dml_hw_init(struct mmci_host *host, struct device_node *np) +static inline void qcom_variant_init(struct mmci_host *host) { - return -ENOSYS; } static inline void dml_start_xfer(struct mmci_host *host, struct mmc_data *data) { diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 6c94474e36f4..f7ffbf1676b1 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -58,11 +58,11 @@ struct pxamci_host { void __iomem *base; struct clk *clk; unsigned long clkrate; - int irq; unsigned int clkrt; unsigned int cmdat; unsigned int imask; unsigned int power_mode; + unsigned long detect_delay_ms; struct pxamci_platform_data *pdata; struct mmc_request *mrq; @@ -72,64 +72,48 @@ struct pxamci_host { struct dma_chan *dma_chan_rx; struct dma_chan *dma_chan_tx; dma_cookie_t dma_cookie; - dma_addr_t sg_dma; unsigned int dma_len; - unsigned int dma_dir; - unsigned int dma_drcmrrx; - unsigned int dma_drcmrtx; - - struct regulator *vcc; }; -static inline void pxamci_init_ocr(struct pxamci_host *host) +static int pxamci_init_ocr(struct pxamci_host *host) { -#ifdef CONFIG_REGULATOR - host->vcc = devm_regulator_get_optional(mmc_dev(host->mmc), "vmmc"); - - if (IS_ERR(host->vcc)) - host->vcc = NULL; - else { - host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc); - if (host->pdata && host->pdata->ocr_mask) - dev_warn(mmc_dev(host->mmc), - "ocr_mask/setpower will not be used\n"); - } -#endif - if (host->vcc == NULL) { + struct mmc_host *mmc = host->mmc; + int ret; + + ret = mmc_regulator_get_supply(mmc); + if (ret < 0) + return ret; + + if (IS_ERR(mmc->supply.vmmc)) { /* fall-back to platform data */ - host->mmc->ocr_avail = host->pdata ? + mmc->ocr_avail = host->pdata ? host->pdata->ocr_mask : MMC_VDD_32_33 | MMC_VDD_33_34; } + + return 0; } static inline int pxamci_set_power(struct pxamci_host *host, unsigned char power_mode, unsigned int vdd) { + struct mmc_host *mmc = host->mmc; + struct regulator *supply = mmc->supply.vmmc; int on; - if (host->vcc) { - int ret; + if (!IS_ERR(supply)) + return mmc_regulator_set_ocr(mmc, supply, vdd); - if (power_mode == MMC_POWER_UP) { - ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd); - if (ret) - return ret; - } else if (power_mode == MMC_POWER_OFF) { - ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0); - if (ret) - return ret; - } - } - if (!host->vcc && host->pdata && + if (host->pdata && gpio_is_valid(host->pdata->gpio_power)) { on = ((1 << vdd) & host->pdata->ocr_mask); gpio_set_value(host->pdata->gpio_power, !!on ^ host->pdata->gpio_power_invert); } - if (!host->vcc && host->pdata && host->pdata->setpower) + + if (host->pdata && host->pdata->setpower) return host->pdata->setpower(mmc_dev(host->mmc), vdd); return 0; @@ -584,7 +568,7 @@ static irqreturn_t pxamci_detect_irq(int irq, void *devid) { struct pxamci_host *host = mmc_priv(devid); - mmc_detect_change(devid, msecs_to_jiffies(host->pdata->detect_delay_ms)); + mmc_detect_change(devid, msecs_to_jiffies(host->detect_delay_ms)); return IRQ_HANDLED; } @@ -596,37 +580,30 @@ static const struct of_device_id pxa_mmc_dt_ids[] = { MODULE_DEVICE_TABLE(of, pxa_mmc_dt_ids); -static int pxamci_of_init(struct platform_device *pdev) +static int pxamci_of_init(struct platform_device *pdev, + struct mmc_host *mmc) { - struct device_node *np = pdev->dev.of_node; - struct pxamci_platform_data *pdata; - u32 tmp; - - if (!np) - return 0; - - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return -ENOMEM; + struct device_node *np = pdev->dev.of_node; + struct pxamci_host *host = mmc_priv(mmc); + u32 tmp; + int ret; - pdata->gpio_card_detect = - of_get_named_gpio(np, "cd-gpios", 0); - pdata->gpio_card_ro = - of_get_named_gpio(np, "wp-gpios", 0); + if (!np) + return 0; /* pxa-mmc specific */ - pdata->gpio_power = - of_get_named_gpio(np, |
