diff options
Diffstat (limited to 'drivers/mmc')
34 files changed, 618 insertions, 516 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index d8486168415a..5914263090fc 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -171,11 +171,7 @@ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk) static inline int mmc_get_devidx(struct gendisk *disk) { - int devmaj = MAJOR(disk_devt(disk)); - int devidx = MINOR(disk_devt(disk)) / perdev_minors; - - if (!devmaj) - devidx = disk->first_minor / perdev_minors; + int devidx = disk->first_minor / perdev_minors; return devidx; } @@ -344,7 +340,7 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( struct mmc_blk_ioc_data *idata; int err; - idata = kzalloc(sizeof(*idata), GFP_KERNEL); + idata = kmalloc(sizeof(*idata), GFP_KERNEL); if (!idata) { err = -ENOMEM; goto out; @@ -364,7 +360,7 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( if (!idata->buf_bytes) return idata; - idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL); + idata->buf = kmalloc(idata->buf_bytes, GFP_KERNEL); if (!idata->buf) { err = -ENOMEM; goto idata_err; @@ -2244,6 +2240,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card, md->disk->queue = md->queue.queue; md->disk->driverfs_dev = parent; set_disk_ro(md->disk, md->read_only || default_ro); + md->disk->flags = GENHD_FL_EXT_DEVT; if (area_type & (MMC_BLK_DATA_AREA_RPMB | MMC_BLK_DATA_AREA_BOOT)) md->disk->flags |= GENHD_FL_NO_PART_SCAN; diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 972ff844cf5a..4bc48f10452f 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -349,6 +349,8 @@ int mmc_add_card(struct mmc_card *card) card->dev.of_node = mmc_of_find_child_device(card->host, 0); + device_enable_async_suspend(&card->dev); + ret = device_add(&card->dev); if (ret) return ret; diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 5ae89e48fd85..f95d41ffc766 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -55,7 +55,6 @@ */ #define MMC_BKOPS_MAX_TIMEOUT (4 * 60 * 1000) /* max time to wait in ms */ -static struct workqueue_struct *workqueue; static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; /* @@ -66,21 +65,16 @@ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; bool use_spi_crc = 1; module_param(use_spi_crc, bool, 0); -/* - * Internal function. Schedule delayed work in the MMC work queue. - */ static int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay) { - return queue_delayed_work(workqueue, work, delay); -} - -/* - * Internal function. Flush all scheduled work from the MMC work queue. - */ -static void mmc_flush_scheduled_work(void) -{ - flush_workqueue(workqueue); + /* + * We use the system_freezable_wq, because of two reasons. + * First, it allows several works (not the same work item) to be + * executed simultaneously. Second, the queue becomes frozen when + * userspace becomes frozen during system PM. + */ + return queue_delayed_work(system_freezable_wq, work, delay); } #ifdef CONFIG_FAIL_MMC_REQUEST @@ -1485,7 +1479,7 @@ int mmc_regulator_get_supply(struct mmc_host *mmc) if (IS_ERR(mmc->supply.vmmc)) { if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER) return -EPROBE_DEFER; - dev_info(dev, "No vmmc regulator found\n"); + dev_dbg(dev, "No vmmc regulator found\n"); } else { ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc); if (ret > 0) @@ -1497,7 +1491,7 @@ int mmc_regulator_get_supply(struct mmc_host *mmc) if (IS_ERR(mmc->supply.vqmmc)) { if (PTR_ERR(mmc->supply.vqmmc) == -EPROBE_DEFER) return -EPROBE_DEFER; - dev_info(dev, "No vqmmc regulator found\n"); + dev_dbg(dev, "No vqmmc regulator found\n"); } return 0; @@ -2476,15 +2470,20 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) * sdio_reset sends CMD52 to reset card. Since we do not know * if the card is being re-initialized, just send it. CMD52 * should be ignored by SD/eMMC cards. + * Skip it if we already know that we do not support SDIO commands */ - sdio_reset(host); + if (!(host->caps2 & MMC_CAP2_NO_SDIO)) + sdio_reset(host); + mmc_go_idle(host); mmc_send_if_cond(host, host->ocr_avail); /* Order's important: probe SDIO, then SD, then MMC */ - if (!mmc_attach_sdio(host)) - return 0; + if (!(host->caps2 & MMC_CAP2_NO_SDIO)) + if (!mmc_attach_sdio(host)) + return 0; + if (!mmc_attach_sd(host)) return 0; if (!mmc_attach_mmc(host)) @@ -2498,9 +2497,6 @@ int _mmc_detect_card_removed(struct mmc_host *host) { int ret; - if (host->caps & MMC_CAP_NONREMOVABLE) - return 0; - if (!host->card || mmc_card_removed(host->card)) return 1; @@ -2536,6 +2532,9 @@ int mmc_detect_card_removed(struct mmc_host *host) if (!card) return 1; + if (host->caps & MMC_CAP_NONREMOVABLE) + return 0; + ret = mmc_card_removed(card); /* * The card will be considered unchanged unless we have been asked to @@ -2567,11 +2566,6 @@ void mmc_rescan(struct work_struct *work) container_of(work, struct mmc_host, detect.work); int i; - if (host->trigger_card_event && host->ops->card_event) { - host->ops->card_event(host); - host->trigger_card_event = false; - } - if (host->rescan_disable) return; @@ -2580,6 +2574,13 @@ void mmc_rescan(struct work_struct *work) return; host->rescan_entered = 1; + if (host->trigger_card_event && host->ops->card_event) { + mmc_claim_host(host); + host->ops->card_event(host); + mmc_release_host(host); + host->trigger_card_event = false; + } + mmc_bus_get(host); /* @@ -2611,15 +2612,14 @@ void mmc_rescan(struct work_struct *work) */ mmc_bus_put(host); + mmc_claim_host(host); if (!(host->caps & MMC_CAP_NONREMOVABLE) && host->ops->get_cd && host->ops->get_cd(host) == 0) { - mmc_claim_host(host); mmc_power_off(host); mmc_release_host(host); goto out; } - mmc_claim_host(host); for (i = 0; i < ARRAY_SIZE(freqs); i++) { if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) break; @@ -2663,7 +2663,6 @@ void mmc_stop_host(struct mmc_host *host) host->rescan_disable = 1; cancel_delayed_work_sync(&host->detect); - mmc_flush_scheduled_work(); /* clear pm flags now and let card drivers set them as needed */ host->pm_flags = 0; @@ -2759,14 +2758,13 @@ int mmc_flush_cache(struct mmc_card *card) } EXPORT_SYMBOL(mmc_flush_cache); -#ifdef CONFIG_PM - +#ifdef CONFIG_PM_SLEEP /* Do the card removal on suspend if card is assumed removeable * Do that in pm notifier while userspace isn't yet frozen, so we will be able to sync the card. */ -int mmc_pm_notify(struct notifier_block *notify_block, - unsigned long mode, void *unused) +static int mmc_pm_notify(struct notifier_block *notify_block, + unsigned long mode, void *unused) { struct mmc_host *host = container_of( notify_block, struct mmc_host, pm_notify); @@ -2813,6 +2811,17 @@ int mmc_pm_notify(struct notifier_block *notify_block, return 0; } + +void mmc_register_pm_notifier(struct mmc_host *host) +{ + host->pm_notify.notifier_call = mmc_pm_notify; + register_pm_notifier(&host->pm_notify); +} + +void mmc_unregister_pm_notifier(struct mmc_host *host) +{ + unregister_pm_notifier(&host->pm_notify); +} #endif /** @@ -2836,13 +2845,9 @@ static int __init mmc_init(void) { int ret; - workqueue = alloc_ordered_workqueue("kmmcd", 0); - if (!workqueue) - return -ENOMEM; - ret = mmc_register_bus(); if (ret) - goto destroy_workqueue; + return ret; ret = mmc_register_host_class(); if (ret) @@ -2858,9 +2863,6 @@ unregister_host_class: mmc_unregister_host_class(); unregister_bus: mmc_unregister_bus(); -destroy_workqueue: - destroy_workqueue(workqueue); - return ret; } @@ -2869,7 +2871,6 @@ static void __exit mmc_exit(void) sdio_unregister_bus(); mmc_unregister_host_class(); mmc_unregister_bus(); - destroy_workqueue(workqueue); } subsys_initcall(mmc_init); diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index 09241e56d628..0fa86a2afc26 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -90,5 +90,13 @@ int mmc_execute_tuning(struct mmc_card *card); int mmc_hs200_to_hs400(struct mmc_card *card); int mmc_hs400_to_hs200(struct mmc_card *card); +#ifdef CONFIG_PM_SLEEP +void mmc_register_pm_notifier(struct mmc_host *host); +void mmc_unregister_pm_notifier(struct mmc_host *host); +#else +static inline void mmc_register_pm_notifier(struct mmc_host *host) { } +static inline void mmc_unregister_pm_notifier(struct mmc_host *host) { } +#endif + #endif diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index da950c44204d..0aecd5c00b86 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -21,7 +21,6 @@ #include <linux/export.h> #include <linux/leds.h> #include <linux/slab.h> -#include <linux/suspend.h> #include <linux/mmc/host.h> #include <linux/mmc/card.h> @@ -275,7 +274,8 @@ int mmc_of_parse(struct mmc_host *host) host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE; if (of_property_read_bool(np, "keep-power-in-suspend")) host->pm_caps |= MMC_PM_KEEP_POWER; - if (of_property_read_bool(np, "enable-sdio-wakeup")) + if (of_property_read_bool(np, "wakeup-source") || + of_property_read_bool(np, "enable-sdio-wakeup")) /* legacy */ host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; if (of_property_read_bool(np, "mmc-ddr-1_8v")) host->caps |= MMC_CAP_1_8V_DDR; @@ -348,9 +348,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) spin_lock_init(&host->lock); init_waitqueue_head(&host->wq); INIT_DELAYED_WORK(&host->detect, mmc_rescan); -#ifdef CONFIG_PM - host->pm_notify.notifier_call = mmc_pm_notify; -#endif setup_timer(&host->retune_timer, mmc_retune_timer, (unsigned long)host); /* @@ -395,7 +392,7 @@ int mmc_add_host(struct mmc_host *host) #endif mmc_start_host(host); - register_pm_notifier(&host->pm_notify); + mmc_register_pm_notifier(host); return 0; } @@ -412,7 +409,7 @@ EXPORT_SYMBOL(mmc_add_host); */ void mmc_remove_host(struct mmc_host *host) { - unregister_pm_notifier(&host->pm_notify); + mmc_unregister_pm_notifier(host); mmc_stop_host(host); #ifdef CONFIG_DEBUG_FS diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 3a9a79ec4343..bf49e44571f2 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1076,8 +1076,7 @@ static int mmc_select_hs400(struct mmc_card *card) mmc_set_clock(host, max_dtr); /* Switch card to HS mode */ - val = EXT_CSD_TIMING_HS | - card->drive_strength << EXT_CSD_DRV_STR_SHIFT; + val = EXT_CSD_TIMING_HS; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, card->ext_csd.generic_cmd6_time, @@ -1160,8 +1159,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card) mmc_set_clock(host, max_dtr); /* Switch HS400 to HS DDR */ - val = EXT_CSD_TIMING_HS | - card->drive_strength << EXT_CSD_DRV_STR_SHIFT; + val = EXT_CSD_TIMING_HS; err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, card->ext_csd.generic_cmd6_time, true, send_status, true); @@ -1907,16 +1905,8 @@ static int mmc_shutdown(struct mmc_host *host) */ static int mmc_resume(struct mmc_host *host) { - int err = 0; - - if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) { - err = _mmc_resume(host); - pm_runtime_set_active(&host->card->dev); - pm_runtime_mark_last_busy(&host->card->dev); - } pm_runtime_enable(&host->card->dev); - - return err; + return 0; } /* @@ -1944,12 +1934,9 @@ static int mmc_runtime_resume(struct mmc_host *host) { int err; - if (!(host->caps & (MMC_CAP_AGGRESSIVE_PM | MMC_CAP_RUNTIME_RESUME))) - return 0; - err = _mmc_resume(host); - if (err) - pr_err("%s: error %d doing aggressive resume\n", + if (err && err != -ENOMEDIUM) + pr_err("%s: error %d doing runtime resume\n", mmc_hostname(host), err); return 0; diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index 1f444269ebbe..2c90635c89af 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -489,6 +489,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, unsigned long timeout; u32 status = 0; bool use_r1b_resp = use_busy_signal; + bool expired = false; mmc_retune_hold(host); @@ -545,6 +546,12 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, timeout = jiffies + msecs_to_jiffies(timeout_ms); do { if (send_status) { + /* + * Due to the possibility of being preempted after + * sending the status command, check the expiration + * time first. + */ + expired = time_after(jiffies, timeout); err = __mmc_send_status(card, &status, ignore_crc); if (err) goto out; @@ -565,7 +572,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, } /* Timeout if the device never leaves the program state. */ - if (time_after(jiffies, timeout)) { + if (expired && R1_CURRENT_STATE(status) == R1_STATE_PRG) { pr_err("%s: Card stuck in programming state! %s\n", mmc_hostname(host), __func__); err = -ETIMEDOUT; diff --git a/drivers/mmc/core/pwrseq.h b/drivers/mmc/core/pwrseq.h index 096da48c6a7e..133de0426687 100644 --- a/drivers/mmc/core/pwrseq.h +++ b/drivers/mmc/core/pwrseq.h @@ -16,7 +16,7 @@ struct mmc_pwrseq_ops { }; struct mmc_pwrseq { - struct mmc_pwrseq_ops *ops; + const struct mmc_pwrseq_ops *ops; }; #ifdef CONFIG_OF diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c index ad4f94ec7e8d..4a82bc77fe49 100644 --- a/drivers/mmc/core/pwrseq_emmc.c +++ b/drivers/mmc/core/pwrseq_emmc.c @@ -51,7 +51,7 @@ static void mmc_pwrseq_emmc_free(struct mmc_host *host) kfree(pwrseq); } -static struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = { +static const struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = { .post_power_on = mmc_pwrseq_emmc_reset, .free = mmc_pwrseq_emmc_free, }; diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c index d10538bb5e07..2b16263458af 100644 --- a/drivers/mmc/core/pwrseq_simple.c +++ b/drivers/mmc/core/pwrseq_simple.c @@ -87,7 +87,7 @@ static void mmc_pwrseq_simple_free(struct mmc_host *host) kfree(pwrseq); } -static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = { +static const struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = { .pre_power_on = mmc_pwrseq_simple_pre_power_on, .post_power_on = mmc_pwrseq_simple_post_power_on, .power_off = mmc_pwrseq_simple_power_off, diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 141eaa923e18..f2b164b214ae 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1128,16 +1128,8 @@ out: */ static int mmc_sd_resume(struct mmc_host *host) { - int err = 0; - - if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) { - err = _mmc_sd_resume(host); - pm_runtime_set_active(&host->card->dev); - pm_runtime_mark_last_busy(&host->card->dev); - } pm_runtime_enable(&host->card->dev); - - return err; + return 0; } /* @@ -1165,12 +1157,9 @@ static int mmc_sd_runtime_resume(struct mmc_host *host) { int err; - if (!(host->caps & (MMC_CAP_AGGRESSIVE_PM | MMC_CAP_RUNTIME_RESUME))) - return 0; - err = _mmc_sd_resume(host); - if (err) - pr_err("%s: error %d doing aggressive resume\n", + if (err && err != -ENOMEDIUM) + pr_err("%s: error %d doing runtime resume\n", mmc_hostname(host), err); return 0; diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 16d838e6d623..d61ba1a0495e 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -630,7 +630,7 @@ try_again: */ if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) { err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, - ocr); + ocr_card); if (err == -EAGAIN) { sdio_reset(host); mmc_go_idle(host); diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 7e327a6dd53d..86f5b3223aae 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -322,6 +322,7 @@ int sdio_add_func(struct sdio_func *func) sdio_set_of_node(func); sdio_acpi_set_handle(func); + device_enable_async_suspend(&func->dev); ret = device_add(&func->dev); if (ret == 0) sdio_func_set_present(func); diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 1dee533634c9..1526b8a10b09 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -455,6 +455,7 @@ config MMC_TIFM_SD config MMC_MVSDIO tristate "Marvell MMC/SD/SDIO host driver" depends on PLAT_ORION + depends on OF ---help--- This selects the Marvell SDIO host driver. SDIO may currently be found on the Kirkwood 88F6281 and 88F6192 diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h deleted file mode 100644 index 0aa44e679df4..000000000000 --- a/drivers/mmc/host/atmel-mci-regs.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Atmel MultiMedia Card Interface driver - * - * Copyright (C) 2004-2006 Atmel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* - * Superset of MCI IP registers integrated in Atmel AVR32 and AT91 Processors - * Registers and bitfields marked with [2] are only available in MCI2 - */ - -#ifndef __DRIVERS_MMC_ATMEL_MCI_H__ -#define __DRIVERS_MMC_ATMEL_MCI_H__ - -/* MCI Register Definitions */ -#define ATMCI_CR 0x0000 /* Control */ -# define ATMCI_CR_MCIEN ( 1 << 0) /* MCI Enable */ -# define ATMCI_CR_MCIDIS ( 1 << 1) /* MCI Disable */ -# define ATMCI_CR_PWSEN ( 1 << 2) /* Power Save Enable */ -# define ATMCI_CR_PWSDIS ( 1 << 3) /* Power Save Disable */ -# define ATMCI_CR_SWRST ( 1 << 7) /* Software Reset */ -#define ATMCI_MR 0x0004 /* Mode */ -# define ATMCI_MR_CLKDIV(x) ((x) << 0) /* Clock Divider */ -# define ATMCI_MR_PWSDIV(x) ((x) << 8) /* Power Saving Divider */ -# define ATMCI_MR_RDPROOF ( 1 << 11) /* Read Proof */ -# define ATMCI_MR_WRPROOF ( 1 << 12) /* Write Proof */ -# define ATMCI_MR_PDCFBYTE ( 1 << 13) /* Force Byte Transfer */ -# define ATMCI_MR_PDCPADV ( 1 << 14) /* Padding Value */ -# define ATMCI_MR_PDCMODE ( 1 << 15) /* PDC-oriented Mode */ -# define ATMCI_MR_CLKODD(x) ((x) << 16) /* LSB of Clock Divider */ -#define ATMCI_DTOR 0x0008 /* Data Timeout */ -# define ATMCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */ -# define ATMCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */ -#define ATMCI_SDCR 0x000c /* SD Card / SDIO */ -# define ATMCI_SDCSEL_SLOT_A ( 0 << 0) /* Select SD slot A */ -# define ATMCI_SDCSEL_SLOT_B ( 1 << 0) /* Select SD slot A */ -# define ATMCI_SDCSEL_MASK ( 3 << 0) -# define ATMCI_SDCBUS_1BIT ( 0 << 6) /* 1-bit data bus */ -# define ATMCI_SDCBUS_4BIT ( 2 << 6) /* 4-bit data bus */ -# define ATMCI_SDCBUS_8BIT ( 3 << 6) /* 8-bit data bus[2] */ -# define ATMCI_SDCBUS_MASK ( 3 << 6) -#define ATMCI_ARGR 0x0010 /* Command Argument */ -#define ATMCI_CMDR 0x0014 /* Command */ -# define ATMCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */ -# define ATMCI_CMDR_RSPTYP_NONE ( 0 << 6) /* No response */ -# define ATMCI_CMDR_RSPTYP_48BIT ( 1 << 6) /* 48-bit response */ -# define ATMCI_CMDR_RSPTYP_136BIT ( 2 << 6) /* 136-bit response */ -# define ATMCI_CMDR_SPCMD_INIT ( 1 << 8) /* Initialization command */ -# define ATMCI_CMDR_SPCMD_SYNC ( 2 << 8) /* Synchronized command */ -# define ATMCI_CMDR_SPCMD_INT ( 4 << 8) /* Interrupt command */ -# define ATMCI_CMDR_SPCMD_INTRESP ( 5 << 8) /* Interrupt response */ -# define ATMCI_CMDR_OPDCMD ( 1 << 11) /* Open Drain */ -# define ATMCI_CMDR_MAXLAT_5CYC ( 0 << 12) /* Max latency 5 cycles */ -# define ATMCI_CMDR_MAXLAT_64CYC ( 1 << 12) /* Max latency 64 cycles */ -# define ATMCI_CMDR_START_XFER ( 1 << 16) /* Start data transfer */ -# define ATMCI_CMDR_STOP_XFER ( 2 << 16) /* Stop data transfer */ -# define ATMCI_CMDR_TRDIR_WRITE ( 0 << 18) /* Write data */ -# define ATMCI_CMDR_TRDIR_READ ( 1 << 18) /* Read data */ -# define ATMCI_CMDR_BLOCK ( 0 << 19) /* Single-block transfer */ -# define ATMCI_CMDR_MULTI_BLOCK ( 1 << 19) /* Multi-block transfer */ -# define ATMCI_CMDR_STREAM ( 2 << 19) /* MMC Stream transfer */ -# define ATMCI_CMDR_SDIO_BYTE ( 4 << 19) /* SDIO Byte transfer */ -# define ATMCI_CMDR_SDIO_BLOCK ( 5 << 19) /* SDIO Block transfer */ -# define ATMCI_CMDR_SDIO_SUSPEND ( 1 << 24) /* SDIO Suspend Command */ -# define ATMCI_CMDR_SDIO_RESUME ( 2 << 24) /* SDIO Resume Command */ -#define ATMCI_BLKR 0x0018 /* Block */ -# define ATMCI_BCNT(x) ((x) << 0) /* Data Block Count */ -# define ATMCI_BLKLEN(x) ((x) << 16) /* Data Block Length */ -#define ATMCI_CSTOR 0x001c /* Completion Signal Timeout[2] */ -# define ATMCI_CSTOCYC(x) ((x) << 0) /* CST cycles */ -# define ATMCI_CSTOMUL(x) ((x) << 4) /* CST multiplier */ -#define ATMCI_RSPR 0x0020 /* Response 0 */ -#define ATMCI_RSPR1 0x0024 /* Response 1 */ -#define ATMCI_RSPR2 0x0028 /* Response 2 */ -#define ATMCI_RSPR3 0x002c /* Response 3 */ -#define ATMCI_RDR 0x0030 /* Receive Data */ -#define ATMCI_TDR 0x0034 /* Transmit Data */ -#define ATMCI_SR 0x0040 /* Status */ -#define ATMCI_IER 0x0044 /* Interrupt Enable */ -#define ATMCI_IDR 0x0048 /* Interrupt Disable */ -#define ATMCI_IMR 0x004c /* Interrupt Mask */ -# define ATMCI_CMDRDY ( 1 << 0) /* Command Ready */ -# define ATMCI_RXRDY ( 1 << 1) /* Receiver Ready */ -# define ATMCI_TXRDY ( 1 << 2) /* Transmitter Ready */ -# define ATMCI_BLKE ( 1 << 3) /* Data Block Ended */ -# define ATMCI_DTIP ( 1 << 4) /* Data Transfer In Progress */ -# define ATMCI_NOTBUSY ( 1 << 5) /* Data Not Busy */ -# define ATMCI_ENDRX ( 1 << 6) /* End of RX Buffer */ -# define ATMCI_ENDTX ( 1 << 7) /* End of TX Buffer */ -# define ATMCI_SDIOIRQA ( 1 << 8) /* SDIO IRQ in slot A */ -# define ATMCI_SDIOIRQB ( 1 << 9) /* SDIO IRQ in slot B */ -# define ATMCI_SDIOWAIT ( 1 << 12) /* SDIO Read Wait Operation Status */ -# define ATMCI_CSRCV ( 1 << 13) /* CE-ATA Completion Signal Received */ -# define ATMCI_RXBUFF ( 1 << 14) /* RX Buffer Full */ -# define ATMCI_TXBUFE ( 1 << 15) /* TX Buffer Empty */ -# define ATMCI_RINDE ( 1 << 16) /* Response Index Error */ -# define ATMCI_RDIRE ( 1 << 17) /* Response Direction Error */ -# define ATMCI_RCRCE ( 1 << 18) /* Response CRC Error */ -# define ATMCI_RENDE ( 1 << 19) /* Response End Bit Error */ -# define ATMCI_RTOE ( 1 << 20) /* Response Time-Out Error */ -# define ATMCI_DCRCE ( 1 << 21) /* Data CRC Error */ -# define ATMCI_DTOE ( 1 << 22) /* Data Time-Out Error */ -# define ATMCI_CSTOE ( 1 << 23) /* Completion Signal Time-out Error */ -# define ATMCI_BLKOVRE ( 1 << 24) /* DMA Block Overrun Error */ -# define ATMCI_DMADONE ( 1 << 25) /* DMA Transfer Done */ -# define ATMCI_FIFOEMPTY ( 1 << 26) /* FIFO Empty Flag */ -# define ATMCI_XFRDONE ( 1 << 27) /* Transfer Done Flag */ -# define ATMCI_ACKRCV ( 1 << 28) /* Boot Operation Acknowledge Received */ -# define ATMCI_ACKRCVE ( 1 << 29) /* Boot Operation Acknowledge Error */ -# define ATMCI_OVRE ( 1 << 30) /* RX Overrun Error */ -# define ATMCI_UNRE ( 1 << 31) /* TX Underrun Error */ -#define ATMCI_DMA 0x0050 /* DMA Configuration[2] */ -# define ATMCI_DMA_OFFSET(x) ((x) << 0) /* DMA Write Buffer Offset */ -# define ATMCI_DMA_CHKSIZE(x) ((x) << 4) /* DMA Channel Read and Write Chunk Size */ -# define ATMCI_DMAEN ( 1 << 8) /* DMA Hardware Handshaking Enable */ -#define ATMCI_CFG 0x0054 /* Configuration[2] */ -# define ATMCI_CFG_FIFOMODE_1DATA ( 1 << 0) /* MCI Internal FIFO control mode */ -# define ATMCI_CFG_FERRCTRL_COR ( 1 << 4) /* Flow Error flag reset control mode */ -# define ATMCI_CFG_HSMODE ( 1 << 8) /* High Speed Mode */ -# define ATMCI_CFG_LSYNC ( 1 << 12) /* Synchronize on the last block */ -#define ATMCI_WPMR 0x00e4 /* Write Protection Mode[2] */ -# define ATMCI_WP_EN ( 1 << 0) /* WP Enable */ -# define ATMCI_WP_KEY (0x4d4349 << 8) /* WP Key */ -#define ATMCI_WPSR 0x00e8 /* Write Protection Status[2] */ -# define ATMCI_GET_WP_VS(x) ((x) & 0x0f) -# define ATMCI_GET_WP_VSRC(x) (((x) >> 8) & 0xffff) -#define ATMCI_VERSION 0x00FC /* Version */ -#define ATMCI_FIFO_APERTURE 0x0200 /* FIFO Aperture[2] */ - -/* This is not including the FIFO Aperture on MCI2 */ -#define ATMCI_REGS_SIZE 0x100 - -/* Register access macros */ -#ifdef CONFIG_AVR32 -#define atmci_readl(port, reg) \ - __raw_readl((port)->regs + reg) -#define atmci_writel(port, reg, value) \ - __raw_writel((value), (port)->regs + reg) -#else -#define atmci_readl(port, reg) \ - readl_relaxed((port)->regs + reg) -#define atmci_writel(port, reg, value) \ - writel_relaxed((value), (port)->regs + reg) -#endif - -/* On AVR chips the Peripheral DMA Controller is not connected to MCI. */ -#ifdef CONFIG_AVR32 -# define ATMCI_PDC_CONNECTED 0 -#else -# define ATMCI_PDC_CONNECTED 1 -#endif - -/* - * Fix sconfig's burst size according to atmel MCI. We need to convert them as: - * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3. - * - * This can be done by finding most significant bit set. - */ -static inline unsigned int atmci_convert_chksize(unsigned int maxburst) -{ - if (maxburst > 1) - return fls(maxburst) - 2; - else - return 0; -} - -#endif /* __DRIVERS_MMC_ATMEL |