Merge branch 'fixes' into next
authorUlf Hansson <ulf.hansson@linaro.org>
Mon, 5 Mar 2018 12:04:37 +0000 (13:04 +0100)
committerUlf Hansson <ulf.hansson@linaro.org>
Mon, 5 Mar 2018 12:04:37 +0000 (13:04 +0100)
20 files changed:
Documentation/devicetree/bindings/mmc/mtk-sd.txt
Documentation/devicetree/bindings/mmc/tmio_mmc.txt
arch/sh/boards/mach-kfr2r09/setup.c
drivers/mmc/core/core.c
drivers/mmc/core/debugfs.c
drivers/mmc/core/slot-gpio.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h
drivers/mmc/host/mtk-sd.c
drivers/mmc/host/renesas_sdhi_internal_dmac.c
drivers/mmc/host/renesas_sdhi_sys_dmac.c
drivers/mmc/host/sdhci-iproc.c
drivers/mmc/host/sdhci-omap.c
drivers/mmc/host/sdhci-pci-core.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/tmio_mmc_core.c
drivers/mmc/host/ushc.c
include/linux/mfd/tmio.h
include/linux/mmc/slot-gpio.h

index 9b80176..f33467a 100644 (file)
@@ -12,6 +12,7 @@ Required properties:
        "mediatek,mt8173-mmc": for mmc host ip compatible with mt8173
        "mediatek,mt2701-mmc": for mmc host ip compatible with mt2701
        "mediatek,mt2712-mmc": for mmc host ip compatible with mt2712
+       "mediatek,mt7622-mmc": for MT7622 SoC
        "mediatek,mt7623-mmc", "mediatek,mt2701-mmc": for MT7623 SoC
 
 - reg: physical base address of the controller and length
index d8685cb..2d5287e 100644 (file)
@@ -50,7 +50,6 @@ Required properties:
          2: R7S72100
 
 Optional properties:
-- toshiba,mmc-wrprotect-disable: write-protect detection is unavailable
 - pinctrl-names: should be "default", "state_uhs"
 - pinctrl-0: should contain default/high speed pin ctrl
 - pinctrl-1: should contain uhs mode pin ctrl
index 5deb2d8..6af7777 100644 (file)
@@ -375,8 +375,8 @@ static struct resource kfr2r09_sh_sdhi0_resources[] = {
 static struct tmio_mmc_data sh7724_sdhi0_data = {
        .chan_priv_tx   = (void *)SHDMA_SLAVE_SDHI0_TX,
        .chan_priv_rx   = (void *)SHDMA_SLAVE_SDHI0_RX,
-       .flags          = TMIO_MMC_WRPROTECT_DISABLE,
        .capabilities   = MMC_CAP_SDIO_IRQ,
+       .capabilities2  = MMC_CAP2_NO_WRITE_PROTECT,
 };
 
 static struct platform_device kfr2r09_sh_sdhi0_device = {
index c0ba6d8..121ce50 100644 (file)
@@ -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);
        }
 
index 0f4a7d7..c51e0c0 100644 (file)
@@ -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)
 {
index 3698b05..31f7dbb 100644 (file)
@@ -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.
  */
index 5455505..09ed242 100644 (file)
@@ -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;
index 1424bd4..9c7085a 100644 (file)
@@ -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)
index 6457a7d..cb274e8 100644 (file)
@@ -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);
index 7c03cfe..a04f31f 100644 (file)
@@ -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);
index 82d757c..4bb46c4 100644 (file)
@@ -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;
index 61666d2..0ef741b 100644 (file)
@@ -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,
 };
 
index 628bfe9..1456abd 100644 (file)
 #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
 
 #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
 #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;
index 82c4f05..787434e 100644 (file)
@@ -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);
index 2020e57..2ededa7 100644 (file)
@@ -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;
index 7bb00c6..4c2a1f8 100644 (file)
@@ -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
index 3349424..e30df9a 100644 (file)
@@ -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))
index 1d84335..81dac17 100644 (file)
@@ -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);
index 396a103..91f9221 100644 (file)
@@ -36,7 +36,6 @@
        } while (0)
 
 /* tmio MMC platform flags */
-#define TMIO_MMC_WRPROTECT_DISABLE     BIT(0)
 /*
  * Some controllers can support a 2-byte block size when the bus width
  * is configured in 4-bit mode.
index 91f1ba0..06607c5 100644 (file)
@@ -31,6 +31,7 @@ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
                         unsigned int debounce, bool *gpio_invert);
 void mmc_gpio_set_cd_isr(struct mmc_host *host,
                         irqreturn_t (*isr)(int irq, void *dev_id));
+int mmc_gpio_set_cd_wake(struct mmc_host *host, bool on);
 void mmc_gpiod_request_cd_irq(struct mmc_host *host);
 bool mmc_can_gpio_cd(struct mmc_host *host);
 bool mmc_can_gpio_ro(struct mmc_host *host);