diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/core/core.c | 5 | ||||
-rw-r--r-- | drivers/mmc/core/debugfs.c | 13 | ||||
-rw-r--r-- | drivers/mmc/core/slot-gpio.c | 23 | ||||
-rw-r--r-- | drivers/mmc/host/dw_mmc.c | 29 | ||||
-rw-r--r-- | drivers/mmc/host/dw_mmc.h | 19 | ||||
-rw-r--r-- | drivers/mmc/host/mtk-sd.c | 12 | ||||
-rw-r--r-- | drivers/mmc/host/renesas_sdhi_internal_dmac.c | 12 | ||||
-rw-r--r-- | drivers/mmc/host/renesas_sdhi_sys_dmac.c | 20 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-iproc.c | 1 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-omap.c | 378 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-pci-core.c | 43 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 19 | ||||
-rw-r--r-- | drivers/mmc/host/sh_mmcif.c | 8 | ||||
-rw-r--r-- | drivers/mmc/host/tmio_mmc_core.c | 66 | ||||
-rw-r--r-- | drivers/mmc/host/ushc.c | 2 |
15 files changed, 509 insertions, 141 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index c0ba6d8823b7..121ce50b6d5e 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2369,7 +2369,7 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card) return card->pref_erase; max_discard = mmc_do_calc_max_discard(card, MMC_ERASE_ARG); - if (mmc_can_trim(card)) { + if (max_discard && mmc_can_trim(card)) { max_trim = mmc_do_calc_max_discard(card, MMC_TRIM_ARG); if (max_trim < max_discard) max_discard = max_trim; @@ -2655,8 +2655,7 @@ void mmc_start_host(struct mmc_host *host) void mmc_stop_host(struct mmc_host *host) { if (host->slot.cd_irq >= 0) { - if (host->slot.cd_wake_enabled) - disable_irq_wake(host->slot.cd_irq); + mmc_gpio_set_cd_wake(host, false); disable_irq(host->slot.cd_irq); } diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c index 0f4a7d7b2626..c51e0c044a3e 100644 --- a/drivers/mmc/core/debugfs.c +++ b/drivers/mmc/core/debugfs.c @@ -196,18 +196,7 @@ static int mmc_ios_show(struct seq_file *s, void *data) return 0; } - -static int mmc_ios_open(struct inode *inode, struct file *file) -{ - return single_open(file, mmc_ios_show, inode->i_private); -} - -static const struct file_operations mmc_ios_fops = { - .open = mmc_ios_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(mmc_ios); static int mmc_clock_opt_get(void *data, u64 *val) { diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 3698b0576009..31f7dbb15668 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -149,11 +149,30 @@ void mmc_gpiod_request_cd_irq(struct mmc_host *host) if (irq < 0) host->caps |= MMC_CAP_NEEDS_POLL; - else if ((host->caps & MMC_CAP_CD_WAKE) && !enable_irq_wake(irq)) - host->slot.cd_wake_enabled = true; } EXPORT_SYMBOL(mmc_gpiod_request_cd_irq); +int mmc_gpio_set_cd_wake(struct mmc_host *host, bool on) +{ + int ret = 0; + + if (!(host->caps & MMC_CAP_CD_WAKE) || + host->slot.cd_irq < 0 || + on == host->slot.cd_wake_enabled) + return 0; + + if (on) { + ret = enable_irq_wake(host->slot.cd_irq); + host->slot.cd_wake_enabled = !ret; + } else { + disable_irq_wake(host->slot.cd_irq); + host->slot.cd_wake_enabled = false; + } + + return ret; +} +EXPORT_SYMBOL(mmc_gpio_set_cd_wake); + /* Register an alternate interrupt service routine for * the card-detect GPIO. */ diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 545550591389..09ed242de464 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -147,19 +147,7 @@ static int dw_mci_req_show(struct seq_file *s, void *v) return 0; } - -static int dw_mci_req_open(struct inode *inode, struct file *file) -{ - return single_open(file, dw_mci_req_show, inode->i_private); -} - -static const struct file_operations dw_mci_req_fops = { - .owner = THIS_MODULE, - .open = dw_mci_req_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(dw_mci_req); static int dw_mci_regs_show(struct seq_file *s, void *v) { @@ -178,19 +166,7 @@ static int dw_mci_regs_show(struct seq_file *s, void *v) return 0; } - -static int dw_mci_regs_open(struct inode *inode, struct file *file) -{ - return single_open(file, dw_mci_regs_show, inode->i_private); -} - -static const struct file_operations dw_mci_regs_fops = { - .owner = THIS_MODULE, - .open = dw_mci_regs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(dw_mci_regs); static void dw_mci_init_debugfs(struct dw_mci_slot *slot) { @@ -2028,7 +2004,6 @@ static void dw_mci_tasklet_func(unsigned long priv) set_bit(EVENT_CMD_COMPLETE, &host->completed_events); err = dw_mci_command_complete(host, cmd); if (cmd == mrq->sbc && !err) { - prev_state = state = STATE_SENDING_CMD; __dw_mci_start_request(host, host->slot, mrq->cmd); goto unlock; diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 1424bd490dd1..9c7085ab63df 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -65,8 +65,7 @@ struct dw_mci_dma_slave { * @fifo_reg: Pointer to MMIO registers for data FIFO * @sg: Scatterlist entry currently being processed by PIO code, if any. * @sg_miter: PIO mapping scatterlist iterator. - * @cur_slot: The slot which is currently using the controller. - * @mrq: The request currently being processed on @cur_slot, + * @mrq: The request currently being processed on @slot, * or NULL if the controller is idle. * @cmd: The command currently being sent to the card, or NULL. * @data: The data currently being transferred, or NULL if no data @@ -102,7 +101,6 @@ struct dw_mci_dma_slave { * @bus_hz: The rate of @mck in Hz. This forms the basis for MMC bus * rate and timeout calculations. * @current_speed: Configured rate of the controller. - * @num_slots: Number of slots available. * @fifoth_val: The value of FIFOTH register. * @verid: Denote Version ID. * @dev: Device associated with the MMC controller. @@ -134,17 +132,17 @@ struct dw_mci_dma_slave { * ======= * * @lock is a softirq-safe spinlock protecting @queue as well as + * @slot, @mrq and @state. These must always be updated * at the same time while holding @lock. + * The @mrq field of struct dw_mci_slot is also protected by @lock, + * and must always be written at the same time as the slot is added to + * @queue. * * @irq_lock is an irq-safe spinlock protecting the INTMASK register * to allow the interrupt handler to modify it directly. Held for only long * enough to read-modify-write INTMASK and no other locks are grabbed when * holding this one. * - * The @mrq field of struct dw_mci_slot is also protected by @lock, - * and must always be written at the same time as the slot is added to - * @queue. - * * @pending_events and @completed_events are accessed using atomic bit * operations, so they don't need any locking. * @@ -321,8 +319,8 @@ struct dw_mci_board { #define SDMMC_ENABLE_SHIFT 0x110 #define SDMMC_DATA(x) (x) /* -* Registers to support idmac 64-bit address mode -*/ + * Registers to support idmac 64-bit address mode + */ #define SDMMC_DBADDRL 0x088 #define SDMMC_DBADDRU 0x08c #define SDMMC_IDSTS64 0x090 @@ -449,7 +447,8 @@ struct dw_mci_board { (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) /* FIFO register access macros. These should not change the data endian-ness - * as they are written to memory to be dealt with by the upper layers */ + * as they are written to memory to be dealt with by the upper layers + */ #define mci_fifo_readw(__reg) __raw_readw(__reg) #define mci_fifo_readl(__reg) __raw_readl(__reg) #define mci_fifo_readq(__reg) __raw_readq(__reg) diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c index 6457a7d8880f..cb274e822293 100644 --- a/drivers/mmc/host/mtk-sd.c +++ b/drivers/mmc/host/mtk-sd.c @@ -438,11 +438,23 @@ static const struct mtk_mmc_compatible mt2712_compat = { .enhance_rx = true, }; +static const struct mtk_mmc_compatible mt7622_compat = { + .clk_div_bits = 12, + .hs400_tune = false, + .pad_tune_reg = MSDC_PAD_TUNE0, + .async_fifo = true, + .data_tune = true, + .busy_check = true, + .stop_clk_fix = true, + .enhance_rx = true, +}; + static const struct of_device_id msdc_of_ids[] = { { .compatible = "mediatek,mt8135-mmc", .data = &mt8135_compat}, { .compatible = "mediatek,mt8173-mmc", .data = &mt8173_compat}, { .compatible = "mediatek,mt2701-mmc", .data = &mt2701_compat}, { .compatible = "mediatek,mt2712-mmc", .data = &mt2712_compat}, + { .compatible = "mediatek,mt7622-mmc", .data = &mt7622_compat}, {} }; MODULE_DEVICE_TABLE(of, msdc_of_ids); diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c b/drivers/mmc/host/renesas_sdhi_internal_dmac.c index 7c03cfead6f9..a04f31fea72f 100644 --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c @@ -71,11 +71,11 @@ static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = { }; static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = { - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | - TMIO_MMC_CLK_ACTUAL | TMIO_MMC_HAVE_CBSY | - TMIO_MMC_MIN_RCAR2, + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL | + TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | MMC_CAP_CMD23, + .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, .bus_shift = 2, .scc_offset = 0x1000, .taps = rcar_gen3_scc_taps, @@ -145,7 +145,6 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host, u32 dtran_mode = DTRAN_MODE_BUS_WID_TH | DTRAN_MODE_ADDR_MODE; enum dma_data_direction dir; int ret; - u32 irq_mask; /* This DMAC cannot handle if sg_len is not 1 */ WARN_ON(host->sg_len > 1); @@ -157,11 +156,9 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host, if (data->flags & MMC_DATA_READ) { dtran_mode |= DTRAN_MODE_CH_NUM_CH1; dir = DMA_FROM_DEVICE; - irq_mask = TMIO_STAT_RXRDY; } else { dtran_mode |= DTRAN_MODE_CH_NUM_CH0; dir = DMA_TO_DEVICE; - irq_mask = TMIO_STAT_TXRQ; } ret = dma_map_sg(&host->pdev->dev, sg, host->sg_len, dir); @@ -170,9 +167,6 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host, renesas_sdhi_internal_dmac_enable_dma(host, true); - /* disable PIO irqs to avoid "PIO IRQ in DMA mode!" */ - tmio_mmc_disable_mmc_irqs(host, irq_mask); - /* set dma parameters */ renesas_sdhi_internal_dmac_dm_write(host, DM_CM_DTRAN_MODE, dtran_mode); diff --git a/drivers/mmc/host/renesas_sdhi_sys_dmac.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c index 82d757c480b2..4bb46c489d71 100644 --- a/drivers/mmc/host/renesas_sdhi_sys_dmac.c +++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c @@ -40,9 +40,9 @@ static const struct renesas_sdhi_of_data of_rz_compatible = { }; static const struct renesas_sdhi_of_data of_rcar_gen1_compatible = { - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | - TMIO_MMC_CLK_ACTUAL, + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ, + .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, }; /* Definitions for sampling clocks */ @@ -58,11 +58,11 @@ static struct renesas_sdhi_scc rcar_gen2_scc_taps[] = { }; static const struct renesas_sdhi_of_data of_rcar_gen2_compatible = { - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | - TMIO_MMC_CLK_ACTUAL | TMIO_MMC_HAVE_CBSY | - TMIO_MMC_MIN_RCAR2, + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL | + TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | MMC_CAP_CMD23, + .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES, .dma_rx_offset = 0x2000, .scc_offset = 0x0300, @@ -79,11 +79,11 @@ static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = { }; static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = { - .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE | - TMIO_MMC_CLK_ACTUAL | TMIO_MMC_HAVE_CBSY | - TMIO_MMC_MIN_RCAR2, + .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL | + TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2, .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ | MMC_CAP_CMD23, + .capabilities2 = MMC_CAP2_NO_WRITE_PROTECT, .bus_shift = 2, .scc_offset = 0x1000, .taps = rcar_gen3_scc_taps, @@ -205,8 +205,6 @@ static void renesas_sdhi_sys_dmac_start_dma_rx(struct tmio_mmc_host *host) return; } - tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_RXRDY); - /* The only sg element can be unaligned, use our bounce buffer then */ if (!aligned) { sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length); @@ -280,8 +278,6 @@ static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host) return; } - tmio_mmc_disable_mmc_irqs(host, TMIO_STAT_TXRQ); - /* The only sg element can be unaligned, use our bounce buffer then */ if (!aligned) { unsigned long flags; diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index 61666d269771..0ef741bc515d 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -214,6 +214,7 @@ static const struct sdhci_pltfm_data sdhci_bcm2835_pltfm_data = { SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | SDHCI_QUIRK_MISSING_CAPS | SDHCI_QUIRK_NO_HISPD_BIT, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, .ops = &sdhci_iproc_32only_ops, }; diff --git a/drivers/mmc/host/sdhci-omap.c b/drivers/mmc/host/sdhci-omap.c index 628bfe9a3d17..1456abd5eeb9 100644 --- a/drivers/mmc/host/sdhci-omap.c +++ b/drivers/mmc/host/sdhci-omap.c @@ -25,17 +25,32 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/pinctrl/consumer.h> #include "sdhci-pltfm.h" #define SDHCI_OMAP_CON 0x12c #define CON_DW8 BIT(5) #define CON_DMA_MASTER BIT(20) +#define CON_DDR BIT(19) +#define CON_CLKEXTFREE BIT(16) +#define CON_PADEN BIT(15) #define CON_INIT BIT(1) #define CON_OD BIT(0) +#define SDHCI_OMAP_DLL 0x0134 +#define DLL_SWT BIT(20) +#define DLL_FORCE_SR_C_SHIFT 13 +#define DLL_FORCE_SR_C_MASK (0x7f << DLL_FORCE_SR_C_SHIFT) +#define DLL_FORCE_VALUE BIT(12) +#define DLL_CALIB BIT(1) + #define SDHCI_OMAP_CMD 0x20c +#define SDHCI_OMAP_PSTATE 0x0224 +#define PSTATE_DLEV_DAT0 BIT(20) +#define PSTATE_DATI BIT(1) + #define SDHCI_OMAP_HCTL 0x228 #define HCTL_SDBP BIT(8) #define HCTL_SDVS_SHIFT 9 @@ -56,12 +71,16 @@ #define SDHCI_OMAP_AC12 0x23c #define AC12_V1V8_SIGEN BIT(19) +#define AC12_SCLK_SEL BIT(23) #define SDHCI_OMAP_CAPA 0x240 #define CAPA_VS33 BIT(24) #define CAPA_VS30 BIT(25) #define CAPA_VS18 BIT(26) +#define SDHCI_OMAP_CAPA2 0x0244 +#define CAPA2_TSDR50 BIT(13) + #define SDHCI_OMAP_TIMEOUT 1 /* 1 msec */ #define SYSCTL_CLKD_MAX 0x3FF @@ -70,8 +89,14 @@ #define IOV_3V0 3000000 /* 300000 uV */ #define IOV_3V3 3300000 /* 330000 uV */ +#define MAX_PHASE_DELAY 0x7C + +/* sdhci-omap controller flags */ +#define SDHCI_OMAP_REQUIRE_IODELAY BIT(0) + struct sdhci_omap_data { u32 offset; + u8 flags; }; struct sdhci_omap_host { @@ -82,8 +107,16 @@ struct sdhci_omap_host { struct sdhci_host *host; u8 bus_mode; u8 power_mode; + u8 timing; + u8 flags; + + struct pinctrl *pinctrl; + struct pinctrl_state **pinctrl_state; }; +static void sdhci_omap_start_clock(struct sdhci_omap_host *omap_host); +static void sdhci_omap_stop_clock(struct sdhci_omap_host *omap_host); + static inline u32 sdhci_omap_readl(struct sdhci_omap_host *host, unsigned int offset) { @@ -191,6 +224,178 @@ static void sdhci_omap_conf_bus_power(struct sdhci_omap_host *omap_host, } } +static inline void sdhci_omap_set_dll(struct sdhci_omap_host *omap_host, + int count) +{ + int i; + u32 reg; + + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL); + reg |= DLL_FORCE_VALUE; + reg &= ~DLL_FORCE_SR_C_MASK; + reg |= (count << DLL_FORCE_SR_C_SHIFT); + sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg); + + reg |= DLL_CALIB; + sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg); + for (i = 0; i < 1000; i++) { + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL); + if (reg & DLL_CALIB) + break; + } + reg &= ~DLL_CALIB; + sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg); +} + +static void sdhci_omap_disable_tuning(struct sdhci_omap_host *omap_host) +{ + u32 reg; + + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12); + reg &= ~AC12_SCLK_SEL; + sdhci_omap_writel(omap_host, SDHCI_OMAP_AC12, reg); + + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL); + reg &= ~(DLL_FORCE_VALUE | DLL_SWT); + sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg); +} + +static int sdhci_omap_execute_tuning(struct mmc_host *mmc, u32 opcode) +{ + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); + struct device *dev = omap_host->dev; + struct mmc_ios *ios = &mmc->ios; + u32 start_window = 0, max_window = 0; + u8 cur_match, prev_match = 0; + u32 length = 0, max_len = 0; + u32 ier = host->ier; + u32 phase_delay = 0; + int ret = 0; + u32 reg; + + pltfm_host = sdhci_priv(host); + omap_host = sdhci_pltfm_priv(pltfm_host); + dev = omap_host->dev; + + /* clock tuning is not needed for upto 52MHz */ + if (ios->clock <= 52000000) + return 0; + + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CAPA2); + if (ios->timing == MMC_TIMING_UHS_SDR50 && !(reg & CAPA2_TSDR50)) + return 0; + + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_DLL); + reg |= DLL_SWT; + sdhci_omap_writel(omap_host, SDHCI_OMAP_DLL, reg); + + /* + * OMAP5/DRA74X/DRA72x Errata i802: + * DCRC error interrupts (MMCHS_STAT[21] DCRC=0x1) can occur + * during the tuning procedure. So disable it during the + * tuning procedure. + */ + ier &= ~SDHCI_INT_DATA_CRC; + sdhci_writel(host, ier, SDHCI_INT_ENABLE); + sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE); + + while (phase_delay <= MAX_PHASE_DELAY) { + sdhci_omap_set_dll(omap_host, phase_delay); + + cur_match = !mmc_send_tuning(mmc, opcode, NULL); + if (cur_match) { + if (prev_match) { + length++; + } else { + start_window = phase_delay; + length = 1; + } + } + + if (length > max_len) { + max_window = start_window; + max_len = length; + } + + prev_match = cur_match; + phase_delay += 4; + } + + if (!max_len) { + dev_err(dev, "Unable to find match\n"); + ret = -EIO; + goto tuning_error; + } + + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12); + if (!(reg & AC12_SCLK_SEL)) { + ret = -EIO; + goto tuning_error; + } + + phase_delay = max_window + 4 * (max_len >> 1); + sdhci_omap_set_dll(omap_host, phase_delay); + + goto ret; + +tuning_error: + dev_err(dev, "Tuning failed\n"); + sdhci_omap_disable_tuning(omap_host); + +ret: + sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + return ret; +} + +static int sdhci_omap_card_busy(struct mmc_host *mmc) +{ + u32 reg, ac12; + int ret = false; + struct sdhci_host *host = mmc_priv(mmc); + struct sdhci_pltfm_host *pltfm_host; + struct sdhci_omap_host *omap_host; + u32 ier = host->ier; + + pltfm_host = sdhci_priv(host); + omap_host = sdhci_pltfm_priv(pltfm_host); + + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); + ac12 = sdhci_omap_readl(omap_host, SDHCI_OMAP_AC12); + reg &= ~CON_CLKEXTFREE; + if (ac12 & AC12_V1V8_SIGEN) + reg |= CON_CLKEXTFREE; + reg |= CON_PADEN; + sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg); + + disable_irq(host->irq); + ier |= SDHCI_INT_CARD_INT; + sdhci_writel(host, ier, SDHCI_INT_ENABLE); + sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE); + + /* + * Delay is required for PSTATE to correctly reflect + * DLEV/CLEV values after PADEN is set. + */ + usleep_range(50, 100); + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_PSTATE); + if ((reg & PSTATE_DATI) || !(reg & PSTATE_DLEV_DAT0)) + ret = true; + + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); + reg &= ~(CON_CLKEXTFREE | CON_PADEN); + sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg); + + sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); + sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); + enable_irq(host->irq); + + return ret; +} + static int sdhci_omap_start_signal_voltage_switch(struct mmc_host *mmc, struct mmc_ios *ios) { @@ -244,6 +449,39 @@ static int sdhci_omap_start_signal_voltage_switch(struct mmc_host *mmc, return 0; } +static void sdhci_omap_set_timing(struct sdhci_omap_host *omap_host, u8 timing) +{ + int ret; + struct pinctrl_state *pinctrl_state; + struct device *dev = omap_host->dev; + + if (!(omap_host->flags & SDHCI_OMAP_REQUIRE_IODELAY)) + return; + + if (omap_host->timing == timing) + return; + + sdhci_omap_stop_clock(omap_host); + + pinctrl_state = omap_host->pinctrl_state[timing]; + ret = pinctrl_select_state(omap_host->pinctrl, pinctrl_state); + if (ret) { + dev_err(dev, "failed to select pinctrl state\n"); + return; + } + + sdhci_omap_start_clock(omap_host); + omap_host->timing = timing; +} + +static void sdhci_omap_set_power_mode(struct sdhci_omap_host *omap_host, + u8 power_mode) +{ + if (omap_host->bus_mode == MMC_POWER_OFF) + sdhci_omap_disable_tuning(omap_host); + omap_host->power_mode = power_mode; +} + static void sdhci_omap_set_bus_mode(struct sdhci_omap_host *omap_host, unsigned int mode) { @@ -272,7 +510,9 @@ static void sdhci_omap_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) omap_host = sdhci_pltfm_priv(pltfm_host); sdhci_omap_set_bus_mode(omap_host, ios->bus_mode); + sdhci_omap_set_timing(omap_host, ios->timing); sdhci_set_ios(mmc, ios); + sdhci_omap_set_power_mode(omap_host, ios->power_mode); } static u16 sdhci_omap_calc_divisor(struct sdhci_pltfm_host *host, @@ -401,8 +641,26 @@ static void sdhci_omap_init_74_clocks(struct sdhci_host *host, u8 power_mode) sdhci_omap_writel(omap_host, SDHCI_OMAP_STAT, INT_CC_EN); enable_irq(host->irq); +} - omap_host->power_mode = power_mode; +static void sdhci_omap_set_uhs_signaling(struct sdhci_host *host, + unsigned int timing) +{ + u32 reg; + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); + + sdhci_omap_stop_clock(omap_host); + + reg = sdhci_omap_readl(omap_host, SDHCI_OMAP_CON); + if (timing == MMC_TIMING_UHS_DDR50 || timing == MMC_TIMING_MMC_DDR52) + reg |= CON_DDR; + else + reg &= ~CON_DDR; + sdhci_omap_writel(omap_host, SDHCI_OMAP_CON, reg); + + sdhci_set_uhs_signaling(host, timing); + sdhci_omap_start_clock(omap_host); } static struct sdhci_ops sdhci_omap_ops = { @@ -414,7 +672,7 @@ static struct sdhci_ops sdhci_omap_ops = { .set_bus_width = sdhci_omap_set_bus_width, .platform_send_init_74_clocks = sdhci_omap_init_74_clocks, .reset = sdhci_reset, - .set_uhs_signaling = sdhci_set_uhs_signaling, + .set_uhs_signaling = sdhci_omap_set_uhs_signaling, }; static int sdhci_omap_set_capabilities(struct sdhci_omap_host *omap_host) @@ -453,14 +711,15 @@ static const struct sdhci_pltfm_data sdhci_omap_pdata = { SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, - .quirks2 = SDHCI_QUIRK2_NO_1_8_V | - SDHCI_QUIRK2_ACMD23_BROKEN | + .quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN | + SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_RSP_136_HAS_CRC, .ops = &sdhci_omap_ops, }; static const struct sdhci_omap_data dra7_data = { .offset = 0x200, + .flags = SDHCI_OMAP_REQUIRE_IODELAY, }; static const struct of_device_id omap_sdhci_match[] = { @@ -469,6 +728,108 @@ static const struct of_device_id omap_sdhci_match[] = { }; MODULE_DEVICE_TABLE(of, omap_sdhci_match); +static struct pinctrl_state +*sdhci_omap_iodelay_pinctrl_state(struct sdhci_omap_host *omap_host, char *mode, + u32 *caps, u32 capmask) +{ + struct device *dev = omap_host->dev; + struct pinctrl_state *pinctrl_state = ERR_PTR(-ENODEV); + + if (!(*caps & capmask)) + goto ret; + + pinctrl_state = pinctrl_lookup_state(omap_host->pinctrl, mode); + if (IS_ERR(pinctrl_state)) { + dev_err(dev, "no pinctrl state for %s mode", mode); + *caps &= ~capmask; + } + +ret: + return pinctrl_state; +} + +static int sdhci_omap_config_iodelay_pinctrl_state(struct sdhci_omap_host + *omap_host) +{ + struct device *dev = omap_host->dev; + struct sdhci_host *host = omap_host->host; + struct mmc_host *mmc = host->mmc; + u32 *caps = &mmc->caps; + u32 *caps2 = &mmc->caps2; + struct pinctrl_state *state; + struct pinctrl_state **pinctrl_state; + + if (!(omap_host->flags & SDHCI_OMAP_REQUIRE_IODELAY)) + return 0; + + pinctrl_state = devm_kzalloc(dev, sizeof(*pinctrl_state) * + (MMC_TIMING_MMC_HS200 + 1), GFP_KERNEL); + if (!pinctrl_state) + return -ENOMEM; + + omap_host->pinctrl = devm_pinctrl_get(omap_host->dev); + if (IS_ERR(omap_host->pinctrl)) { + dev_err(dev, "Cannot get pinctrl\n"); + return PTR_ERR(omap_host->pinctrl); + } + + state = pinctrl_lookup_state(omap_host->pinctrl, "default"); + if (IS_ERR(state)) { + dev_err(dev, "no pinctrl state for default mode\n"); + return PTR_ERR(state); + } + pinctrl_state[MMC_TIMING_LEGACY] = state; + + state = sdhci_omap_iodelay_pinctrl_state(omap_host, "sdr104", caps, + MMC_CAP_UHS_SDR104); + if (!IS_ERR(state)) + pinctrl_state[MMC_TIMING_UHS_SDR104] = state; + + state = sdhci_omap_iodelay_pinctrl_state(omap_host, "ddr50", caps, + MMC_CAP_UHS_DDR50); + if (!IS_ERR(state)) + pinctrl_state[MMC_TIMING_UHS_DDR50] = state; + + state = sdhci_omap_iodelay_pinctrl_state(omap_host, "sdr50", caps, + MMC_CAP_UHS_SDR50); + if (!IS_ERR(state)) + pinctrl_state[MMC_TIMING_UHS_SDR50] = state; + + state = sdhci_omap_iodelay_pinctrl_state(omap_host, "sdr25", caps, + MMC_CAP_UHS_SDR25); + if (!IS_ERR(state)) + pinctrl_state[MMC_TIMING_UHS_SDR25] = state; + + state = sdhci_omap_iodelay_pinctrl_state(omap_host, "sdr12", caps, + MMC_CAP_UHS_SDR12); + if (!IS_ERR(state)) + pinctrl_state[MMC_TIMING_UHS_SDR12] = state; + + state = sdhci_omap_iodelay_pinctrl_state(omap_host, "ddr_1_8v", caps, + MMC_CAP_1_8V_DDR); + if (!IS_ERR(state)) + pinctrl_state[MMC_TIMING_MMC_DDR52] = state; + + state = sdhci_omap_iodelay_pinctrl_state(omap_host, "hs", caps, + MMC_CAP_SD_HIGHSPEED); + if (!IS_ERR(state)) + pinctrl_state[MMC_TIMING_SD_HS] = state; + + state = sdhci_omap_iodelay_pinctrl_state(omap_host, "hs", caps, + MMC_CAP_MMC_HIGHSPEED); + if (!IS_ERR(state)) + pinctrl_state[MMC_TIMING_MMC_HS] = state; + + state = sdhci_omap_iodelay_pinctrl_state(omap_host, "hs200_1_8v", caps2, + MMC_CAP2_HS200_1_8V_SDR); + if (!IS_ERR(state)) + pinctrl_state[MMC_TIMING_MMC_HS200] = state; + + omap_host->pinctrl_state = pinctrl_state; + + return 0; +} + static int sdhci_omap_probe(struct platform_device *pdev) { int ret; @@ -504,6 +865,9 @@ static int sdhci_omap_probe(struct platform_device *pdev) omap_host->host = host; omap_host->base = host->ioaddr; omap_host->dev = dev; + omap_host->power_mode = MMC_POWER_UNDEFINED; + omap_host->timing = MMC_TIMING_LEGACY; + omap_host->flags = data->flags; host->ioaddr += offset; mmc = host->mmc; @@ -552,10 +916,16 @@ static int sdhci_omap_probe(struct platform_device *pdev) goto err_put_sync; } + ret = sdhci_omap_config_iodelay_pinctrl_state(omap_host); + if (ret) + goto err_put_sync; + host->mmc_host_ops.get_ro = mmc_gpio_get_ro; host->mmc_host_ops.start_signal_voltage_switch = sdhci_omap_start_signal_voltage_switch; host->mmc_host_ops.set_ios = sdhci_omap_set_ios; + host->mmc_host_ops.card_busy = sdhci_omap_card_busy; + host->mmc_host_ops.execute_tuning = sdhci_omap_execute_tuning; sdhci_read_caps(host); host->caps |= SDHCI_CAN_DO_ADMA2; diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 82c4f05f91d8..787434e5589d 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -41,18 +41,25 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host); static int sdhci_pci_init_wakeup(struct sdhci_pci_chip *chip) { mmc_pm_flag_t pm_flags = 0; + bool cap_cd_wake = false; int i; for (i = 0; i < chip->num_slots; i++) { struct sdhci_pci_slot *slot = chip->slots[i]; - if (slot) + if (slot) { pm_flags |= slot->host->mmc->pm_flags; + if (slot->host->mmc->caps & MMC_CAP_CD_WAKE) + cap_cd_wake = true; + } } - return device_set_wakeup_enable(&chip->pdev->dev, - (pm_flags & MMC_PM_KEEP_POWER) && - (pm_flags & MMC_PM_WAKE_SDIO_IRQ)); + if ((pm_flags & MMC_PM_KEEP_POWER) && (pm_flags & MMC_PM_WAKE_SDIO_IRQ)) + return device_wakeup_enable(&chip->pdev->dev); + else if (!cap_cd_wake) + return device_wakeup_disable(&chip->pdev->dev); + + return 0; } static int sdhci_pci_suspend_host(struct sdhci_pci_chip *chip) @@ -76,6 +83,9 @@ static int sdhci_pci_suspend_host(struct sdhci_pci_chip *chip) ret = sdhci_suspend_host(host); if (ret) goto err_pci_suspend; + + if (device_may_wakeup(&chip->pdev->dev)) + mmc_gpio_set_cd_wake(host->mmc, true); } return 0; @@ -99,6 +109,8 @@ int sdhci_pci_resume_host(struct sdhci_pci_chip *chip) ret = sdhci_resume_host(slot->host); if (ret) return ret; + + mmc_gpio_set_cd_wake(slot->host->mmc, false); } return 0; @@ -712,26 +724,8 @@ static int glk_emmc_probe_slot(struct sdhci_pci_slot *slot) return ret; } -static void glk_cqe_enable(struct mmc_host *mmc) -{ - struct sdhci_host *host = mmc_priv(mmc); - u32 reg; - - /* - * CQE gets stuck if it sees Buffer Read Enable bit set, which can be - * the case after tuning, so ensure the buffer is drained. - */ - reg = sdhci_readl(host, SDHCI_PRESENT_STATE); - while (reg & SDHCI_DATA_AVAILABLE) { - sdhci_readl(host, SDHCI_BUFFER); - reg = sdhci_readl(host, SDHCI_PRESENT_STATE); - } - - sdhci_cqe_enable(mmc); -} - static const struct cqhci_host_ops glk_cqhci_ops = { - .enable = glk_cqe_enable, + .enable = sdhci_cqe_enable, .disable = sdhci_cqe_disable, .dumpregs = sdhci_pci_dumpregs, }; @@ -1716,6 +1710,9 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( if (device_can_wakeup(&pdev->dev)) host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; + if (host->mmc->caps & MMC_CAP_CD_WAKE) + device_init_wakeup(&pdev->dev, true); + if (slot->cd_idx >= 0) { ret = mmc_gpiod_request_cd(host->mmc, NULL, slot->cd_idx, slot->cd_override_level, 0, NULL); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 2020e57ffa7e..2ededa7f43df 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2899,6 +2899,14 @@ static irqreturn_t sdhci_thread_irq(int irq, void *dev_id) \*****************************************************************************/ #ifdef CONFIG_PM + +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); +} + /* * To enable wakeup events, the corresponding events have to be enabled in * the Interrupt Status Enable register too. See 'Table 1-6: Wakeup Signal @@ -2915,13 +2923,18 @@ static bool sdhci_enable_irq_wakeups(struct sdhci_host *host) u8 wake_val = 0; u8 val; - if (!(host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)) { + if (sdhci_cd_irq_can_wakeup(host)) { wake_val |= SDHCI_WAKE_ON_INSERT | SDHCI_WAKE_ON_REMOVE; irq_val |= SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE; } - wake_val |= SDHCI_WAKE_ON_INT; - irq_val |= SDHCI_INT_CARD_INT; + if (mmc_card_wake_sdio_irq(host->mmc)) { + wake_val |= SDHCI_WAKE_ON_INT; + irq_val |= SDHCI_INT_CARD_INT; + } + + if (!irq_val) + return false; val = sdhci_readb(host, SDHCI_WAKE_UP_CONTROL); val &= ~mask; diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 7bb00c68a756..4c2a1f8ddbf3 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -7,13 +7,6 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License. - * - * - * TODO - * 1. DMA - * 2. Power management - * 3. Handle MMC errors better - * */ /* @@ -67,7 +60,6 @@ #include <linux/module.h> #define DRIVER_NAME "sh_mmcif" -#define DRIVER_VERSION "2010-04-28" /* CE_CMD_SET */ #define CMD_MASK 0x3f000000 diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c index 33494241245a..e30df9ad8197 100644 --- a/drivers/mmc/host/tmio_mmc_core.c +++ b/drivers/mmc/host/tmio_mmc_core.c @@ -278,7 +278,6 @@ static void tmio_mmc_reset_work(struct work_struct *work) host->cmd = NULL; host->data = NULL; - host->force_pio = false; spin_unlock_irqrestore(&host->lock, flags); @@ -350,8 +349,6 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, c |= TRANSFER_READ; } - if (!host->native_hotplug) - irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT); tmio_mmc_enable_mmc_irqs(host, irq_mask); /* Fire off the command */ @@ -623,15 +620,21 @@ static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, unsigned int stat) */ if (host->data && (!cmd->error || cmd->error == -EILSEQ)) { if (host->data->flags & MMC_DATA_READ) { - if (host->force_pio || !host->chan_rx) + if (host->force_pio || !host->chan_rx) { tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_READOP); - else + } else { + tmio_mmc_disable_mmc_irqs(host, + TMIO_MASK_READOP); tasklet_schedule(&host->dma_issue); + } } else { - if (host->force_pio || !host->chan_tx) + if (host->force_pio || !host->chan_tx) { tmio_mmc_enable_mmc_irqs(host, TMIO_MASK_WRITEOP); - else + } else { + tmio_mmc_disable_mmc_irqs(host, + TMIO_MASK_WRITEOP); tasklet_schedule(&host->dma_issue); + } } } else { schedule_work(&host->done); @@ -755,6 +758,7 @@ static int tmio_mmc_start_data(struct tmio_mmc_host *host, tmio_mmc_init_sg(host, data); host->data = data; + host->force_pio = false; /* Set transfer length / blocksize */ sd_ctrl_write16(host, CTL_SD_XFER_LEN, data->blksz); @@ -846,7 +850,6 @@ static void tmio_process_mrq(struct tmio_mmc_host *host, return; fail: - host->force_pio = false; host->mrq = NULL; mrq->cmd->error = ret; mmc_request_done(host->mmc, mrq); @@ -896,7 +899,6 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host) if (host->cmd != mrq->sbc) { host->cmd = NULL; host->data = NULL; - host->force_pio = false; host->mrq = NULL; } @@ -1061,10 +1063,17 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) static int tmio_mmc_get_ro(struct mmc_host *mmc) { struct tmio_mmc_host *host = mmc_priv(mmc); - struct tmio_mmc_data *pdata = host->pdata; - return !((pdata->flags & TMIO_MMC_WRPROTECT_DISABLE) || - (sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)); + return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & + TMIO_STAT_WRPROTECT); +} + +static int tmio_mmc_get_cd(struct mmc_host *mmc) +{ + struct tmio_mmc_host *host = mmc_priv(mmc); + + return !!(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & + TMIO_STAT_SIGSTATE); } static int tmio_multi_io_quirk(struct mmc_card *card, @@ -1082,7 +1091,7 @@ static const struct mmc_host_ops tmio_mmc_ops = { .request = tmio_mmc_request, .set_ios = tmio_mmc_set_ios, .get_ro = tmio_mmc_get_ro, - .get_cd = mmc_gpio_get_cd, + .get_cd = tmio_mmc_get_cd, .enable_sdio_irq = tmio_mmc_enable_sdio_irq, .multi_io_quirk = tmio_multi_io_quirk, .hw_reset = tmio_mmc_hw_reset, @@ -1114,15 +1123,20 @@ static int tmio_mmc_init_ocr(struct tmio_mmc_host *host) } static void tmio_mmc_of_parse(struct platform_device *pdev, - struct tmio_mmc_data *pdata) + struct mmc_host *mmc) { const struct device_node *np = pdev->dev.of_node; if (!np) return; + /* + * DEPRECATED: + * For new platforms, please use "disable-wp" instead of + * "toshiba,mmc-wrprotect-disable" + */ if (of_get_property(np, "toshiba,mmc-wrprotect-disable", NULL)) - pdata->flags |= TMIO_MMC_WRPROTECT_DISABLE; + mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT; } struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev, @@ -1157,7 +1171,7 @@ struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev, goto free; } - tmio_mmc_of_parse(pdev, pdata); + tmio_mmc_of_parse(pdev, mmc); platform_set_drvdata(pdev, host); @@ -1181,7 +1195,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) struct tmio_mmc_data *pdata = _host->pdata; struct mmc_host *mmc = _host->mmc; int ret; - u32 irq_mask = TMIO_MASK_CMD; /* * Check the sanity of mmc->f_min to prevent tmio_mmc_set_clock() from @@ -1230,6 +1243,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) if (mmc_can_gpio_ro(mmc)) _host->ops.get_ro = mmc_gpio_get_ro; + if (mmc_can_gpio_cd(mmc)) + _host->ops.get_cd = mmc_gpio_get_cd; + _host->native_hotplug = !(mmc_can_gpio_cd(mmc) || mmc->caps & MMC_CAP_NEEDS_POLL || !mmc_card_is_removable(mmc)); @@ -1260,15 +1276,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host) _host->sdcard_irq_mask = sd_ctrl_read16_and_16_as_32(_host, CTL_IRQ_MASK); tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL); - /* Unmask the IRQs we want to know about */ - if (!_host->chan_rx) - irq_mask |= TMIO_MASK_READOP; - if (!_host->chan_tx) - irq_mask |= TMIO_MASK_WRITEOP; - if (!_host->native_hotplug) - irq_mask &= ~(TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT); - - _host->sdcard_irq_mask &= ~irq_mask; + if (_host->native_hotplug) + tmio_mmc_enable_mmc_irqs(_host, + TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT); spin_lock_init(&_host->lock); mutex_init(&_host->ios_lock); @@ -1367,6 +1377,10 @@ int tmio_mmc_host_runtime_resume(struct device *dev) if (host->clk_cache) tmio_mmc_set_clock(host, host->clk_cache); + if (host->native_hotplug) + tmio_mmc_enable_mmc_irqs(host, + TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT); + tmio_mmc_enable_dma(host, true); if (tmio_mmc_can_retune(host) && host->select_tuning(host)) diff --git a/drivers/mmc/host/ushc.c b/drivers/mmc/host/ushc.c index 1d843357422e..81dac17064d7 100644 --- a/drivers/mmc/host/ushc.c +++ b/drivers/mmc/host/ushc.c @@ -309,8 +309,6 @@ static void ushc_request(struct mmc_host *mmc, struct mmc_request *req) /* Submit CSW. */ ret = usb_submit_urb(ushc->csw_urb, GFP_ATOMIC); - if (ret < 0) - goto out; out: spin_unlock_irqrestore(&ushc->lock, flags); |