diff options
Diffstat (limited to 'drivers/mmc/host/atmel-mci.c')
-rw-r--r-- | drivers/mmc/host/atmel-mci.c | 140 |
1 files changed, 84 insertions, 56 deletions
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index dd18440a90c5..535783c43105 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -11,15 +11,14 @@ #include <linux/dmaengine.h> #include <linux/dma-mapping.h> #include <linux/err.h> -#include <linux/gpio.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/ioport.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> -#include <linux/of_gpio.h> +#include <linux/irq.h> +#include <linux/gpio/consumer.h> #include <linux/platform_device.h> #include <linux/scatterlist.h> #include <linux/seq_file.h> @@ -30,7 +29,6 @@ #include <linux/mmc/host.h> #include <linux/mmc/sdio.h> -#include <linux/atmel-mci.h> #include <linux/atmel_pdc.h> #include <linux/pm.h> #include <linux/pm_runtime.h> @@ -40,6 +38,8 @@ #include <asm/io.h> #include <asm/unaligned.h> +#define ATMCI_MAX_NR_SLOTS 2 + /* * Superset of MCI IP registers integrated in Atmel AT91 Processor * Registers and bitfields marked with [2] are only available in MCI2 @@ -201,6 +201,40 @@ enum atmci_pdc_buf { PDC_SECOND_BUF, }; +/** + * struct mci_slot_pdata - board-specific per-slot configuration + * @bus_width: Number of data lines wired up the slot + * @detect_pin: GPIO pin wired to the card detect switch + * @wp_pin: GPIO pin wired to the write protect sensor + * @non_removable: The slot is not removable, only detect once + * + * If a given slot is not present on the board, @bus_width should be + * set to 0. The other fields are ignored in this case. + * + * Any pins that aren't available should be set to a negative value. + * + * Note that support for multiple slots is experimental -- some cards + * might get upset if we don't get the clock management exactly right. + * But in most cases, it should work just fine. + */ +struct mci_slot_pdata { + unsigned int bus_width; + struct gpio_desc *detect_pin; + struct gpio_desc *wp_pin; + bool non_removable; +}; + +/** + * struct mci_platform_data - board-specific MMC/SDcard configuration + * @dma_slave: DMA slave interface to use in data transfers. + * @slot: Per-slot configuration data. + */ +struct mci_platform_data { + void *dma_slave; + dma_filter_fn dma_filter; + struct mci_slot_pdata slot[ATMCI_MAX_NR_SLOTS]; +}; + struct atmel_mci_caps { bool has_dma_conf_reg; bool has_pdc; @@ -369,7 +403,6 @@ struct atmel_mci { * available. * @wp_pin: GPIO pin used for card write protect sending, or negative * if not available. - * @detect_is_active_high: The state of the detect pin when it is active. * @detect_timer: Timer used for debouncing @detect_pin interrupts. */ struct atmel_mci_slot { @@ -388,9 +421,8 @@ struct atmel_mci_slot { #define ATMCI_CARD_NEED_INIT 1 #define ATMCI_SHUTDOWN 2 - int detect_pin; - int wp_pin; - bool detect_is_active_high; + struct gpio_desc *detect_pin; + struct gpio_desc *wp_pin; struct timer_list detect_timer; }; @@ -608,6 +640,7 @@ atmci_of_init(struct platform_device *pdev) struct device_node *cnp; struct mci_platform_data *pdata; u32 slot_id; + int err; if (!np) { dev_err(&pdev->dev, "device node not found\n"); @@ -637,16 +670,27 @@ atmci_of_init(struct platform_device *pdev) pdata->slot[slot_id].bus_width = 1; pdata->slot[slot_id].detect_pin = - of_get_named_gpio(cnp, "cd-gpios", 0); - - pdata->slot[slot_id].detect_is_active_high = - of_property_read_bool(cnp, "cd-inverted"); + devm_fwnode_gpiod_get(&pdev->dev, of_fwnode_handle(cnp), + "cd", GPIOD_IN, "cd-gpios"); + err = PTR_ERR_OR_ZERO(pdata->slot[slot_id].detect_pin); + if (err) { + if (err != -ENOENT) + return ERR_PTR(err); + pdata->slot[slot_id].detect_pin = NULL; + } pdata->slot[slot_id].non_removable = of_property_read_bool(cnp, "non-removable"); pdata->slot[slot_id].wp_pin = - of_get_named_gpio(cnp, "wp-gpios", 0); + devm_fwnode_gpiod_get(&pdev->dev, of_fwnode_handle(cnp), + "wp", GPIOD_IN, "wp-gpios"); + err = PTR_ERR_OR_ZERO(pdata->slot[slot_id].wp_pin); + if (err) { + if (err != -ENOENT) + return ERR_PTR(err); + pdata->slot[slot_id].wp_pin = NULL; + } } return pdata; @@ -1509,8 +1553,8 @@ static int atmci_get_ro(struct mmc_host *mmc) int read_only = -ENOSYS; struct atmel_mci_slot *slot = mmc_priv(mmc); - if (gpio_is_valid(slot->wp_pin)) { - read_only = gpio_get_value(slot->wp_pin); + if (slot->wp_pin) { + read_only = gpiod_get_value(slot->wp_pin); dev_dbg(&mmc->class_dev, "card is %s\n", read_only ? "read-only" : "read-write"); } @@ -1523,9 +1567,8 @@ static int atmci_get_cd(struct mmc_host *mmc) int present = -ENOSYS; struct atmel_mci_slot *slot = mmc_priv(mmc); - if (gpio_is_valid(slot->detect_pin)) { - present = !(gpio_get_value(slot->detect_pin) ^ - slot->detect_is_active_high); + if (slot->detect_pin) { + present = gpiod_get_value_cansleep(slot->detect_pin); dev_dbg(&mmc->class_dev, "card is %spresent\n", present ? "" : "not "); } @@ -1637,9 +1680,8 @@ static void atmci_detect_change(struct timer_list *t) if (test_bit(ATMCI_SHUTDOWN, &slot->flags)) return; - enable_irq(gpio_to_irq(slot->detect_pin)); - present = !(gpio_get_value(slot->detect_pin) ^ - slot->detect_is_active_high); + enable_irq(gpiod_to_irq(slot->detect_pin)); + present = gpiod_get_value_cansleep(slot->detect_pin); present_old = test_bit(ATMCI_CARD_PRESENT, &slot->flags); dev_vdbg(&slot->mmc->class_dev, "detect change: %d (was %d)\n", @@ -2230,16 +2272,15 @@ static int atmci_init_slot(struct atmel_mci *host, slot->host = host; slot->detect_pin = slot_data->detect_pin; slot->wp_pin = slot_data->wp_pin; - slot->detect_is_active_high = slot_data->detect_is_active_high; slot->sdc_reg = sdc_reg; slot->sdio_irq = sdio_irq; dev_dbg(&mmc->class_dev, "slot[%u]: bus_width=%u, detect_pin=%d, " "detect_is_active_high=%s, wp_pin=%d\n", - id, slot_data->bus_width, slot_data->detect_pin, - slot_data->detect_is_active_high ? "true" : "false", - slot_data->wp_pin); + id, slot_data->bus_width, desc_to_gpio(slot_data->detect_pin), + !gpiod_is_active_low(slot_data->detect_pin) ? "true" : "false", + desc_to_gpio(slot_data->wp_pin)); mmc->ops = &atmci_ops; mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512); @@ -2275,31 +2316,22 @@ static int atmci_init_slot(struct atmel_mci *host, /* Assume card is present initially */ set_bit(ATMCI_CARD_PRESENT, &slot->flags); - if (gpio_is_valid(slot->detect_pin)) { - if (devm_gpio_request(&host->pdev->dev, slot->detect_pin, - "mmc_detect")) { - dev_dbg(&mmc->class_dev, "no detect pin available\n"); - slot->detect_pin = -EBUSY; - } else if (gpio_get_value(slot->detect_pin) ^ - slot->detect_is_active_high) { + if (slot->detect_pin) { + if (!gpiod_get_value_cansleep(slot->detect_pin)) clear_bit(ATMCI_CARD_PRESENT, &slot->flags); - } + } else { + dev_dbg(&mmc->class_dev, "no detect pin available\n"); } - if (!gpio_is_valid(slot->detect_pin)) { + if (!slot->detect_pin) { if (slot_data->non_removable) mmc->caps |= MMC_CAP_NONREMOVABLE; else mmc->caps |= MMC_CAP_NEEDS_POLL; } - if (gpio_is_valid(slot->wp_pin)) { - if (devm_gpio_request(&host->pdev->dev, slot->wp_pin, - "mmc_wp")) { - dev_dbg(&mmc->class_dev, "no WP pin available\n"); - slot->wp_pin = -EBUSY; - } - } + if (!slot->wp_pin) + dev_dbg(&mmc->class_dev, "no WP pin available\n"); host->slot[id] = slot; mmc_regulator_get_supply(mmc); @@ -2309,18 +2341,18 @@ static int atmci_init_slot(struct atmel_mci *host, return ret; } - if (gpio_is_valid(slot->detect_pin)) { + if (slot->detect_pin) { timer_setup(&slot->detect_timer, atmci_detect_change, 0); - ret = request_irq(gpio_to_irq(slot->detect_pin), - atmci_detect_interrupt, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - "mmc-detect", slot); + ret = request_irq(gpiod_to_irq(slot->detect_pin), + atmci_detect_interrupt, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + "mmc-detect", slot); if (ret) { dev_dbg(&mmc->class_dev, "could not request IRQ %d for detect pin\n", - gpio_to_irq(slot->detect_pin)); - slot->detect_pin = -EBUSY; + gpiod_to_irq(slot->detect_pin)); + slot->detect_pin = NULL; } } @@ -2339,10 +2371,8 @@ static void atmci_cleanup_slot(struct atmel_mci_slot *slot, mmc_remove_host(slot->mmc); - if (gpio_is_valid(slot->detect_pin)) { - int pin = slot->detect_pin; - - free_irq(gpio_to_irq(pin), slot); + if (slot->detect_pin) { + free_irq(gpiod_to_irq(slot->detect_pin), slot); del_timer_sync(&slot->detect_timer); } @@ -2600,7 +2630,7 @@ err_dma_probe_defer: return ret; } -static int atmci_remove(struct platform_device *pdev) +static void atmci_remove(struct platform_device *pdev) { struct atmel_mci *host = platform_get_drvdata(pdev); unsigned int i; @@ -2630,8 +2660,6 @@ static int atmci_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); - - return 0; } #ifdef CONFIG_PM @@ -2664,7 +2692,7 @@ static const struct dev_pm_ops atmci_dev_pm_ops = { static struct platform_driver atmci_driver = { .probe = atmci_probe, - .remove = atmci_remove, + .remove_new = atmci_remove, .driver = { .name = "atmel_mci", .probe_type = PROBE_PREFER_ASYNCHRONOUS, |