Loading arch/arm/mach-ux500/board-mop500-sdi.c +8 −13 Original line number Diff line number Diff line Loading @@ -31,21 +31,13 @@ * SDI 0 (MicroSD slot) */ /* MMCIPOWER bits */ #define MCI_DATA2DIREN (1 << 2) #define MCI_CMDDIREN (1 << 3) #define MCI_DATA0DIREN (1 << 4) #define MCI_DATA31DIREN (1 << 5) #define MCI_FBCLKEN (1 << 7) /* GPIO pins used by the sdi0 level shifter */ static int sdi0_en = -1; static int sdi0_vsel = -1; static u32 mop500_sdi0_vdd_handler(struct device *dev, unsigned int vdd, unsigned char power_mode) static int mop500_sdi0_ios_handler(struct device *dev, struct mmc_ios *ios) { switch (power_mode) { switch (ios->power_mode) { case MMC_POWER_UP: case MMC_POWER_ON: /* Loading @@ -65,8 +57,7 @@ static u32 mop500_sdi0_vdd_handler(struct device *dev, unsigned int vdd, break; } return MCI_FBCLKEN | MCI_CMDDIREN | MCI_DATA0DIREN | MCI_DATA2DIREN | MCI_DATA31DIREN; return 0; } #ifdef CONFIG_STE_DMA40 Loading @@ -90,13 +81,17 @@ static struct stedma40_chan_cfg mop500_sdi0_dma_cfg_tx = { #endif static struct mmci_platform_data mop500_sdi0_data = { .vdd_handler = mop500_sdi0_vdd_handler, .ios_handler = mop500_sdi0_ios_handler, .ocr_mask = MMC_VDD_29_30, .f_max = 50000000, .capabilities = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED, .gpio_wp = -1, .sigdir = MCI_ST_FBCLKEN | MCI_ST_CMDDIREN | MCI_ST_DATA0DIREN | MCI_ST_DATA2DIREN, #ifdef CONFIG_STE_DMA40 .dma_filter = stedma40_filter, .dma_rx_param = &mop500_sdi0_dma_cfg_rx, Loading drivers/mmc/host/mmci.c +121 −45 Original line number Diff line number Diff line Loading @@ -53,6 +53,8 @@ static unsigned int fmax = 515633; * @sdio: variant supports SDIO * @st_clkdiv: true if using a ST-specific clock divider algorithm * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register * @pwrreg_powerup: power up value for MMCIPOWER register * @signal_direction: input/out direction of bus signals can be indicated */ struct variant_data { unsigned int clkreg; Loading @@ -63,18 +65,22 @@ struct variant_data { bool sdio; bool st_clkdiv; bool blksz_datactrl16; u32 pwrreg_powerup; bool signal_direction; }; static struct variant_data variant_arm = { .fifosize = 16 * 4, .fifohalfsize = 8 * 4, .datalength_bits = 16, .pwrreg_powerup = MCI_PWR_UP, }; static struct variant_data variant_arm_extended_fifo = { .fifosize = 128 * 4, .fifohalfsize = 64 * 4, .datalength_bits = 16, .pwrreg_powerup = MCI_PWR_UP, }; static struct variant_data variant_u300 = { Loading @@ -83,6 +89,8 @@ static struct variant_data variant_u300 = { .clkreg_enable = MCI_ST_U300_HWFCEN, .datalength_bits = 16, .sdio = true, .pwrreg_powerup = MCI_PWR_ON, .signal_direction = true, }; static struct variant_data variant_ux500 = { Loading @@ -93,6 +101,8 @@ static struct variant_data variant_ux500 = { .datalength_bits = 24, .sdio = true, .st_clkdiv = true, .pwrreg_powerup = MCI_PWR_ON, .signal_direction = true, }; static struct variant_data variant_ux500v2 = { Loading @@ -104,8 +114,32 @@ static struct variant_data variant_ux500v2 = { .sdio = true, .st_clkdiv = true, .blksz_datactrl16 = true, .pwrreg_powerup = MCI_PWR_ON, .signal_direction = true, }; /* * This must be called with host->lock held */ static void mmci_write_clkreg(struct mmci_host *host, u32 clk) { if (host->clk_reg != clk) { host->clk_reg = clk; writel(clk, host->base + MMCICLOCK); } } /* * This must be called with host->lock held */ static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr) { if (host->pwr_reg != pwr) { host->pwr_reg = pwr; writel(pwr, host->base + MMCIPOWER); } } /* * This must be called with host->lock held */ Loading Loading @@ -153,7 +187,7 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8) clk |= MCI_ST_8BIT_BUS; writel(clk, host->base + MMCICLOCK); mmci_write_clkreg(host, clk); } static void Loading @@ -166,14 +200,10 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) host->mrq = NULL; host->cmd = NULL; /* * Need to drop the host lock here; mmc_request_done may call * back into the driver... */ spin_unlock(&host->lock); pm_runtime_put(mmc_dev(host->mmc)); mmc_request_done(host->mmc, mrq); spin_lock(&host->lock); pm_runtime_mark_last_busy(mmc_dev(host->mmc)); pm_runtime_put_autosuspend(mmc_dev(host->mmc)); } static void mmci_set_mask1(struct mmci_host *host, unsigned int mask) Loading Loading @@ -607,6 +637,11 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) if (data->flags & MMC_DATA_READ) datactrl |= MCI_DPSM_DIRECTION; /* The ST Micro variants has a special bit to enable SDIO */ if (variant->sdio && host->mmc->card) if (mmc_card_sdio(host->mmc->card)) datactrl |= MCI_ST_DPSM_SDIOEN; /* * Attempt to use DMA operation mode, if this * should fail, fall back to PIO mode Loading Loading @@ -635,11 +670,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) irqmask = MCI_TXFIFOHALFEMPTYMASK; } /* The ST Micro variants has a special bit to enable SDIO */ if (variant->sdio && host->mmc->card) if (mmc_card_sdio(host->mmc->card)) datactrl |= MCI_ST_DPSM_SDIOEN; writel(datactrl, base + MMCIDATACTRL); writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); mmci_set_mask1(host, irqmask); Loading Loading @@ -786,7 +816,24 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema if (count <= 0) break; /* * SDIO especially may want to send something that is * not divisible by 4 (as opposed to card sectors * etc). Therefore make sure to always read the last bytes * while only doing full 32-bit reads towards the FIFO. */ if (unlikely(count & 0x3)) { if (count < 4) { unsigned char buf[4]; readsl(base + MMCIFIFO, buf, 1); memcpy(ptr, buf, count); } else { readsl(base + MMCIFIFO, ptr, count >> 2); count &= ~0x3; } } else { readsl(base + MMCIFIFO, ptr, count >> 2); } ptr += count; remain -= count; Loading Loading @@ -821,14 +868,13 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem */ if (variant->sdio && mmc_card_sdio(host->mmc->card)) { u32 clk; if (count < 8) writel(readl(host->base + MMCICLOCK) & ~variant->clkreg_enable, host->base + MMCICLOCK); clk = host->clk_reg & ~variant->clkreg_enable; else writel(readl(host->base + MMCICLOCK) | variant->clkreg_enable, host->base + MMCICLOCK); clk = host->clk_reg | variant->clkreg_enable; mmci_write_clkreg(host, clk); } /* Loading Loading @@ -1015,10 +1061,17 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct mmci_host *host = mmc_priv(mmc); struct variant_data *variant = host->variant; u32 pwr = 0; unsigned long flags; int ret; pm_runtime_get_sync(mmc_dev(mmc)); if (host->plat->ios_handler && host->plat->ios_handler(mmc_dev(mmc), ios)) dev_err(mmc_dev(mmc), "platform ios_handler failed\n"); switch (ios->power_mode) { case MMC_POWER_OFF: if (host->vcc) Loading @@ -1035,22 +1088,38 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) * power should be rare so we print an error * and return here. */ return; goto out; } } if (host->plat->vdd_handler) pwr |= host->plat->vdd_handler(mmc_dev(mmc), ios->vdd, ios->power_mode); /* The ST version does not have this, fall through to POWER_ON */ if (host->hw_designer != AMBA_VENDOR_ST) { pwr |= MCI_PWR_UP; /* * The ST Micro variant doesn't have the PL180s MCI_PWR_UP * and instead uses MCI_PWR_ON so apply whatever value is * configured in the variant data. */ pwr |= variant->pwrreg_powerup; break; } case MMC_POWER_ON: pwr |= MCI_PWR_ON; break; } if (variant->signal_direction && ios->power_mode != MMC_POWER_OFF) { /* * The ST Micro variant has some additional bits * indicating signal direction for the signals in * the SD/MMC bus and feedback-clock usage. */ pwr |= host->plat->sigdir; if (ios->bus_width == MMC_BUS_WIDTH_4) pwr &= ~MCI_ST_DATA74DIREN; else if (ios->bus_width == MMC_BUS_WIDTH_1) pwr &= (~MCI_ST_DATA74DIREN & ~MCI_ST_DATA31DIREN & ~MCI_ST_DATA2DIREN); } if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) { if (host->hw_designer != AMBA_VENDOR_ST) pwr |= MCI_ROD; Loading @@ -1066,13 +1135,13 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) spin_lock_irqsave(&host->lock, flags); mmci_set_clkreg(host, ios->clock); if (host->pwr != pwr) { host->pwr = pwr; writel(pwr, host->base + MMCIPOWER); } mmci_write_pwrreg(host, pwr); spin_unlock_irqrestore(&host->lock, flags); out: pm_runtime_mark_last_busy(mmc_dev(mmc)); pm_runtime_put_autosuspend(mmc_dev(mmc)); } static int mmci_get_ro(struct mmc_host *mmc) Loading Loading @@ -1345,6 +1414,8 @@ static int __devinit mmci_probe(struct amba_device *dev, mmci_dma_setup(host); pm_runtime_set_autosuspend_delay(&dev->dev, 50); pm_runtime_use_autosuspend(&dev->dev); pm_runtime_put(&dev->dev); mmc_add_host(mmc); Loading Loading @@ -1429,43 +1500,49 @@ static int __devexit mmci_remove(struct amba_device *dev) return 0; } #ifdef CONFIG_PM static int mmci_suspend(struct amba_device *dev, pm_message_t state) #ifdef CONFIG_SUSPEND static int mmci_suspend(struct device *dev) { struct mmc_host *mmc = amba_get_drvdata(dev); struct amba_device *adev = to_amba_device(dev); struct mmc_host *mmc = amba_get_drvdata(adev); int ret = 0; if (mmc) { struct mmci_host *host = mmc_priv(mmc); ret = mmc_suspend_host(mmc); if (ret == 0) if (ret == 0) { pm_runtime_get_sync(dev); writel(0, host->base + MMCIMASK0); } } return ret; } static int mmci_resume(struct amba_device *dev) static int mmci_resume(struct device *dev) { struct mmc_host *mmc = amba_get_drvdata(dev); struct amba_device *adev = to_amba_device(dev); struct mmc_host *mmc = amba_get_drvdata(adev); int ret = 0; if (mmc) { struct mmci_host *host = mmc_priv(mmc); writel(MCI_IRQENABLE, host->base + MMCIMASK0); pm_runtime_put(dev); ret = mmc_resume_host(mmc); } return ret; } #else #define mmci_suspend NULL #define mmci_resume NULL #endif static const struct dev_pm_ops mmci_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(mmci_suspend, mmci_resume) }; static struct amba_id mmci_ids[] = { { .id = 0x00041180, Loading Loading @@ -1511,11 +1588,10 @@ MODULE_DEVICE_TABLE(amba, mmci_ids); static struct amba_driver mmci_driver = { .drv = { .name = DRIVER_NAME, .pm = &mmci_dev_pm_ops, }, .probe = mmci_probe, .remove = __devexit_p(mmci_remove), .suspend = mmci_suspend, .resume = mmci_resume, .id_table = mmci_ids, }; Loading drivers/mmc/host/mmci.h +3 −12 Original line number Diff line number Diff line Loading @@ -13,16 +13,6 @@ #define MCI_PWR_ON 0x03 #define MCI_OD (1 << 6) #define MCI_ROD (1 << 7) /* * The ST Micro version does not have ROD and reuse the voltage registers * for direction settings */ #define MCI_ST_DATA2DIREN (1 << 2) #define MCI_ST_CMDDIREN (1 << 3) #define MCI_ST_DATA0DIREN (1 << 4) #define MCI_ST_DATA31DIREN (1 << 5) #define MCI_ST_FBCLKEN (1 << 7) #define MCI_ST_DATA74DIREN (1 << 8) #define MMCICLOCK 0x004 #define MCI_CLK_ENABLE (1 << 8) Loading Loading @@ -160,7 +150,7 @@ (MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \ MCI_TXFIFOHALFEMPTYMASK) #define NR_SG 16 #define NR_SG 128 struct clk; struct variant_data; Loading Loading @@ -189,7 +179,8 @@ struct mmci_host { unsigned int mclk; unsigned int cclk; u32 pwr; u32 pwr_reg; u32 clk_reg; struct mmci_platform_data *plat; struct variant_data *variant; Loading include/linux/amba/mmci.h +19 −3 Original line number Diff line number Diff line Loading @@ -6,6 +6,19 @@ #include <linux/mmc/host.h> /* * These defines is places here due to access is needed from machine * configuration files. The ST Micro version does not have ROD and * reuse the voltage registers for direction settings. */ #define MCI_ST_DATA2DIREN (1 << 2) #define MCI_ST_CMDDIREN (1 << 3) #define MCI_ST_DATA0DIREN (1 << 4) #define MCI_ST_DATA31DIREN (1 << 5) #define MCI_ST_FBCLKEN (1 << 7) #define MCI_ST_DATA74DIREN (1 << 8) /* Just some dummy forwarding */ struct dma_chan; Loading @@ -18,7 +31,8 @@ struct dma_chan; * @ocr_mask: available voltages on the 4 pins from the block, this * is ignored if a regulator is used, see the MMC_VDD_* masks in * mmc/host.h * @vdd_handler: a callback function to translate a MMC_VDD_* * @ios_handler: a callback function to act on specfic ios changes, * used for example to control a levelshifter * mask into a value to be binary (or set some other custom bits * in MMCIPWR) or:ed and written into the MMCIPWR register of the * block. May also control external power based on the power_mode. Loading @@ -31,6 +45,8 @@ struct dma_chan; * @capabilities: the capabilities of the block as implemented in * this platform, signify anything MMC_CAP_* from mmc/host.h * @capabilities2: more capabilities, MMC_CAP2_* from mmc/host.h * @sigdir: a bit field indicating for what bits in the MMC bus the host * should enable signal direction indication. * @dma_filter: function used to select an appropriate RX and TX * DMA channel to be used for DMA, if and only if you're deploying the * generic DMA engine Loading @@ -46,14 +62,14 @@ struct dma_chan; struct mmci_platform_data { unsigned int f_max; unsigned int ocr_mask; u32 (*vdd_handler)(struct device *, unsigned int vdd, unsigned char power_mode); int (*ios_handler)(struct device *, struct mmc_ios *); unsigned int (*status)(struct device *); int gpio_wp; int gpio_cd; bool cd_invert; unsigned long capabilities; unsigned long capabilities2; u32 sigdir; bool (*dma_filter)(struct dma_chan *chan, void *filter_param); void *dma_rx_param; void *dma_tx_param; Loading Loading
arch/arm/mach-ux500/board-mop500-sdi.c +8 −13 Original line number Diff line number Diff line Loading @@ -31,21 +31,13 @@ * SDI 0 (MicroSD slot) */ /* MMCIPOWER bits */ #define MCI_DATA2DIREN (1 << 2) #define MCI_CMDDIREN (1 << 3) #define MCI_DATA0DIREN (1 << 4) #define MCI_DATA31DIREN (1 << 5) #define MCI_FBCLKEN (1 << 7) /* GPIO pins used by the sdi0 level shifter */ static int sdi0_en = -1; static int sdi0_vsel = -1; static u32 mop500_sdi0_vdd_handler(struct device *dev, unsigned int vdd, unsigned char power_mode) static int mop500_sdi0_ios_handler(struct device *dev, struct mmc_ios *ios) { switch (power_mode) { switch (ios->power_mode) { case MMC_POWER_UP: case MMC_POWER_ON: /* Loading @@ -65,8 +57,7 @@ static u32 mop500_sdi0_vdd_handler(struct device *dev, unsigned int vdd, break; } return MCI_FBCLKEN | MCI_CMDDIREN | MCI_DATA0DIREN | MCI_DATA2DIREN | MCI_DATA31DIREN; return 0; } #ifdef CONFIG_STE_DMA40 Loading @@ -90,13 +81,17 @@ static struct stedma40_chan_cfg mop500_sdi0_dma_cfg_tx = { #endif static struct mmci_platform_data mop500_sdi0_data = { .vdd_handler = mop500_sdi0_vdd_handler, .ios_handler = mop500_sdi0_ios_handler, .ocr_mask = MMC_VDD_29_30, .f_max = 50000000, .capabilities = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED, .gpio_wp = -1, .sigdir = MCI_ST_FBCLKEN | MCI_ST_CMDDIREN | MCI_ST_DATA0DIREN | MCI_ST_DATA2DIREN, #ifdef CONFIG_STE_DMA40 .dma_filter = stedma40_filter, .dma_rx_param = &mop500_sdi0_dma_cfg_rx, Loading
drivers/mmc/host/mmci.c +121 −45 Original line number Diff line number Diff line Loading @@ -53,6 +53,8 @@ static unsigned int fmax = 515633; * @sdio: variant supports SDIO * @st_clkdiv: true if using a ST-specific clock divider algorithm * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register * @pwrreg_powerup: power up value for MMCIPOWER register * @signal_direction: input/out direction of bus signals can be indicated */ struct variant_data { unsigned int clkreg; Loading @@ -63,18 +65,22 @@ struct variant_data { bool sdio; bool st_clkdiv; bool blksz_datactrl16; u32 pwrreg_powerup; bool signal_direction; }; static struct variant_data variant_arm = { .fifosize = 16 * 4, .fifohalfsize = 8 * 4, .datalength_bits = 16, .pwrreg_powerup = MCI_PWR_UP, }; static struct variant_data variant_arm_extended_fifo = { .fifosize = 128 * 4, .fifohalfsize = 64 * 4, .datalength_bits = 16, .pwrreg_powerup = MCI_PWR_UP, }; static struct variant_data variant_u300 = { Loading @@ -83,6 +89,8 @@ static struct variant_data variant_u300 = { .clkreg_enable = MCI_ST_U300_HWFCEN, .datalength_bits = 16, .sdio = true, .pwrreg_powerup = MCI_PWR_ON, .signal_direction = true, }; static struct variant_data variant_ux500 = { Loading @@ -93,6 +101,8 @@ static struct variant_data variant_ux500 = { .datalength_bits = 24, .sdio = true, .st_clkdiv = true, .pwrreg_powerup = MCI_PWR_ON, .signal_direction = true, }; static struct variant_data variant_ux500v2 = { Loading @@ -104,8 +114,32 @@ static struct variant_data variant_ux500v2 = { .sdio = true, .st_clkdiv = true, .blksz_datactrl16 = true, .pwrreg_powerup = MCI_PWR_ON, .signal_direction = true, }; /* * This must be called with host->lock held */ static void mmci_write_clkreg(struct mmci_host *host, u32 clk) { if (host->clk_reg != clk) { host->clk_reg = clk; writel(clk, host->base + MMCICLOCK); } } /* * This must be called with host->lock held */ static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr) { if (host->pwr_reg != pwr) { host->pwr_reg = pwr; writel(pwr, host->base + MMCIPOWER); } } /* * This must be called with host->lock held */ Loading Loading @@ -153,7 +187,7 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired) if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8) clk |= MCI_ST_8BIT_BUS; writel(clk, host->base + MMCICLOCK); mmci_write_clkreg(host, clk); } static void Loading @@ -166,14 +200,10 @@ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) host->mrq = NULL; host->cmd = NULL; /* * Need to drop the host lock here; mmc_request_done may call * back into the driver... */ spin_unlock(&host->lock); pm_runtime_put(mmc_dev(host->mmc)); mmc_request_done(host->mmc, mrq); spin_lock(&host->lock); pm_runtime_mark_last_busy(mmc_dev(host->mmc)); pm_runtime_put_autosuspend(mmc_dev(host->mmc)); } static void mmci_set_mask1(struct mmci_host *host, unsigned int mask) Loading Loading @@ -607,6 +637,11 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) if (data->flags & MMC_DATA_READ) datactrl |= MCI_DPSM_DIRECTION; /* The ST Micro variants has a special bit to enable SDIO */ if (variant->sdio && host->mmc->card) if (mmc_card_sdio(host->mmc->card)) datactrl |= MCI_ST_DPSM_SDIOEN; /* * Attempt to use DMA operation mode, if this * should fail, fall back to PIO mode Loading Loading @@ -635,11 +670,6 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data) irqmask = MCI_TXFIFOHALFEMPTYMASK; } /* The ST Micro variants has a special bit to enable SDIO */ if (variant->sdio && host->mmc->card) if (mmc_card_sdio(host->mmc->card)) datactrl |= MCI_ST_DPSM_SDIOEN; writel(datactrl, base + MMCIDATACTRL); writel(readl(base + MMCIMASK0) & ~MCI_DATAENDMASK, base + MMCIMASK0); mmci_set_mask1(host, irqmask); Loading Loading @@ -786,7 +816,24 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema if (count <= 0) break; /* * SDIO especially may want to send something that is * not divisible by 4 (as opposed to card sectors * etc). Therefore make sure to always read the last bytes * while only doing full 32-bit reads towards the FIFO. */ if (unlikely(count & 0x3)) { if (count < 4) { unsigned char buf[4]; readsl(base + MMCIFIFO, buf, 1); memcpy(ptr, buf, count); } else { readsl(base + MMCIFIFO, ptr, count >> 2); count &= ~0x3; } } else { readsl(base + MMCIFIFO, ptr, count >> 2); } ptr += count; remain -= count; Loading Loading @@ -821,14 +868,13 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem */ if (variant->sdio && mmc_card_sdio(host->mmc->card)) { u32 clk; if (count < 8) writel(readl(host->base + MMCICLOCK) & ~variant->clkreg_enable, host->base + MMCICLOCK); clk = host->clk_reg & ~variant->clkreg_enable; else writel(readl(host->base + MMCICLOCK) | variant->clkreg_enable, host->base + MMCICLOCK); clk = host->clk_reg | variant->clkreg_enable; mmci_write_clkreg(host, clk); } /* Loading Loading @@ -1015,10 +1061,17 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq) static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct mmci_host *host = mmc_priv(mmc); struct variant_data *variant = host->variant; u32 pwr = 0; unsigned long flags; int ret; pm_runtime_get_sync(mmc_dev(mmc)); if (host->plat->ios_handler && host->plat->ios_handler(mmc_dev(mmc), ios)) dev_err(mmc_dev(mmc), "platform ios_handler failed\n"); switch (ios->power_mode) { case MMC_POWER_OFF: if (host->vcc) Loading @@ -1035,22 +1088,38 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) * power should be rare so we print an error * and return here. */ return; goto out; } } if (host->plat->vdd_handler) pwr |= host->plat->vdd_handler(mmc_dev(mmc), ios->vdd, ios->power_mode); /* The ST version does not have this, fall through to POWER_ON */ if (host->hw_designer != AMBA_VENDOR_ST) { pwr |= MCI_PWR_UP; /* * The ST Micro variant doesn't have the PL180s MCI_PWR_UP * and instead uses MCI_PWR_ON so apply whatever value is * configured in the variant data. */ pwr |= variant->pwrreg_powerup; break; } case MMC_POWER_ON: pwr |= MCI_PWR_ON; break; } if (variant->signal_direction && ios->power_mode != MMC_POWER_OFF) { /* * The ST Micro variant has some additional bits * indicating signal direction for the signals in * the SD/MMC bus and feedback-clock usage. */ pwr |= host->plat->sigdir; if (ios->bus_width == MMC_BUS_WIDTH_4) pwr &= ~MCI_ST_DATA74DIREN; else if (ios->bus_width == MMC_BUS_WIDTH_1) pwr &= (~MCI_ST_DATA74DIREN & ~MCI_ST_DATA31DIREN & ~MCI_ST_DATA2DIREN); } if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) { if (host->hw_designer != AMBA_VENDOR_ST) pwr |= MCI_ROD; Loading @@ -1066,13 +1135,13 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) spin_lock_irqsave(&host->lock, flags); mmci_set_clkreg(host, ios->clock); if (host->pwr != pwr) { host->pwr = pwr; writel(pwr, host->base + MMCIPOWER); } mmci_write_pwrreg(host, pwr); spin_unlock_irqrestore(&host->lock, flags); out: pm_runtime_mark_last_busy(mmc_dev(mmc)); pm_runtime_put_autosuspend(mmc_dev(mmc)); } static int mmci_get_ro(struct mmc_host *mmc) Loading Loading @@ -1345,6 +1414,8 @@ static int __devinit mmci_probe(struct amba_device *dev, mmci_dma_setup(host); pm_runtime_set_autosuspend_delay(&dev->dev, 50); pm_runtime_use_autosuspend(&dev->dev); pm_runtime_put(&dev->dev); mmc_add_host(mmc); Loading Loading @@ -1429,43 +1500,49 @@ static int __devexit mmci_remove(struct amba_device *dev) return 0; } #ifdef CONFIG_PM static int mmci_suspend(struct amba_device *dev, pm_message_t state) #ifdef CONFIG_SUSPEND static int mmci_suspend(struct device *dev) { struct mmc_host *mmc = amba_get_drvdata(dev); struct amba_device *adev = to_amba_device(dev); struct mmc_host *mmc = amba_get_drvdata(adev); int ret = 0; if (mmc) { struct mmci_host *host = mmc_priv(mmc); ret = mmc_suspend_host(mmc); if (ret == 0) if (ret == 0) { pm_runtime_get_sync(dev); writel(0, host->base + MMCIMASK0); } } return ret; } static int mmci_resume(struct amba_device *dev) static int mmci_resume(struct device *dev) { struct mmc_host *mmc = amba_get_drvdata(dev); struct amba_device *adev = to_amba_device(dev); struct mmc_host *mmc = amba_get_drvdata(adev); int ret = 0; if (mmc) { struct mmci_host *host = mmc_priv(mmc); writel(MCI_IRQENABLE, host->base + MMCIMASK0); pm_runtime_put(dev); ret = mmc_resume_host(mmc); } return ret; } #else #define mmci_suspend NULL #define mmci_resume NULL #endif static const struct dev_pm_ops mmci_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(mmci_suspend, mmci_resume) }; static struct amba_id mmci_ids[] = { { .id = 0x00041180, Loading Loading @@ -1511,11 +1588,10 @@ MODULE_DEVICE_TABLE(amba, mmci_ids); static struct amba_driver mmci_driver = { .drv = { .name = DRIVER_NAME, .pm = &mmci_dev_pm_ops, }, .probe = mmci_probe, .remove = __devexit_p(mmci_remove), .suspend = mmci_suspend, .resume = mmci_resume, .id_table = mmci_ids, }; Loading
drivers/mmc/host/mmci.h +3 −12 Original line number Diff line number Diff line Loading @@ -13,16 +13,6 @@ #define MCI_PWR_ON 0x03 #define MCI_OD (1 << 6) #define MCI_ROD (1 << 7) /* * The ST Micro version does not have ROD and reuse the voltage registers * for direction settings */ #define MCI_ST_DATA2DIREN (1 << 2) #define MCI_ST_CMDDIREN (1 << 3) #define MCI_ST_DATA0DIREN (1 << 4) #define MCI_ST_DATA31DIREN (1 << 5) #define MCI_ST_FBCLKEN (1 << 7) #define MCI_ST_DATA74DIREN (1 << 8) #define MMCICLOCK 0x004 #define MCI_CLK_ENABLE (1 << 8) Loading Loading @@ -160,7 +150,7 @@ (MCI_RXFIFOHALFFULLMASK | MCI_RXDATAAVLBLMASK | \ MCI_TXFIFOHALFEMPTYMASK) #define NR_SG 16 #define NR_SG 128 struct clk; struct variant_data; Loading Loading @@ -189,7 +179,8 @@ struct mmci_host { unsigned int mclk; unsigned int cclk; u32 pwr; u32 pwr_reg; u32 clk_reg; struct mmci_platform_data *plat; struct variant_data *variant; Loading
include/linux/amba/mmci.h +19 −3 Original line number Diff line number Diff line Loading @@ -6,6 +6,19 @@ #include <linux/mmc/host.h> /* * These defines is places here due to access is needed from machine * configuration files. The ST Micro version does not have ROD and * reuse the voltage registers for direction settings. */ #define MCI_ST_DATA2DIREN (1 << 2) #define MCI_ST_CMDDIREN (1 << 3) #define MCI_ST_DATA0DIREN (1 << 4) #define MCI_ST_DATA31DIREN (1 << 5) #define MCI_ST_FBCLKEN (1 << 7) #define MCI_ST_DATA74DIREN (1 << 8) /* Just some dummy forwarding */ struct dma_chan; Loading @@ -18,7 +31,8 @@ struct dma_chan; * @ocr_mask: available voltages on the 4 pins from the block, this * is ignored if a regulator is used, see the MMC_VDD_* masks in * mmc/host.h * @vdd_handler: a callback function to translate a MMC_VDD_* * @ios_handler: a callback function to act on specfic ios changes, * used for example to control a levelshifter * mask into a value to be binary (or set some other custom bits * in MMCIPWR) or:ed and written into the MMCIPWR register of the * block. May also control external power based on the power_mode. Loading @@ -31,6 +45,8 @@ struct dma_chan; * @capabilities: the capabilities of the block as implemented in * this platform, signify anything MMC_CAP_* from mmc/host.h * @capabilities2: more capabilities, MMC_CAP2_* from mmc/host.h * @sigdir: a bit field indicating for what bits in the MMC bus the host * should enable signal direction indication. * @dma_filter: function used to select an appropriate RX and TX * DMA channel to be used for DMA, if and only if you're deploying the * generic DMA engine Loading @@ -46,14 +62,14 @@ struct dma_chan; struct mmci_platform_data { unsigned int f_max; unsigned int ocr_mask; u32 (*vdd_handler)(struct device *, unsigned int vdd, unsigned char power_mode); int (*ios_handler)(struct device *, struct mmc_ios *); unsigned int (*status)(struct device *); int gpio_wp; int gpio_cd; bool cd_invert; unsigned long capabilities; unsigned long capabilities2; u32 sigdir; bool (*dma_filter)(struct dma_chan *chan, void *filter_param); void *dma_rx_param; void *dma_tx_param; Loading