diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-10 13:33:09 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-10 13:33:09 -0700 |
commit | d0048f0b91ee35ab940ec6cbdfdd238c55b12a14 (patch) | |
tree | 72914692414729a14ec1308c326d92359a3825a3 | |
parent | 7426d62871dafbeeed087d609c6469a515c88389 (diff) | |
parent | 9d731e7539713acc0ec7b67a5a91357c455d2334 (diff) |
Merge tag 'mmc-updates-for-3.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
Pull MMC updates from Chris Ball:
"MMC highlights for 3.12:
Core:
- Support Allocation Units 8MB-64MB in SD3.0, previous max was 4MB.
- The slot-gpio helper can now handle GPIO debouncing card-detect.
- Read supported voltages from DT "voltage-ranges" property.
Drivers:
- dw_mmc: Add support for ARC architecture, and support exynos5420.
- mmc_spi: Support CD/RO GPIOs.
- sh_mobile_sdhi: Add compatibility for more Renesas SoCs.
- sh_mmcif: Add DT support for DMA channels"
* tag 'mmc-updates-for-3.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (50 commits)
Revert "mmc: tmio-mmc: Remove .set_pwr() callback from platform data"
mmc: dw_mmc: Add support for ARC
mmc: sdhci-s3c: initialize host->quirks2 for using quirks2
mmc: sdhci-s3c: fix the wrong register value, when clock is disabled
mmc: esdhc: add support to get voltage from device-tree
mmc: sdhci: get voltage from sdhc host
mmc: core: parse voltage from device-tree
mmc: omap_hsmmc: use the generic config for omap2plus devices
mmc: omap_hsmmc: clear status flags before starting a new command
mmc: dw_mmc: exynos: Add a new compatible string for exynos5420
mmc: sh_mmcif: revision-specific CLK_CTRL2 handling
mmc: sh_mmcif: revision-specific Command Completion Signal handling
mmc: sh_mmcif: add support for Device Tree DMA bindings
mmc: sh_mmcif: move header include from header into .c
mmc: SDHI: add DT compatibility strings for further SoCs
mmc: dw_mmc-pci: enable bus-mastering mode
mmc: dw_mmc-pci: get resources from a proper BAR
mmc: tmio-mmc: Remove .set_pwr() callback from platform data
mmc: tmio-mmc: Remove .get_cd() callback from platform data
mmc: sh_mobile_sdhi: Remove .set_pwr() callback from platform data
...
42 files changed, 336 insertions, 335 deletions
diff --git a/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt index bd9be0b5bc2..b7943f3f999 100644 --- a/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt +++ b/Documentation/devicetree/bindings/mmc/fsl-esdhc.txt @@ -19,6 +19,9 @@ Optional properties: "bus-width = <1>" property. - sdhci,auto-cmd12: specifies that a controller can only handle auto CMD12. + - voltage-ranges : two cells are required, first cell specifies minimum + slot voltage (mV), second cell specifies maximum slot voltage (mV). + Several ranges could be specified. Example: @@ -29,4 +32,5 @@ sdhci@2e000 { interrupt-parent = <&ipic>; /* Filled in by U-Boot */ clock-frequency = <0>; + voltage-ranges = <3300 3300>; }; diff --git a/arch/arm/mach-ep93xx/vision_ep9307.c b/arch/arm/mach-ep93xx/vision_ep9307.c index 64f2e50e19c..6bc1c181581 100644 --- a/arch/arm/mach-ep93xx/vision_ep9307.c +++ b/arch/arm/mach-ep93xx/vision_ep9307.c @@ -224,62 +224,15 @@ static struct ep93xx_spi_chip_ops vision_spi_flash_hw = { #define VISION_SPI_MMC_WP EP93XX_GPIO_LINE_F(0) #define VISION_SPI_MMC_CD EP93XX_GPIO_LINE_EGPIO15 -static struct gpio vision_spi_mmc_gpios[] = { - { VISION_SPI_MMC_WP, GPIOF_DIR_IN, "mmc_spi:wp" }, - { VISION_SPI_MMC_CD, GPIOF_DIR_IN, "mmc_spi:cd" }, -}; - -static int vision_spi_mmc_init(struct device *pdev, - irqreturn_t (*func)(int, void *), void *pdata) -{ - int err; - - err = gpio_request_array(vision_spi_mmc_gpios, - ARRAY_SIZE(vision_spi_mmc_gpios)); - if (err) - return err; - - err = gpio_set_debounce(VISION_SPI_MMC_CD, 1); - if (err) - goto exit_err; - - err = request_irq(gpio_to_irq(VISION_SPI_MMC_CD), func, - IRQ_TYPE_EDGE_BOTH, "mmc_spi:cd", pdata); - if (err) - goto exit_err; - - return 0; - -exit_err: - gpio_free_array(vision_spi_mmc_gpios, ARRAY_SIZE(vision_spi_mmc_gpios)); - return err; - -} - -static void vision_spi_mmc_exit(struct device *pdev, void *pdata) -{ - free_irq(gpio_to_irq(VISION_SPI_MMC_CD), pdata); - gpio_free_array(vision_spi_mmc_gpios, ARRAY_SIZE(vision_spi_mmc_gpios)); -} - -static int vision_spi_mmc_get_ro(struct device *pdev) -{ - return !!gpio_get_value(VISION_SPI_MMC_WP); -} - -static int vision_spi_mmc_get_cd(struct device *pdev) -{ - return !gpio_get_value(VISION_SPI_MMC_CD); -} - static struct mmc_spi_platform_data vision_spi_mmc_data = { - .init = vision_spi_mmc_init, - .exit = vision_spi_mmc_exit, - .get_ro = vision_spi_mmc_get_ro, - .get_cd = vision_spi_mmc_get_cd, .detect_delay = 100, .powerup_msecs = 100, .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, + .flags = MMC_SPI_USE_CD_GPIO | MMC_SPI_USE_RO_GPIO, + .cd_gpio = VISION_SPI_MMC_CD, + .cd_debounce = 1, + .ro_gpio = VISION_SPI_MMC_WP, + .caps2 = MMC_CAP2_RO_ACTIVE_HIGH, }; static int vision_spi_mmc_hw_setup(struct spi_device *spi) diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 65dd81baa7f..1fa8be40977 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -600,37 +600,13 @@ static struct platform_device sdhi0_power = { }, }; -static void sdhi0_set_pwr(struct platform_device *pdev, int state) -{ - static int power_gpio = -EINVAL; - - if (power_gpio < 0) { - int ret = gpio_request(GPIO_PTB6, NULL); - if (!ret) { - power_gpio = GPIO_PTB6; - gpio_direction_output(power_gpio, 0); - } - } - - /* - * Toggle the GPIO regardless, whether we managed to grab it above or - * the fixed regulator driver did. - */ - gpio_set_value(GPIO_PTB6, state); -} - -static int sdhi0_get_cd(struct platform_device *pdev) -{ - return !gpio_get_value(GPIO_PTY7); -} - static struct sh_mobile_sdhi_info sdhi0_info = { .dma_slave_tx = SHDMA_SLAVE_SDHI0_TX, .dma_slave_rx = SHDMA_SLAVE_SDHI0_RX, - .set_pwr = sdhi0_set_pwr, .tmio_caps = MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD | MMC_CAP_NEEDS_POLL, - .get_cd = sdhi0_get_cd, + .tmio_flags = TMIO_MMC_USE_GPIO_CD, + .cd_gpio = GPIO_PTY7, }; static struct resource sdhi0_resources[] = { @@ -656,39 +632,15 @@ static struct platform_device sdhi0_device = { }, }; -static void cn12_set_pwr(struct platform_device *pdev, int state) -{ - static int power_gpio = -EINVAL; - - if (power_gpio < 0) { - int ret = gpio_request(GPIO_PTB7, NULL); - if (!ret) { - power_gpio = GPIO_PTB7; - gpio_direction_output(power_gpio, 0); - } - } - - /* - * Toggle the GPIO regardless, whether we managed to grab it above or - * the fixed regulator driver did. - */ - gpio_set_value(GPIO_PTB7, state); -} - #if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE) /* SDHI1 */ -static int sdhi1_get_cd(struct platform_device *pdev) -{ - return !gpio_get_value(GPIO_PTW7); -} - static struct sh_mobile_sdhi_info sdhi1_info = { .dma_slave_tx = SHDMA_SLAVE_SDHI1_TX, .dma_slave_rx = SHDMA_SLAVE_SDHI1_RX, .tmio_caps = MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD | MMC_CAP_NEEDS_POLL, - .set_pwr = cn12_set_pwr, - .get_cd = sdhi1_get_cd, + .tmio_flags = TMIO_MMC_USE_GPIO_CD, + .cd_gpio = GPIO_PTW7, }; static struct resource sdhi1_resources[] = { @@ -718,27 +670,19 @@ static struct platform_device sdhi1_device = { #else /* MMC SPI */ -static int mmc_spi_get_ro(struct device *dev) -{ - return gpio_get_value(GPIO_PTY6); -} - -static int mmc_spi_get_cd(struct device *dev) -{ - return !gpio_get_value(GPIO_PTY7); -} - static void mmc_spi_setpower(struct device *dev, unsigned int maskval) { gpio_set_value(GPIO_PTB6, maskval ? 1 : 0); } static struct mmc_spi_platform_data mmc_spi_info = { - .get_ro = mmc_spi_get_ro, - .get_cd = mmc_spi_get_cd, .caps = MMC_CAP_NEEDS_POLL, + .caps2 = MMC_CAP2_RO_ACTIVE_HIGH, .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, /* 3.3V only */ .setpower = mmc_spi_setpower, + .flags = MMC_SPI_USE_CD_GPIO | MMC_SPI_USE_RO_GPIO, + .cd_gpio = GPIO_PTY7, + .ro_gpio = GPIO_PTY6, }; static struct spi_board_info spi_bus[] = { @@ -998,11 +942,6 @@ static struct platform_device vou_device = { #if defined(CONFIG_MMC_SH_MMCIF) || defined(CONFIG_MMC_SH_MMCIF_MODULE) /* SH_MMCIF */ -static void mmcif_down_pwr(struct platform_device *pdev) -{ - cn12_set_pwr(pdev, 0); -} - static struct resource sh_mmcif_resources[] = { [0] = { .name = "SH_MMCIF", @@ -1023,8 +962,6 @@ static struct resource sh_mmcif_resources[] = { }; static struct sh_mmcif_plat_data sh_mmcif_plat = { - .set_pwr = cn12_set_pwr, - .down_pwr = mmcif_down_pwr, .sup_pclk = 0, /* SH7724: Max Pclk/2 */ .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA | @@ -1341,10 +1278,6 @@ static int __init arch_setup(void) gpio_direction_input(GPIO_PTR6); /* SD-card slot CN11 */ - /* Card-detect, used on CN11, either with SDHI0 or with SPI */ - gpio_request(GPIO_PTY7, NULL); - gpio_direction_input(GPIO_PTY7); - #if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE) /* enable SDHI0 on CN11 (needs DS2.4 set to ON) */ gpio_request(GPIO_FN_SDHI0WP, NULL); @@ -1363,8 +1296,6 @@ static int __init arch_setup(void) gpio_direction_output(GPIO_PTM4, 1); /* active low CS */ gpio_request(GPIO_PTB6, NULL); /* 3.3V power control */ gpio_direction_output(GPIO_PTB6, 0); /* disable power by default */ - gpio_request(GPIO_PTY6, NULL); /* write protect */ - gpio_direction_input(GPIO_PTY6); spi_register_board_info(spi_bus, ARRAY_SIZE(spi_bus)); #endif @@ -1394,10 +1325,6 @@ static int __init arch_setup(void) gpio_request(GPIO_FN_SDHI1D1, NULL); gpio_request(GPIO_FN_SDHI1D0, NULL); - /* Card-detect, used on CN12 with SDHI1 */ - gpio_request(GPIO_PTW7, NULL); - gpio_direction_input(GPIO_PTW7); - cn12_enabled = true; #endif diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index cd0b7f4a1ff..1a3163f1407 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -812,7 +812,7 @@ static int mmc_blk_cmd_error(struct request *req, const char *name, int error, * Otherwise we don't understand what happened, so abort. */ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, - struct mmc_blk_request *brq, int *ecc_err) + struct mmc_blk_request *brq, int *ecc_err, int *gen_err) { bool prev_cmd_status_valid = true; u32 status, stop_status = 0; @@ -850,6 +850,16 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, (brq->cmd.resp[0] & R1_CARD_ECC_FAILED)) *ecc_err = 1; + /* Flag General errors */ + if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) + if ((status & R1_ERROR) || + (brq->stop.resp[0] & R1_ERROR)) { + pr_err("%s: %s: general error sending stop or status command, stop cmd response %#x, card status %#x\n", + req->rq_disk->disk_name, __func__, + brq->stop.resp[0], status); + *gen_err = 1; + } + /* * Check the current card state. If it is in some data transfer * mode, tell it to stop (and hopefully transition back to TRAN.) @@ -869,6 +879,13 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req, return ERR_ABORT; if (stop_status & R1_CARD_ECC_FAILED) *ecc_err = 1; + if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) + if (stop_status & R1_ERROR) { + pr_err("%s: %s: general error sending stop command, stop cmd response %#x\n", + req->rq_disk->disk_name, __func__, + stop_status); + *gen_err = 1; + } } /* Check for set block count errors */ @@ -1097,7 +1114,7 @@ static int mmc_blk_err_check(struct mmc_card *card, mmc_active); struct mmc_blk_request *brq = &mq_mrq->brq; struct request *req = mq_mrq->req; - int ecc_err = 0; + int ecc_err = 0, gen_err = 0; /* * sbc.error indicates a problem with the set block count @@ -1111,7 +1128,7 @@ static int mmc_blk_err_check(struct mmc_card *card, */ if (brq->sbc.error || brq->cmd.error || brq->stop.error || brq->data.error) { - switch (mmc_blk_cmd_recovery(card, req, brq, &ecc_err)) { + switch (mmc_blk_cmd_recovery(card, req, brq, &ecc_err, &gen_err)) { case ERR_RETRY: return MMC_BLK_RETRY; case ERR_ABORT: @@ -1143,6 +1160,14 @@ static int mmc_blk_err_check(struct mmc_card *card, u32 status; unsigned long timeout; + /* Check stop command response */ + if (brq->stop.resp[0] & R1_ERROR) { + pr_err("%s: %s: general error sending stop command, stop cmd response %#x\n", + req->rq_disk->disk_name, __func__, + brq->stop.resp[0]); + gen_err = 1; + } + timeout = jiffies + msecs_to_jiffies(MMC_BLK_TIMEOUT_MS); do { int err = get_card_status(card, &status, 5); @@ -1152,6 +1177,13 @@ static int mmc_blk_err_check(struct mmc_card *card, return MMC_BLK_CMD_ERR; } + if (status & R1_ERROR) { + pr_err("%s: %s: general error sending status command, card status %#x\n", + req->rq_disk->disk_name, __func__, + status); + gen_err = 1; + } + /* Timeout if the device never becomes ready for data * and never leaves the program state. */ @@ -1171,6 +1203,13 @@ static int mmc_blk_err_check(struct mmc_card *card, (R1_CURRENT_STATE(status) == R1_STATE_PRG)); } + /* if general error occurs, retry the write operation. */ + if (gen_err) { + pr_warn("%s: retrying write for general error\n", + req->rq_disk->disk_name); + return MMC_BLK_RETRY; + } + if (brq->data.error) { pr_err("%s: error %d transferring data, sector %u, nr %u, cmd response %#x, card status %#x\n", req->rq_disk->disk_name, brq->data.error, @@ -2191,10 +2230,10 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md) * is freeing the queue that stops new requests * from being accepted. */ + card = md->queue.card; mmc_cleanup_queue(&md->queue); if (md->flags & MMC_BLK_PACKED_CMD) mmc_packed_clean(&md->queue); - card = md->queue.card; if (md->disk->flags & GENHD_FL_UP) { device_remove_file(disk_to_dev(md->disk), &md->force_ro); if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) && diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index a69df521627..0c0fc52d42c 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c @@ -2849,18 +2849,12 @@ static ssize_t mtf_test_write(struct file *file, const char __user *buf, struct seq_file *sf = (struct seq_file *)file->private_data; struct mmc_card *card = (struct mmc_card *)sf->private; struct mmc_test_card *test; - char lbuf[12]; long testcase; + int ret; - if (count >= sizeof(lbuf)) - return -EINVAL; - - if (copy_from_user(lbuf, buf, count)) - return -EFAULT; - lbuf[count] = '\0'; - - if (strict_strtol(lbuf, 10, &testcase)) - return -EINVAL; + ret = kstrtol_from_user(buf, count, 10, &testcase); + if (ret) + return ret; test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL); if (!test) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 5d088551196..bf18b6bfce4 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -27,6 +27,7 @@ #include <linux/fault-inject.h> #include <linux/random.h> #include <linux/slab.h> +#include <linux/of.h> #include <linux/mmc/card.h> #include <linux/mmc/host.h> @@ -1196,6 +1197,49 @@ u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max) } EXPORT_SYMBOL(mmc_vddrange_to_ocrmask); +#ifdef CONFIG_OF + +/** + * mmc_of_parse_voltage - return mask of supported voltages + * @np: The device node need to be parsed. + * @mask: mask of voltages available for MMC/SD/SDIO + * + * 1. Return zero on success. + * 2. Return negative errno: voltage-range is invalid. + */ +int mmc_of_parse_voltage(struct device_node *np, u32 *mask) +{ + const u32 *voltage_ranges; + int num_ranges, i; + + voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges); + num_ranges = num_ranges / sizeof(*voltage_ranges) / 2; + if (!voltage_ranges || !num_ranges) { + pr_info("%s: voltage-ranges unspecified\n", np->full_name); + return -EINVAL; + } + + for (i = 0; i < num_ranges; i++) { + const int j = i * 2; + u32 ocr_mask; + + ocr_mask = mmc_vddrange_to_ocrmask( + be32_to_cpu(voltage_ranges[j]), + be32_to_cpu(voltage_ranges[j + 1])); + if (!ocr_mask) { + pr_err("%s: voltage-range #%d is invalid\n", + np->full_name, i); + return -EINVAL; + } + *mask |= ocr_mask; + } + + return 0; +} +EXPORT_SYMBOL(mmc_of_parse_voltage); + +#endif /* CONFIG_OF */ + #ifdef CONFIG_REGULATOR /** diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 6fb6f77450c..49bc403e31f 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -374,7 +374,7 @@ int mmc_of_parse(struct mmc_host *host) if (!(flags & OF_GPIO_ACTIVE_LOW)) gpio_inv_cd = true; - ret = mmc_gpio_request_cd(host, gpio); + ret = mmc_gpio_request_cd(host, gpio, 0); if (ret < 0) { dev_err(host->parent, "Failed to request CD GPIO #%d: %d!\n", diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 837fc7386e2..ef183483d5b 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -531,6 +531,7 @@ mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, data.sg = &sg; data.sg_len = 1; + mmc_set_data_timeout(&data, card); sg_init_one(&sg, data_buf, len); mmc_wait_for_req(host, &mrq); err = 0; diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 176d125f5b5..5e8823dc3ef 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -215,7 +215,7 @@ static int mmc_decode_scr(struct mmc_card *card) static int mmc_read_ssr(struct mmc_card *card) { unsigned int au, es, et, eo; - int err, i; + int err, i, max_au; u32 *ssr; if (!(card->csd.cmdclass & CCC_APP_SPEC)) { @@ -239,12 +239,15 @@ static int mmc_read_ssr(struct mmc_card *card) for (i = 0; i < 16; i++) ssr[i] = be32_to_cpu(ssr[i]); + /* SD3.0 increases max AU size to 64MB (0xF) from 4MB (0x9) */ + max_au = card->scr.sda_spec3 ? 0xF : 0x9; + /* * UNSTUFF_BITS only works with four u32s so we have to offset the * bitfield positions accordingly. */ au = UNSTUFF_BITS(ssr, 428 - 384, 4); - if (au > 0 && au <= 9) { + if (au > 0 && au <= max_au) { card->ssr.au = 1 << (au + 4); es = UNSTUFF_BITS(ssr, 408 - 384, 16); et = UNSTUFF_BITS(ssr, 402 - 384, 6); @@ -942,13 +945,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, if (!mmc_host_is_spi(host)) { err = mmc_send_relative_addr(host, &card->rca); if (err) - return err; + goto free_card; } if (!oldcard) { err = mmc_sd_get_csd(host, card); if (err) - return err; + goto free_card; mmc_decode_cid(card); } @@ -959,7 +962,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, if (!mmc_host_is_spi(host)) { err = mmc_select_card(card); if (err) - return err; + goto free_card; } err = mmc_sd_setup_card(host, card, oldcard != NULL); diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c index 32423510551..46596b71a32 100644 --- a/drivers/mmc/core/slot-gpio.c +++ b/drivers/mmc/core/slot-gpio.c @@ -135,6 +135,7 @@ EXPORT_SYMBOL(mmc_gpio_request_ro); * mmc_gpio_request_cd - request a gpio for card-detection * @host: mmc host * @gpio: gpio number requested + * @debounce: debounce time in microseconds * * As devm_* managed functions are used in mmc_gpio_request_cd(), client * drivers do not need to explicitly call mmc_gpio_free_cd() for freeing up, @@ -143,9 +144,14 @@ EXPORT_SYMBOL(mmc_gpio_request_ro); * switching for card-detection, they are responsible for calling * mmc_gpio_request_cd() and mmc_gpio_free_cd() as a pair on their own. * + * If GPIO debouncing is desired, set the debounce parameter to a non-zero + * value. The caller is responsible for ensuring that the GPIO driver associated + * with the GPIO supports debouncing, otherwise an error will be returned. + * * Returns zero on success, else an error. */ -int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio) +int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio, + unsigned int debounce) { struct mmc_gpio *ctx; int irq = gpio_to_irq(gpio); @@ -167,6 +173,12 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio) */ return ret; + if (debounce) { + ret = gpio_set_debounce(gpio, debounce); + if (ret < 0) + return ret; + } + /* * Even if gpio_to_irq() returns a valid IRQ number, the platform might * still prefer to poll, e.g., because that IRQ number is already used diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 8a4c066787d..b7fd5ab80a4 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -284,11 +284,11 @@ config MMC_OMAP config MMC_OMAP_HS tristate "TI OMAP High Speed Multimedia Card Interface support" - depends on SOC_OMAP2430 || ARCH_OMAP3 || ARCH_OMAP4 + depends on ARCH_OMAP2PLUS || COMPILE_TEST help This selects the TI OMAP High Speed Multimedia card Interface. - If you have an OMAP2430 or OMAP3 board or OMAP4 board with a - Multimedia Card slot, say Y or M here. + If you have an omap2plus board with a Multimedia Card slot, + say Y or M here. If unsure, say N. @@ -530,7 +530,7 @@ config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND config MMC_DW tristate "Synopsys DesignWare Memory Card Interface" - depends on ARM + depends on ARC || ARM help This selects support for the Synopsys DesignWare Mobile Storage IP block, this provides host support for SD and MMC interfaces, in both @@ -569,7 +569,7 @@ config MMC_DW_EXYNOS config MMC_DW_SOCFPGA tristate "SOCFPGA specific extensions for Synopsys DW Memory Card Interface" - depends on MMC_DW + depends on MMC_DW && MFD_SYSCON select MMC_DW_PLTFM help This selects support for Altera SoCFPGA specific extensions to the diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index d422e2167e1..c41d0c36450 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -52,8 +52,6 @@ obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o -obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o - obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index bdb84da7495..69e438ee043 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -378,6 +378,8 @@ static int atmci_regs_show(struct seq_file *s, void *v) { struct atmel_mci *host = s->private; u32 *buf; + int ret = 0; + buf = kmalloc(ATMCI_REGS_SIZE, GFP_KERNEL); if (!buf) @@ -388,12 +390,16 @@ static int atmci_regs_show(struct seq_file *s, void *v) * not disabling interrupts, so IMR and SR may not be * consistent. */ + ret = clk_prepare_enable(host->mck); + if (ret) + goto out; + spin_lock_bh(&host->lock); - clk_enable(host->mck); memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE); - clk_disable(host->mck); spin_unlock_bh(&host->lock); + clk_disable_unprepare(host->mck); + seq_printf(s, "MR:\t0x%08x%s%s ", buf[ATMCI_MR / 4], buf[ATMCI_MR / 4] & ATMCI_MR_RDPROOF ? " RDPROOF" : "", @@ -442,9 +448,10 @@ static int atmci_regs_show(struct seq_file *s, void *v) val & ATMCI_CFG_LSYNC ? " LSYNC" : ""); } +out: kfree(buf); - return 0; + return ret; } static int atmci_regs_open(struct inode *inode, struct file *file) @@ -1262,6 +1269,7 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) struct atmel_mci_slot *slot = mmc_priv(mmc); struct atmel_mci *host = slot->host; unsigned int i; + bool unprepare_clk; slot->sdc_reg &= ~ATMCI_SDCBUS_MASK; switch (ios->bus_width) { @@ -1277,9 +1285,13 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) unsigned int clock_min = ~0U; u32 clkdiv; + clk_prepare(host->mck); + unprepare_clk = true; + spin_lock_bh(&host->lock); if (!host->mode_reg) { clk_enable(host->mck); + unprepare_clk = false; atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN); if (host->caps.has_cfg_reg) @@ -1347,6 +1359,8 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } else { bool any_slot_active = false; + unprepare_clk = false; + spin_lock_bh(&host->lock); slot->clock = 0; for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) { @@ -1360,12 +1374,16 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (host->mode_reg) { atmci_readl(host, ATMCI_MR); clk_disable(host->mck); + unprepare_clk = true; } host->mode_reg = 0; } spin_unlock_bh(&host->lock); } + if (unprepare_clk) + clk_unprepare(host->mck); + switch (ios->power_mode) { case MMC_POWER_UP: set_bit(ATMCI_CARD_NEED_INIT, &slot->flags); @@ -2376,10 +2394,12 @@ static int __init atmci_probe(struct platform_device *pdev) if (!host->regs) goto err_ioremap; - clk_enable(host->mck); + ret = clk_prepare_enable(host->mck); + if (ret) + goto err_request_irq; atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST); host->bus_hz = clk_get_rate(host->mck); - clk_disable(host->mck); + clk_disable_unprepare(host->mck); host->mapbase = regs->start; @@ -2482,11 +2502,11 @@ static int __exit atmci_remove(struct platform_device *pdev) atmci_cleanup_slot(host->slot[i], i); } - clk_enable(host->mck); + clk_prepare_enable(host->mck); atmci_writel(host, ATMCI_IDR, ~0UL); atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS); atmci_readl(host, ATMCI_SR); - clk_disable(host->mck); + clk_disable_unprepare(host->mck); if (host->dma.chan) dma_release_channel(host->dma.chan); diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c index 866edef2e82..6a1fa2110a0 100644 --- a/drivers/mmc/host/dw_mmc-exynos.c +++ b/drivers/mmc/host/dw_mmc-exynos.c @@ -39,6 +39,7 @@ enum dw_mci_exynos_type { DW_MCI_TYPE_EXYNOS4210, DW_MCI_TYPE_EXYNOS4412, DW_MCI_TYPE_EXYNOS5250, + DW_MCI_TYPE_EXYNOS5420, }; /* Exynos implementation specific driver private data */ @@ -62,6 +63,9 @@ static struct dw_mci_exynos_compatible { }, { .compatible = "samsung,exynos5250-dw-mshc", .ctrl_type = DW_MCI_TYPE_EXYNOS5250, + }, { + .compatible = "samsung,exynos5420-dw-mshc", + .ctrl_type = DW_MCI_TYPE_EXYNOS5420, }, }; @@ -90,7 +94,8 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host) { struct dw_mci_exynos_priv_data *priv = host->priv; - if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5250) + if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5250 || + priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420) host->bus_hz /= (priv->ciu_div + 1); else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412) host->bus_hz /= EXYNOS4412_FIXED_CIU_CLK_DIV; @@ -173,6 +178,8 @@ static const struct of_device_id dw_mci_exynos_match[] = { .data = &exynos_drv_data, }, { .compatible = "samsung,exynos5250-dw-mshc", .data = &exynos_drv_data, }, + { .compatible = "samsung,exynos5420-dw-mshc", + .data = &exynos_drv_data, }, {}, }; MODULE_DEVICE_TABLE(of, dw_mci_exynos_match); diff --git a/drivers/mmc/host/dw_mmc-pci.c b/drivers/mmc/host/dw_mmc-pci.c index b456b0c3523..f70546a3a7c 100644 --- a/drivers/mmc/host/dw_mmc-pci.c +++ b/drivers/mmc/host/dw_mmc-pci.c @@ -59,7 +59,9 @@ static int dw_mci_pci_probe(struct pci_dev *pdev, if (ret) return ret; - host->regs = pcim_iomap_table(pdev)[0]; + host->regs = pcim_iomap_table(pdev)[PCI_BAR_NO]; + + pci_set_master(pdev); ret = dw_mci_probe(host); if (ret) diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c index ee525565aa7..20897529ea5 100644 --- a/drivers/mmc/host/dw_mmc-pltfm.c +++ b/drivers/mmc/host/dw_mmc-pltfm.c @@ -23,6 +23,7 @@ #include <linux/of.h> #include "dw_mmc.h" +#include "dw_mmc-pltfm.h" static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr) { diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index 542407363dd..018f365e5ae 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1601,18 +1601,17 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id) pending = mci_readl(host, MINTSTS); /* read-only mask reg */ - if (pending) { - - /* - * DTO fix - version 2.10a and below, and only if internal DMA - * is configured. - */ - if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) { - if (!pending && - ((mci_readl(host, STATUS) >> 17) & 0x1fff)) - pending |= SDMMC_INT_DATA_OVER; - } + /* + * DTO fix - version 2.10a and below, and only if internal DMA + * is configured. + */ + if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) { + if (!pending && + ((mci_readl(host, STATUS) >> 17) & 0x1fff)) + pending |= SDMMC_INT_DATA_OVER; + } + if (pending) { if (pending & DW_MCI_CMD_ERROR_FLAGS) { mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS); host->cmd_status = pending; diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 0308c9f1cf5..66516339e3a 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -713,7 +713,7 @@ static int jz4740_mmc_request_gpios(struct mmc_host *mmc, mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; if (gpio_is_valid(pdata->gpio_card_detect)) { - ret = mmc_gpio_request_cd(mmc, pdata->gpio_card_detect); + ret = mmc_gpio_request_cd(mmc, pdata->gpio_card_detect, 0); if (ret) return ret; } @@ -783,9 +783,8 @@ static int jz4740_mmc_probe(struct platform_device* pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); host->base = devm_ioremap_resource(&pdev->dev, res); - if (!host->base) { - ret = -EBUSY; - dev_err(&pdev->dev, "Failed to ioremap base memory\n"); + if (IS_ERR(host->base)) { + ret = PTR_ERR(host->base); goto err_free_host; } diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 74145d1d51f..0a87e569134 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -36,6 +36,7 @@ #include <linux/mmc/host.h> #include <linux/mmc/mmc.h> /* for R1_SPI_* bit values */ +#include <linux/mmc/slot-gpio.h> #include <linux/spi/spi.h> #include <linux/spi/mmc_spi.h> @@ -1272,33 +1273,11 @@ static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) } } -static int mmc_spi_get_ro(struct mmc_host *mmc) -{ - struct mmc_spi_host *host = mmc_priv(mmc); - - if (host->pdata && host->pdata->get_ro) - return !!host->pdata->get_ro(mmc->parent); - /* - * Board doesn't support read only detection; let the mmc core - * decide what to do. - */ - return -ENOSYS; -} - -static int mmc_spi_get_cd(struct mmc_host *mmc) -{ - struct mmc_spi_host *host = mmc_priv(mmc); - - if (host->pdata && host->pdata->get_cd) - return !!host->pdata->get_cd(mmc->parent); - return -ENOSYS; -} - static const struct mmc_host_ops mmc_spi_ops = { .request = mmc_spi_request, .set_ios = mmc_spi_set_ios, - .get_ro = mmc_spi_get_ro, - .get_cd = mmc_spi_get_cd, + .get_ro = mmc_gpio_get_ro, + .get_cd = mmc_gpio_get_cd, }; @@ -1324,6 +1303,7 @@ static int mmc_spi_probe(struct spi_device *spi) struct mmc_host *mmc; struct mmc_spi_host *host; int status; + bool has_ro = false; /* We rely on full duplex transfers, mostly to reduce * per-transfer overheads (by making fewer transfers). @@ -1448,18 +1428,33 @@ static int mmc_spi_probe(struct spi_device *spi) } /* pass platform capabilities, if any */ - if (host->pdata) + if (host->pdata) { mmc->caps |= host->pdata->caps; + mmc->caps2 |= host->pdata->caps2; + } status = mmc_add_host(mmc); if (status != 0) goto fail_add_host; + if (host->pdata && host->pdata->flags & MMC_SPI_USE_CD_GPIO) { + status = mmc_gpio_request_cd(mmc, host->pdata->cd_gpio, + host->pdata->cd_debounce); + if (status != 0) + goto fail_add_host; + } + + if (host->pdata && host->pdata->flags & MMC_SPI_USE_RO_GPIO) { + has_ro = true; + status = mmc_gpio_request_ro(mmc, host->pdata->ro_gpio); + if (status != 0) + goto fail_add_host; + } + dev_info(&spi->dev, "SD/MMC host %s%s%s%s%s\n", dev_name(&mmc->class_dev), host->dma_dev ? "" : ", no DMA", - (host->pdata && host->pdata->get_ro) - ? "" : ", no WP", + has_ro ? "" : ", no WP", (host->pdata && host->pdata->setpower) ? "" : ", no poweroff", (mmc->caps & MMC_CAP_NEEDS_POLL) diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c index 4ddd83f9865..06c5b0b28eb 100644 --- a/drivers/mmc/host/mvsdio.c +++ b/drivers/mmc/host/mvsdio.c @@ -757,7 +757,8 @@ static int __init mvsd_probe(struct platform_device *pdev) if (mvsd_data->gpio_card_detect && gpio_is_valid(mvsd_data->gpio_card_detect)) { ret = mmc_gpio_request_cd(mmc, - mvsd_data->gpio_card_detect); + mvsd_data->gpio_card_detect, + 0); if (ret) goto out; } else { diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index f38d75f46f7..e1fa3ef735e 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -102,12 +102,15 @@ static int mxs_mmc_get_cd(struct mmc_host *mmc) BM_SSP_STATUS_CARD_DETECT) ^ host->cd_inverted; } -static void mxs_mmc_reset(struct mxs_mmc_host *host) +static int mxs_mmc_reset(struct mxs_mmc_host *host) { struct mxs_ssp *ssp = &host->ssp; u32 ctrl0, ctrl1; + int ret; - stmp_reset_block(ssp->base); + ret = stmp_reset_block(ssp->base); + if (ret) + return ret; ctrl0 = BM_SSP_CTRL0_IGNORE_CRC; ctrl1 = BF_SSP(0x3, CTRL1_SSP_MODE) | @@ -132,6 +135,7 @@ static void mxs_mmc_reset(struct mxs_mmc_host *host) writel(ctrl0, ssp->base + HW_SSP_CTRL0); writel(ctrl1, ssp->base + HW_SSP_CTRL1(ssp)); + return 0; } static void mxs_mmc_start_cmd(struct mxs_mmc_host *host, @@ -618,21 +622,25 @@ static int mxs_mmc_probe(struct platform_device *pdev) } } - ssp->clk = clk_get(&pdev->dev, NULL); + ssp->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(ssp->clk)) { ret = PTR_ERR(ssp->clk); goto out_mmc_free; } clk_prepare_enable(ssp->clk); - mxs_mmc_reset(host); + ret = mxs_mmc_reset(host); + if (ret) { + dev_err(&pdev->dev, "Failed to reset mmc: %d\n", ret); + goto out_clk_disable; + } ssp->dmach = dma_request_slave_channel(&pdev->dev, "rx-tx"); if (!ssp->dmach) { dev_err(mmc_dev(host->mmc), "%s: failed to request dma\n", __func__); ret = -ENODEV; - goto out_clk_put; + goto out_clk_disable; } /* set mmc core parameters */ @@ -685,9 +693,8 @@ static int mxs_mmc_probe(struct platform_device *pdev) out_free_dma: if (ssp->dmach) dma_release_channel(ssp->dmach); -out_clk_put: +out_clk_disable: clk_disable_unprepare(ssp->clk); - clk_put(ssp->clk); out_mmc_free: mmc_free_host(mmc); return ret; @@ -705,7 +712,6 @@ static int mxs_mmc_remove(struct platform_device *pdev) dma_release_channel(ssp->dmach); clk_disable_unprepare(ssp->clk); - clk_put(ssp->clk); mmc_free_host(mmc); diff --git a/drivers/mmc/host/of_mmc_spi.c b/drivers/mmc/host/of_mmc_spi.c index d720b5e05b9..6e218fb1a66 100644 --- a/drivers/mmc/host/of_mmc_spi.c +++ b/drivers/mmc/host/of_mmc_spi.c @@ -50,25 +50,6 @@ static struct of_mmc_spi *to_of_mmc_spi(struct device *dev) return container_of(dev->platform_data, struct of_mmc_spi, pdata); } -static int of_mmc_spi_read_gpio(struct device *dev, int gpio_num) -{ - struct of_mmc_spi *oms = to_of_mmc_spi(dev); - bool active_low = oms->alow_gpios[gpio_num]; - bool value = gpio_get_value(oms->gpios[gpio_num]); - - return active_low ^ value; -} - -static int of_mmc_spi_get_cd(struct device *dev) -{ - return of_mmc_spi_read_gpio(dev, CD_GPIO); -} - -static int of_mmc_spi_get_ro(struct device *dev) -{ - return of_mmc_spi_read_gpio(dev, WP_GPIO); -} - static int of_mmc_spi_init(struct device *dev, irqreturn_t (*irqhandler)(int, void *), void *mmc) { @@ -130,20 +111,22 @@ struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi) if (!gpio_is_valid(oms->gpios[i])) continue; - ret = gpio_request(oms->gpios[i], dev_name(dev)); - if (ret < 0) { - oms->gpios[i] = -EINVAL; - continue; - } - if (gpio_flags & OF_GPIO_ACTIVE_LOW) oms->alow_gpios[i] = true; } - if (gpio_is_valid(oms->gpios[CD_GPIO])) - oms->pdata.get_cd = of_mmc_spi_get_cd; - if (gpio_is_valid(oms->gpios[WP_GPIO])) - oms->pdata.get_ro = of_mmc_spi_get_ro; + if (gpio_is_valid(oms->gpios[CD_GPIO])) { + oms->pdata.cd_gpio = oms->gpios[CD_GPIO]; + oms->pdata.flags |= MMC_SPI_USE_CD_GPIO; + if (!oms->alow_gpios[CD_GPIO]) + oms->pdata.caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; + } + if (gpio_is_valid(oms->gpios[WP_GPIO])) { + oms->pdata.ro_gpio = oms->gpios[WP_GPIO]; + oms->pdata.flags |= MMC_SPI_USE_RO_GPIO; + if (!oms->alow_gpios[WP_GPIO]) + oms->pdata.caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; + } oms->detect_irq = irq_of_parse_and_map(np, 0); if (oms->detect_irq != 0) { @@ -166,15 +149,10 @@ void mmc_spi_put_pdata(struct spi_device *spi) struct device *dev = &spi->dev; struct device_node *np = dev->of_node; struct of_mmc_spi *oms = to_of_mmc_spi(dev); - int i; if (!dev->platform_data || !np) return; - for (i = 0; i < ARRAY_SIZE(oms->gpios); i++) { - if (gpio_is_valid(oms->gpios[i])) - gpio_free(oms->gpios[i]); - } kfree(oms); dev->platform_data = NULL; } diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 1865321465c..6ac63df645c 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -21,6 +21,7 @@ #include <linux/debugfs.h> #include <linux/dmaengine.h> #include <linux/seq_file.h> +#include <linux/sizes.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/dma-mapping.h> @@ -1041,6 +1042,7 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status) } } + OMAP_HSMMC_WRITE(host->base, STAT, status); if (end_cmd || ((status & CC_EN) && host->cmd)) omap_hsmmc_cmd_done(host, host->cmd); if ((end_trans || (status & TC_EN)) && host->mrq) @@ -1060,7 +1062,6 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id) omap_hsmmc_do_irq(host, status); /* Flush posted write */ - OMAP_HSMMC_WRITE(host->base, STAT, status); status = OMAP_HSMMC_READ(host->base, STAT); } diff --git a/drivers/mmc/host/sdhci-bcm2835.c b/drivers/mmc/host/sdhci-bcm2835.c index 0584a1c788b..36fa2df0466 100644 --- a/drivers/mmc/host/sdhci-bcm2835.c +++ b/drivers/mmc/host/sdhci-bcm2835.c @@ -119,7 +119,7 @@ static u8 bcm2835_sdhci_readb(struct sdhci_host *host, int reg) return byte; } -unsigned int bcm2835_sdhci_get_min_clock(struct sdhci_host *host) +static unsigned int bcm2835_sdhci_get_min_clock(struct sdhci_host *host) { return MIN_FREQ; } diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 1dd5ba85875..abc8cf01e6e 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -616,7 +616,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) /* card_detect */ switch (boarddata->cd_type) { case ESDHC_CD_GPIO: - err = mmc_gpio_request_cd(host->mmc, boarddata->cd_gpio); + err = mmc_gpio_request_cd(host->mmc, boarddata->cd_gpio, 0); if (err) { dev_err(mmc_dev(host->mmc), "failed to request card-detect gpio!\n"); diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 15039e2d1c1..e328252ebf2 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -316,6 +316,7 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) /* call to generic mmc_of_parse to support additional capabilities */ mmc_of_parse(host->mmc); + mmc_of_parse_voltage(np, &host->ocr_mask); ret = sdhci_add_host(host); if (ret) diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index bf99359a3a9..793dacd3b84 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -278,7 +278,8 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) host->mmc->pm_caps |= pdata->pm_caps; if (gpio_is_valid(pdata->ext_cd_gpio)) { - ret = mmc_gpio_request_cd(host->mmc, pdata->ext_cd_gpio); + ret = mmc_gpio_request_cd(host->mmc, pdata->ext_cd_gpio, + 0); if (ret) { dev_err(mmc_dev(host->mmc), "failed to allocate card detect gpio\n"); diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 926aaf6acc6..6debda95215 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -296,9 +296,12 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) unsigned long timeout; u16 clk = 0; - /* don't bother if the clock is going off */ - if (clock == 0) + /* If the clock is going off, set to 0 at clock control register */ + if (clock == 0) { + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + host->clock = clock; return; + } sdhci_s3c_set_clock(host, clock); @@ -608,6 +611,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev) host->hw_name = "samsung-hsmmc"; host->ops = &sdhci_s3c_ops; host->quirks = 0; + host->quirks2 = 0; host->irq = irq; /* Setup quirks for the controller */ diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c index 62a4a835acc..696122c1b46 100644 --- a/drivers/mmc/host/sdhci-sirf.c +++ b/drivers/mmc/host/sdhci-sirf.c @@ -84,7 +84,7 @@ static int sdhci_sirf_probe(struct platform_device *pdev) * gets setup in sdhci_add_host() and we oops. */ if (gpio_is_valid(priv->gpio_cd)) { - ret = mmc_gpio_request_cd(host->mmc, priv->gpio_cd); + ret = mmc_gpio_request_cd(host->mmc, priv->gpio_cd, 0); if (ret) { dev_err(&pdev->dev, "card detect irq request failed: %d\n", ret); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index dd2c083c434..7a7fb4f0d5a 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3119,6 +3119,9 @@ int sdhci_add_host(struct sdhci_host *host) SDHCI_MAX_CURRENT_MULTIPLIER; } + if (host->ocr_mask) + ocr_avail = host->ocr_mask; + mmc->ocr_avail = ocr_avail; mmc->ocr_avail_sdio = ocr_avail; if (host->ocr_avail_sdio) @@ -3213,6 +3216,8 @@ int sdhci_add_host(struct sdhci_host *host) host->tuning_timer.function = sdhci_tuning_timer; } + sdhci_init(host, 0); + ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, mmc_hostname(mmc), host); if (ret) { @@ -3221,8 +3226,6 @@ int sdhci_add_host(struct sdhci_host *host) goto untasklet; } - sdhci_init(host, 0); - #ifdef CONFIG_MMC_DEBUG sdhci_dumpregs(host); #endif diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 6706b5e3b97..36629a024aa 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -61,6 +61,7 @@ #include <linux/platform_device.h> #include <linux/pm_qos.h> #include <linux/pm_runtime.h> +#include <linux/sh_dma.h> #include <linux/spinlock.h> #include <linux/module.h> @@ -133,6 +134,8 @@ INT_BUFWEN | INT_CMD12DRE | INT_BUFRE | \ INT_DTRANE | INT_CMD12RBE | INT_CMD12CRE) +#define INT_CCS (INT_CCSTO | INT_CCSRCV | INT_CCSDE) + /* CE_INT_MASK */ #define MASK_ALL 0x00000000 #define MASK_MCCSDE (1 << 29) @@ -161,7 +164,7 @@ #define MASK_START_CMD (MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | \ MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | \ - MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO | \ + MASK_MCRCSTO | MASK_MWDATTO | \ MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO) #define MASK_CLEAN (INT_ERR_STS | MASK_MRBSYE | MASK_MCRSPE | \ @@ -243,6 +246,8 @@ struct sh_mmcif_host { int sg_blkidx; bool power; bool card_present; + bool ccs_enable; /* Command Completion Signal support */ + bool clk_ctrl2_enable; struct mutex thread_lock; /* DMA support */ @@ -386,25 +391,29 @@ static void sh_mmcif_request_dma(struct sh_mmcif_host *host, host->dma_active = false; - if (!pdata) - return; - - if (pdata->slave_id_tx <= 0 || pdata->slave_id_rx <= 0) + if (pdata) { + if (pdata->slave_id_tx <= 0 || pdata->slave_id_rx <= 0) + return; + } else if (!host->pd->dev.of_node) { return; + } /* We can only either use DMA for both Tx and Rx or not use it at all */ dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - host->chan_tx = dma_request_channel(mask, shdma_chan_filter, - (void *)pdata->slave_id_tx); + host->chan_tx = dma_request_slave_channel_compat(mask, shdma_chan_filter, + pdata ? (void *)pdata->slave_id_tx : NULL, + &host->pd->dev, "tx"); dev_dbg(&host->pd->dev, "%s: TX: got channel %p\n", __func__, host->chan_tx); if (!host->chan_tx) return; - cfg.slave_id = pdata->slave_id_tx; + /* In the OF case the driver will get the slave ID from the DT */ + if (pdata) + cfg.slave_id = pdata->slave_id_tx; cfg.direction = DMA_MEM_TO_DEV; cfg.dst_addr = res->start + MMCIF_CE_DATA; cfg.src_addr = 0; @@ -412,15 +421,17 @@ static void sh_mmcif_request_dma(struct sh_mmcif_host *host, if (ret < 0) goto ecfgtx; - host->chan_rx = dma_request_channel(mask, shdma_chan_filter, - (void *)pdata->slave_id_rx); + host->chan_rx = dma_request_slave_channel_compat(mask, shdma_chan_filter, + pdata ? (void *)pdata->slave_id_rx : NULL, + &host->pd->dev, "rx"); dev_dbg(&host->pd->dev, "%s: RX: got channel %p\n", __func__, host->chan_rx); if (!host->chan_rx) goto erqrx; - cfg.slave_id = pdata->slave_id_rx; + if (pdata) + cfg.slave_id = pdata->slave_id_rx; cfg.direction = DMA_DEV_TO_MEM; cfg.dst_addr = 0; cfg.src_addr = res->start + MMCIF_CE_DATA; @@ -485,8 +496,12 @@ static void sh_mmcif_sync_reset(struct sh_mmcif_host *host) sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_ON); sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_OFF); + if (host->ccs_enable) + tmp |= SCCSTO_29; + if (host->clk_ctrl2_enable) + sh_mmcif_writel(host->addr, MMCIF_CE_CLK_CTRL2, 0x0F0F0000); sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, tmp | - SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29); + SRSPTO_256 | SRBSYTO_29 | SRWDTO_29); /* byte swap on */ sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_ATYP); } @@ -866,6 +881,9 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, break; } + if (host->ccs_enable) + mask |= MASK_MCCSTO; + if (mrq->data) { sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, 0); sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, @@ -873,7 +891,10 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, } opc = sh_mmcif_set_cmd(host, mrq); - sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0); + if (host->ccs_enable) + sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0); + else + sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0 | INT_CCS); sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask); /* set arg */ sh_mmcif_writel(host->addr, MMCIF_CE_ARG, cmd->arg); @@ -956,11 +977,8 @@ static int sh_mmcif_clk_update(struct sh_mmcif_host *host) static void sh_mmcif_set_power(struct sh_mmcif_host *host, struct mmc_ios *ios) { - struct sh_mmcif_plat_data *pd = host->pd->dev.platform_data; struct mmc_host *mmc = host->mmc; - if (pd && pd->set_pwr) - pd->set_pwr(host->pd, ios->power_mode != MMC_POWER_OFF); if (!IS_ERR(mmc->supply.vmmc)) /* Errors ignored... */ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, @@ -1241,11 +1259,14 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id) static irqreturn_t sh_mmcif_intr(int irq, void *dev_id) { struct sh_mmcif_host *host = dev_id; - u32 state; + u32 state, mask; state = sh_mmcif_readl(host->addr, MMCIF_CE_INT); - sh_mmcif_writel(host->addr, MMCIF_CE_INT, - ~(state & sh_mmcif_readl(host->addr, MMCIF_CE_INT_MASK))); + mask = sh_mmcif_readl(host->addr, MMCIF_CE_INT_MASK); + if (host->ccs_enable) + sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(state & mask)); + else + sh_mmcif_writel(host->addr, MMCIF_CE_INT, INT_CCS | ~(state & mask)); sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state & MASK_CLEAN); if (state & ~MASK_CLEAN) @@ -1379,6 +1400,8 @@ static int sh_mmcif_probe(struct platform_device *pdev) host->mmc = mmc; host->addr = reg; host->timeout = msecs_to_jiffies(1000); + host->ccs_enable = !pd || !pd->ccs_unsupported; + host->clk_ctrl2_enable = pd && pd->clk_ctrl2_present; host->pd = pdev; @@ -1436,7 +1459,7 @@ static int sh_mmcif_probe(struct platform_device *pdev) } if (pd && pd->use_cd_gpio) { - ret = mmc_gpio_request_cd(mmc, pd->cd_gpio); + ret = mmc_gpio_request_cd(mmc, pd->cd_gpio, 0); if (ret < 0) goto erqcd; } diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c index ebea749297c..87ed3fb5149 100644 --- a/drivers/mmc/host/sh_mobile_sdhi.c +++ b/drivers/mmc/host/sh_mobile_sdhi.c @@ -70,20 +70,6 @@ static void sh_mobile_sdhi_clk_disable(struct platform_device *pdev) clk_disable(priv->clk); } -static void sh_mobile_sdhi_set_pwr(struct platform_device *pdev, int state) -{ - struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; - - p->set_pwr(pdev, state); -} - -static int sh_mobile_sdhi_get_cd(struct platform_device *pdev) -{ - struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; - - return p->get_cd(pdev); -} - static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host) { int timeout = 1000; @@ -129,7 +115,12 @@ static const struct sh_mobile_sdhi_ops sdhi_ops = { static const struct of_device_id sh_mobile_sdhi_of_match[] = { { .compatible = "renesas,shmobile-sdhi" }, { .compatible = "renesas,sh7372-sdhi" }, + { .compatible = "renesas,sh73a0-sdhi", .data = &sh_mobile_sdhi_of_cfg[0], }, + { .compatible = "renesas,r8a73a4-sdhi", .data = &sh_mobile_sdhi_of_cfg[0], }, { .compatible = "renesas,r8a7740-sdhi", .data = &sh_mobile_sdhi_of_cfg[0], }, + { .compatible = "renesas,r8a7778-sdhi", .data = &sh_mobile_sdhi_of_cfg[0], }, + { .compatible = "renesas,r8a7779-sdhi", .data = &sh_mobile_sdhi_of_cfg[0], }, + { .compatible = "renesas,r8a7790-sdhi", .data = &sh_mobile_sdhi_of_cfg[0], }, {}, }; MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match); @@ -180,10 +171,6 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev) mmc_data->capabilities |= p->tmio_caps; mmc_data->capabilities2 |= p->tmio_caps2; mmc_data->cd_gpio = p->cd_gpio; - if (p->set_pwr) - mmc_data->set_pwr = sh_mobile_sdhi_set_pwr; - if (p->get_cd) - mmc_data->get_cd = sh_mobile_sdhi_get_cd; if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) { /* diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c index 47bdb8fa341..65edb4a6245 100644 --- a/drivers/mmc/host/tmio_mmc_dma.c +++ b/drivers/mmc/host/tmio_mmc_dma.c @@ -104,6 +104,7 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host) pio: if (!desc) { /* DMA failed, fall back to PIO */ + tmio_mmc_enable_dma(host, false); if (ret >= 0) ret = -EIO; host->chan_rx = NULL; @@ -116,7 +117,6 @@ pio: } dev_warn(&host->pdev->dev, "DMA failed: %d, falling back to PIO\n", ret); - tmio_mmc_enable_dma(host, false); } dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__, @@ -185,6 +185,7 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host) pio: if (!desc) { /* DMA failed, fall back to PIO */ + tmio_mmc_enable_dma(host, false); if (ret >= 0) ret = -EIO; host->chan_tx = NULL; @@ -197,7 +198,6 @@ pio: } dev_warn(&host->pdev->dev, "DMA failed: %d, falling back to PIO\n", ret); - tmio_mmc_enable_dma(host, false); } dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d\n", __func__, diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index b72edb72f7d..b3802256f95 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -795,9 +795,13 @@ static void tmio_mmc_power_on(struct tmio_mmc_host *host, unsigned short vdd) * omap_hsmmc.c driver does. */ if (!IS_ERR(mmc->supply.vqmmc) && !ret) { - regulator_enable(mmc->supply.vqmmc); + ret = regulator_enable(mmc->supply.vqmmc); udelay(200); } + + if (ret < 0) + dev_dbg(&host->pdev->dev, "Regulators failed to power up: %d\n", + ret); } static void tmio_mmc_power_off(struct tmio_mmc_host *host) @@ -932,25 +936,11 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc) (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT)); } -static int tmio_mmc_get_cd(struct mmc_host *mmc) -{ - struct tmio_mmc_host *host = mmc_priv(mmc); - struct tmio_mmc_data *pdata = host->pdata; - int ret = mmc_gpio_get_cd(mmc); - if (ret >= 0) - return ret; - - if (!pdata->get_cd) - return -ENOSYS; - else - return pdata->get_cd(host->pdev); -} - 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 = tmio_mmc_get_cd, + .get_cd = mmc_gpio_get_cd, .enable_sdio_irq = tmio_mmc_enable_sdio_irq, }; @@ -1106,7 +1096,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host, dev_pm_qos_expose_latency_limit(&pdev->dev, 100); if (pdata->flags & TMIO_MMC_USE_GPIO_CD) { - ret = mmc_gpio_request_cd(mmc, pdata->cd_gpio); + ret = mmc_gpio_request_cd(mmc, pdata->cd_gpio, 0); if (ret < 0) { tmio_mmc_host_remove(_host); return ret; diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index cb9f361c03a..e9028ad05ff 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -2079,7 +2079,7 @@ static void vub300_enable_sdio_irq(struct mmc_host *mmc, int enable) kref_put(&vub300->kref, vub300_delete); } -void vub300_init_card(struct mmc_host *mmc, struct mmc_card *card) +static void vub300_init_card(struct mmc_host *mmc, struct mmc_card *card) { /* NOT irq */ struct vub300_mmc_host *vub300 = mmc_priv(mmc); dev_info(&vub300->udev->dev, "NO host QUIRKS for this card\n"); diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h index ce3511326f8..b22883d6050 100644 --- a/include/linux/mfd/tmio.h +++ b/include/linux/mfd/tmio.h @@ -108,7 +108,6 @@ struct tmio_mmc_data { unsigned int cd_gpio; void (*set_pwr)(struct platform_device *host, int state); void (*set_clk_div)(struct platform_device *host, int state); - int (*get_cd)(struct platform_device *host); int (*write16_hook)(struct tmio_mmc_host *host, int addr); /* clock management callbacks */ int (*clk_enable)(struct platform_device *pdev, unsigned int *f); diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index 443243b241d..da51bec578c 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -208,6 +208,8 @@ static inline void mmc_claim_host(struct mmc_host *host) __mmc_claim_host(host, NULL); } +struct device_node; extern u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max); +extern int mmc_of_parse_voltage(struct device_node *np, u32 *mask); #endif /* LINUX_MMC_CORE_H */ diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index e3c6a74d980..3e781b8c0be 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -171,6 +171,7 @@ struct sdhci_host { unsigned int ocr_avail_sdio; /* OCR bit masks */ unsigned int ocr_avail_sd; unsigned int ocr_avail_mmc; + u32 ocr_mask; /* available voltages */ wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */ unsigned int tuning_done; /* Condition flag set when CMD19 succeeds */ diff --git a/include/linux/mmc/sh_mmcif.h b/include/linux/mmc/sh_mmcif.h index e7d5dd67bb7..ccd8fb2cad5 100644 --- a/include/linux/mmc/sh_mmcif.h +++ b/include/linux/mmc/sh_mmcif.h @@ -16,7 +16,6 @@ #include <linux/io.h> #include <linux/platform_device.h> -#include <linux/sh_dma.h> /* * MMCIF : CE_CLK_CTRL [19:16] @@ -33,12 +32,12 @@ */ struct sh_mmcif_plat_data { - void (*set_pwr)(struct platform_device *pdev, int state); - void (*down_pwr)(struct platform_device *pdev); int (*get_cd)(struct platform_device *pdef); unsigned int slave_id_tx; /* embedded slave_id_[tr]x */ unsigned int slave_id_rx; bool use_cd_gpio : 1; + bool ccs_unsupported : 1; + bool clk_ctrl2_present : 1; unsigned int cd_gpio; u8 sup_pclk; /* 1 :SH7757, 0: SH7724/SH7372 */ unsigned long caps; @@ -62,6 +61,7 @@ struct sh_mmcif_plat_data { #define MMCIF_CE_INT_MASK 0x00000044 #define MMCIF_CE_HOST_STS1 0x00000048 #define MMCIF_CE_HOST_STS2 0x0000004C +#define MMCIF_CE_CLK_CTRL2 0x00000070 #define MMCIF_CE_VERSION 0x0000007C /* CE_BUF_ACC */ diff --git a/include/linux/mmc/sh_mobile_sdhi.h b/include/linux/mmc/sh_mobile_sdhi.h index b76bcf0621f..68927ae5084 100644 --- a/include/linux/mmc/sh_mobile_sdhi.h +++ b/include/linux/mmc/sh_mobile_sdhi.h @@ -25,8 +25,6 @@ struct sh_mobile_sdhi_info { unsigned long tmio_caps2; u32 tmio_ocr_mask; /* available MMC voltages */ unsigned int cd_gpio; - void (*set_pwr)(struct platform_device *pdev, int state); - int (*get_cd)(struct platform_device *pdev); /* callbacks for board specific setup code */ int (*init)(struct platform_device *pdev, diff --git a/include/linux/mmc/slot-gpio.h b/include/linux/mmc/slot-gpio.h index 7d88d27bfaf..b0c73e4cace 100644 --- a/include/linux/mmc/slot-gpio.h +++ b/include/linux/mmc/slot-gpio.h @@ -18,7 +18,8 @@ int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio); void mmc_gpio_free_ro(struct mmc_host *host); int mmc_gpio_get_cd(struct mmc_host *host); -int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio); +int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio, + unsigned int debounce); void mmc_gpio_free_cd(struct mmc_host *host); #endif diff --git a/include/linux/spi/mmc_spi.h b/include/linux/spi/mmc_spi.h index 32be8dbdf19..274bc0fa00a 100644 --- a/include/linux/spi/mmc_spi.h +++ b/include/linux/spi/mmc_spi.h @@ -7,6 +7,11 @@ struct device; struct mmc_host; +#define MMC_SPI_USE_CD_GPIO (1 << 0) +#define MMC_SPI_USE_RO_GPIO (1 << 1) +#define MMC_SPI_CD_GPIO_ACTIVE_LOW (1 << 2) +#define MMC_SPI_RO_GPIO_ACTIVE_LOW (1 << 3) + /* Put this in platform_data of a device being used to manage an MMC/SD * card slot. (Modeled after PXA mmc glue; see that for usage examples.) * @@ -21,17 +26,19 @@ struct mmc_spi_platform_data { void *); void (*exit)(struct device *, void *); - /* sense switch on sd cards */ - int (*get_ro)(struct device *); - /* - * If board does not use CD interrupts, driver can optimize polling - * using this function. + * Card Detect and Read Only GPIOs. To enable debouncing on the card + * detect GPIO, set the cd_debounce to the debounce time in + * microseconds. */ - int (*get_cd)(struct device *); + unsigned int flags; + unsigned int cd_gpio; + unsigned int cd_debounce; + unsigned int ro_gpio; /* Capabilities to pass into mmc core (e.g. MMC_CAP_NEEDS_POLL). */ unsigned long caps; + unsigned long caps2; /* how long to debounce card detect, in msecs */ u16 detect_delay; |