dect
/
linux-2.6
Archived
13
0
Fork 0

MMC highlights for 3.8:

Core:
  - Expose access to the eMMC RPMB ("Replay Protected Memory Block") area
    by extending the existing mmc_block ioctl.
  - Add SDIO powered-suspend DT properties to the core MMC DT binding.
  - Add no-1-8-v DT flag for boards where the SD controller reports that it
    supports 1.8V but the board itself has no way to switch to 1.8V.
  - More work on switching to 1.8V UHS support using a vqmmc regulator.
  - Fix up a case where the slot-gpio helper may fail to reset the host
    controller properly if a card was removed during a transfer.
  - Fix several cases where a broken device could cause an infinite loop
    while we wait for a register to update.
 
 Drivers:
  - at91-mci: Remove obsolete driver, atmel-mci handles these devices now.
  - sdhci-dove: Allow using GPIOs for card-detect notifications.
  - sdhci-esdhc: Fix for recovering from ADMA errors on broken silicon.
  - sdhci-s3c: Add pinctrl support.
  - wmt-sdmmc: New driver for WonderMedia SD/MMC controllers.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJQxpwoAAoJEHNBYZ7TNxYMir0P/in5xv6vVq+06hMb9JTA2+M0
 +eSgNAoSQt3Zn3dTxGtcaMbrnVvegMD2sRmnHncSKoi6iUgWh7RhuT7o8vp2zgJe
 KbuOF/OF5+RSnLwgCMcOCjauhBtHO7s+NPNbUH4DMN2/xQ7fpiY+QIsxrKWtImyO
 E4v62zRm/6aa1IfGDgYTAlX8Y1QfEQhH55OYrF9UzU1m7TKsSGxYTXwx+LeLQZQ0
 j6HO+FVlmu5jbZ4V69z3qNIdiklRGQBE7D+7cJqW6btv7x4oLmyygEoNA8M8ncxX
 g5BD5oEt9oxW5OW8hYcEJ/flDErgekZekH8n+fZoNVDVq8gMJxHOV73mnN+wxRnd
 lRGLhniVOzl4cU+ObcYTBzdUV+2yR3sRHSK8nwtb+HFATetM70gBlpoWni1+sGr5
 qvFhnpzNrj0xCwoQpLerwrvCwPpyko9uxZQwO51HqhugFwWlJuTqQsnCgj+Q4MDE
 CRUq4R6TCH7oMGeGin0qyD7jyigDnh7g4pPNQmuIYJSLsDwvinisz98MQ0XC8szc
 Z1H9YXKch2woLHLPFWzNyAIlJWHXakjk5vb9uSQmkUIto/y7q+LiGVCc5uvny3rU
 pJmda+U/8R8YmSWS7pUi6OmPRfcnPuAIllEwo3lBypVpdP/fcZ6aribrbGEo6DLb
 XLFIHnl3O9/sjfUcMl+L
 =oSX3
 -----END PGP SIGNATURE-----

Merge tag 'mmc-updates-for-3.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc

Pull MMC updates from Chris Ball:
 "MMC highlights for 3.8:

  Core:
   - Expose access to the eMMC RPMB ("Replay Protected Memory Block")
     area by extending the existing mmc_block ioctl.
   - Add SDIO powered-suspend DT properties to the core MMC DT binding.
   - Add no-1-8-v DT flag for boards where the SD controller reports
     that it supports 1.8V but the board itself has no way to switch to
     1.8V.
   - More work on switching to 1.8V UHS support using a vqmmc regulator.
   - Fix up a case where the slot-gpio helper may fail to reset the host
     controller properly if a card was removed during a transfer.
   - Fix several cases where a broken device could cause an infinite
     loop while we wait for a register to update.

  Drivers:
   - at91-mci: Remove obsolete driver, atmel-mci handles these devices
     now.
   - sdhci-dove: Allow using GPIOs for card-detect notifications.
   - sdhci-esdhc: Fix for recovering from ADMA errors on broken silicon.
   - sdhci-s3c: Add pinctrl support.
   - wmt-sdmmc: New driver for WonderMedia SD/MMC controllers."

* tag 'mmc-updates-for-3.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (65 commits)
  mmc: sdhci: implement the .card_event() method
  mmc: extend the slot-gpio card-detection to use host's .card_event() method
  mmc: add a card-event host operation
  mmc: sdhci-s3c: Fix compilation warning
  mmc: sdhci-pci: Enable SDHCI_CAN_DO_HISPD for Ricoh SDHCI controller
  mmc: sdhci-dove: allow GPIOs to be used for card detection on Dove
  mmc: sdhci-dove: use two-stage initialization for sdhci-pltfm
  mmc: sdhci-dove: use devm_clk_get()
  mmc: eSDHC: Recover from ADMA errors
  mmc: dw_mmc: remove duplicated buswidth code
  mmc: dw_mmc: relocate where dw_mci_setup_bus() is called from
  mmc: Limit MMC speed to 52MHz if not HS200
  mmc: dw_mmc: use devres functions in dw_mmc
  mmc: sh_mmcif: remove unneeded clock connection ID
  mmc: sh_mobile_sdhi: remove unneeded clock connection ID
  mmc: sh_mobile_sdhi: fix clock frequency printing
  mmc: Remove redundant null check before kfree in bus.c
  mmc: Remove redundant null check before kfree in sdio_bus.c
  mmc: sdhci-imx-esdhc: use more devm_* functions
  mmc: dt: add no-1-8-v device tree flag
  ...
This commit is contained in:
Linus Torvalds 2012-12-11 11:19:09 -08:00
commit 11b84c5857
52 changed files with 1781 additions and 1722 deletions

View File

@ -21,6 +21,12 @@ Optional properties:
- cd-inverted: when present, polarity on the cd gpio line is inverted
- wp-inverted: when present, polarity on the wp gpio line is inverted
- max-frequency: maximum operating clock frequency
- no-1-8-v: when present, denotes that 1.8v card voltage is not supported on
this system, even if the controller claims it is.
Optional SDIO properties:
- keep-power-in-suspend: Preserves card power during a suspend/resume cycle
- enable-sdio-wakeup: Enables wake up of host system on SDIO IRQ assertion
Example:
@ -33,4 +39,6 @@ sdhci@ab000000 {
cd-inverted;
wp-gpios = <&gpio 70 0>;
max-frequency = <50000000>;
keep-power-in-suspend;
enable-sdio-wakeup;
}

View File

@ -12,10 +12,6 @@ is used. The Samsung's SDHCI controller bindings extends this as listed below.
[A] The property "samsung,cd-pinmux-gpio" can be used as stated in the
"Optional Board Specific Properties" section below.
[B] If core card-detect bindings and "samsung,cd-pinmux-gpio" property
is not specified, it is assumed that there is no card detection
mechanism used.
Required SoC Specific Properties:
- compatible: should be one of the following
- "samsung,s3c6410-sdhci": For controllers compatible with s3c6410 sdhci
@ -24,14 +20,18 @@ Required SoC Specific Properties:
controller.
Required Board Specific Properties:
- gpios: Should specify the gpios used for clock, command and data lines. The
gpio specifier format depends on the gpio controller.
- Samsung GPIO variant (will be completely replaced by pinctrl):
- gpios: Should specify the gpios used for clock, command and data lines. The
gpio specifier format depends on the gpio controller.
- Pinctrl variant (preferred if available):
- pinctrl-0: Should specify pin control groups used for this controller.
- pinctrl-names: Should contain only one value - "default".
Optional Board Specific Properties:
- samsung,cd-pinmux-gpio: Specifies the card detect line that is routed
through a pinmux to the card-detect pin of the card slot. This property
should be used only if none of the mmc core card-detect properties are
used.
used. Only for Samsung GPIO variant.
Example:
sdhci@12530000 {
@ -40,12 +40,18 @@ Example:
interrupts = <0 75 0>;
bus-width = <4>;
cd-gpios = <&gpk2 2 2 3 3>;
/* Samsung GPIO variant */
gpios = <&gpk2 0 2 0 3>, /* clock line */
<&gpk2 1 2 0 3>, /* command line */
<&gpk2 3 2 3 3>, /* data line 0 */
<&gpk2 4 2 3 3>, /* data line 1 */
<&gpk2 5 2 3 3>, /* data line 2 */
<&gpk2 6 2 3 3>; /* data line 3 */
/* Pinctrl variant */
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4>;
pinctrl-names = "default";
};
Note: This example shows both SoC specific and board specific properties

View File

@ -19,6 +19,7 @@ ti,dual-volt: boolean, supports dual voltage cards
"supply-name" examples are "vmmc", "vmmc_aux" etc
ti,non-removable: non-removable slot (like eMMC)
ti,needs-special-reset: Requires a special softreset sequence
ti,needs-special-hs-handling: HSMMC IP needs special setting for handling High Speed
Example:
mmc1: mmc@0x4809c000 {

View File

@ -0,0 +1,23 @@
* Wondermedia WM8505/WM8650 SD/MMC Host Controller
This file documents differences between the core properties described
by mmc.txt and the properties used by the wmt-sdmmc driver.
Required properties:
- compatible: Should be "wm,wm8505-sdhc".
- interrupts: Two interrupts are required - regular irq and dma irq.
Optional properties:
- sdon-inverted: SD_ON bit is inverted on the controller
Examples:
sdhc@d800a000 {
compatible = "wm,wm8505-sdhc";
reg = <0xd800a000 0x1000>;
interrupts = <20 21>;
clocks = <&sdhc>;
bus-width = <4>;
sdon-inverted;
};

View File

@ -25,6 +25,8 @@ All attributes are read-only.
serial Product Serial Number (from CID Register)
erase_size Erase group size
preferred_erase_size Preferred erase size
raw_rpmb_size_mult RPMB partition size
rel_sectors Reliable write sector count
Note on Erase Size and Preferred Erase Size:
@ -65,6 +67,11 @@ Note on Erase Size and Preferred Erase Size:
"preferred_erase_size" is in bytes.
Note on raw_rpmb_size_mult:
"raw_rpmb_size_mult" is a mutliple of 128kB block.
RPMB size in byte is calculated by using the following equation:
RPMB partition size = 128kB x raw_rpmb_size_mult
SD/MMC/SDIO Clock Gating Attribute
==================================

View File

@ -1237,6 +1237,7 @@ F: drivers/video/wm8505fb*
F: drivers/video/wmt_ge_rops.*
F: drivers/tty/serial/vt8500_serial.c
F: drivers/rtc/rtc-vt8500-c
F: drivers/mmc/host/wmt-sdmmc.c
ARM/ZIPIT Z2 SUPPORT
M: Marek Vasut <marek.vasut@gmail.com>
@ -1368,14 +1369,6 @@ S: Maintained
F: drivers/atm/
F: include/linux/atm*
ATMEL AT91 MCI DRIVER
M: Ludovic Desroches <ludovic.desroches@atmel.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
W: http://www.atmel.com/products/AT91/
W: http://www.at91.com/
S: Maintained
F: drivers/mmc/host/at91_mci.c
ATMEL AT91 / AT32 MCI DRIVER
M: Ludovic Desroches <ludovic.desroches@atmel.com>
S: Maintained

View File

@ -70,16 +70,6 @@ struct at91_cf_data {
extern void __init at91_add_device_cf(struct at91_cf_data *data);
/* MMC / SD */
/* at91_mci platform config */
struct at91_mmc_data {
int det_pin; /* card detect IRQ */
unsigned slot_b:1; /* uses Slot B */
unsigned wire4:1; /* (SD) supports DAT0..DAT3 */
int wp_pin; /* (SD) writeprotect detect */
int vcc_pin; /* power switching (high == on) */
};
extern void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data);
/* atmel-mci platform config */
extern void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data);

View File

@ -126,6 +126,7 @@ struct omap_mmc_platform_data {
/* we can put the features above into this variable */
#define HSMMC_HAS_PBIAS (1 << 0)
#define HSMMC_HAS_UPDATED_RESET (1 << 1)
#define HSMMC_HAS_HSPE_SUPPORT (1 << 2)
unsigned features;
int switch_pin; /* gpio (card detect) */

View File

@ -57,6 +57,7 @@ MODULE_ALIAS("mmc:block");
#define INAND_CMD38_ARG_SECERASE 0x80
#define INAND_CMD38_ARG_SECTRIM1 0x81
#define INAND_CMD38_ARG_SECTRIM2 0x88
#define MMC_BLK_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
static DEFINE_MUTEX(block_mutex);
@ -126,6 +127,10 @@ enum mmc_blk_status {
module_param(perdev_minors, int, 0444);
MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device");
static inline int mmc_blk_part_switch(struct mmc_card *card,
struct mmc_blk_data *md);
static int get_card_status(struct mmc_card *card, u32 *status, int retries);
static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
{
struct mmc_blk_data *md;
@ -357,6 +362,38 @@ out:
return ERR_PTR(err);
}
static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status,
u32 retries_max)
{
int err;
u32 retry_count = 0;
if (!status || !retries_max)
return -EINVAL;
do {
err = get_card_status(card, status, 5);
if (err)
break;
if (!R1_STATUS(*status) &&
(R1_CURRENT_STATE(*status) != R1_STATE_PRG))
break; /* RPMB programming operation complete */
/*
* Rechedule to give the MMC device a chance to continue
* processing the previous command without being polled too
* frequently.
*/
usleep_range(1000, 5000);
} while (++retry_count < retries_max);
if (retry_count == retries_max)
err = -EPERM;
return err;
}
static int mmc_blk_ioctl_cmd(struct block_device *bdev,
struct mmc_ioc_cmd __user *ic_ptr)
{
@ -368,6 +405,8 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
struct mmc_request mrq = {NULL};
struct scatterlist sg;
int err;
int is_rpmb = false;
u32 status = 0;
/*
* The caller must have CAP_SYS_RAWIO, and must be calling this on the
@ -387,6 +426,9 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
goto cmd_err;
}
if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
is_rpmb = true;
card = md->queue.card;
if (IS_ERR(card)) {
err = PTR_ERR(card);
@ -437,12 +479,23 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
mmc_claim_host(card->host);
err = mmc_blk_part_switch(card, md);
if (err)
goto cmd_rel_host;
if (idata->ic.is_acmd) {
err = mmc_app_cmd(card->host, card);
if (err)
goto cmd_rel_host;
}
if (is_rpmb) {
err = mmc_set_blockcount(card, data.blocks,
idata->ic.write_flag & (1 << 31));
if (err)
goto cmd_rel_host;
}
mmc_wait_for_req(card->host, &mrq);
if (cmd.error) {
@ -478,6 +531,18 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
}
}
if (is_rpmb) {
/*
* Ensure RPMB command has completed by polling CMD13
* "Send Status".
*/
err = ioctl_rpmb_card_status_poll(card, &status, 5);
if (err)
dev_err(mmc_dev(card->host),
"%s: Card Status=0x%08X, error %d\n",
__func__, status, err);
}
cmd_rel_host:
mmc_release_host(card->host);
@ -1034,6 +1099,9 @@ static int mmc_blk_err_check(struct mmc_card *card,
*/
if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
u32 status;
unsigned long timeout;
timeout = jiffies + msecs_to_jiffies(MMC_BLK_TIMEOUT_MS);
do {
int err = get_card_status(card, &status, 5);
if (err) {
@ -1041,6 +1109,17 @@ static int mmc_blk_err_check(struct mmc_card *card,
req->rq_disk->disk_name, err);
return MMC_BLK_CMD_ERR;
}
/* Timeout if the device never becomes ready for data
* and never leaves the program state.
*/
if (time_after(jiffies, timeout)) {
pr_err("%s: Card stuck in programming state!"\
" %s %s\n", mmc_hostname(card->host),
req->rq_disk->disk_name, __func__);
return MMC_BLK_CMD_ERR;
}
/*
* Some cards mishandle the status bits,
* so make sure to check both the busy
@ -1504,6 +1583,8 @@ 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);
if (area_type & MMC_BLK_DATA_AREA_RPMB)
md->disk->flags |= GENHD_FL_NO_PART_SCAN;
/*
* As discussed on lkml, GENHD_FL_REMOVABLE should:

View File

@ -68,6 +68,16 @@ static int mmc_queue_thread(void *d)
if (req || mq->mqrq_prev->req) {
set_current_state(TASK_RUNNING);
mq->issue_fn(mq, req);
/*
* Current request becomes previous request
* and vice versa.
*/
mq->mqrq_prev->brq.mrq.data = NULL;
mq->mqrq_prev->req = NULL;
tmp = mq->mqrq_prev;
mq->mqrq_prev = mq->mqrq_cur;
mq->mqrq_cur = tmp;
} else {
if (kthread_should_stop()) {
set_current_state(TASK_RUNNING);
@ -77,13 +87,6 @@ static int mmc_queue_thread(void *d)
schedule();
down(&mq->thread_sem);
}
/* Current request becomes previous request and vice versa. */
mq->mqrq_prev->brq.mrq.data = NULL;
mq->mqrq_prev->req = NULL;
tmp = mq->mqrq_prev;
mq->mqrq_prev = mq->mqrq_cur;
mq->mqrq_cur = tmp;
} while (1);
up(&mq->thread_sem);

View File

@ -225,8 +225,7 @@ static void mmc_release_card(struct device *dev)
sdio_free_common_cis(card);
if (card->info)
kfree(card->info);
kfree(card->info);
kfree(card);
}

View File

@ -42,6 +42,9 @@
#include "sd_ops.h"
#include "sdio_ops.h"
/* If the device is not responding */
#define MMC_CORE_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
/*
* Background operations can take a long time, depending on the housekeeping
* operations the card has to perform.
@ -1631,6 +1634,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
{
struct mmc_command cmd = {0};
unsigned int qty = 0;
unsigned long timeout;
int err;
/*
@ -1708,6 +1712,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
if (mmc_host_is_spi(card->host))
goto out;
timeout = jiffies + msecs_to_jiffies(MMC_CORE_TIMEOUT_MS);
do {
memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SEND_STATUS;
@ -1721,8 +1726,19 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
err = -EIO;
goto out;
}
/* Timeout if the device never becomes ready for data and
* never leaves the program state.
*/
if (time_after(jiffies, timeout)) {
pr_err("%s: Card stuck in programming state! %s\n",
mmc_hostname(card->host), __func__);
err = -EIO;
goto out;
}
} while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG);
(R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG));
out:
return err;
}
@ -1942,6 +1958,20 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
}
EXPORT_SYMBOL(mmc_set_blocklen);
int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
bool is_rel_write)
{
struct mmc_command cmd = {0};
cmd.opcode = MMC_SET_BLOCK_COUNT;
cmd.arg = blockcount & 0x0000FFFF;
if (is_rel_write)
cmd.arg |= 1 << 31;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
return mmc_wait_for_cmd(card->host, &cmd, 5);
}
EXPORT_SYMBOL(mmc_set_blockcount);
static void mmc_hw_reset_for_init(struct mmc_host *host)
{
if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)

View File

@ -144,6 +144,22 @@ static int mmc_ios_show(struct seq_file *s, void *data)
}
seq_printf(s, "timing spec:\t%u (%s)\n", ios->timing, str);
switch (ios->signal_voltage) {
case MMC_SIGNAL_VOLTAGE_330:
str = "3.30 V";
break;
case MMC_SIGNAL_VOLTAGE_180:
str = "1.80 V";
break;
case MMC_SIGNAL_VOLTAGE_120:
str = "1.20 V";
break;
default:
str = "invalid";
break;
}
seq_printf(s, "signal voltage:\t%u (%s)\n", ios->chip_select, str);
return 0;
}

View File

@ -239,7 +239,7 @@ static void mmc_select_card_type(struct mmc_card *card)
{
struct mmc_host *host = card->host;
u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK;
unsigned int caps = host->caps, caps2 = host->caps2;
u32 caps = host->caps, caps2 = host->caps2;
unsigned int hs_max_dtr = 0;
if (card_type & EXT_CSD_CARD_TYPE_26)
@ -491,6 +491,17 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION];
/*
* RPMB regions are defined in multiples of 128K.
*/
card->ext_csd.raw_rpmb_size_mult = ext_csd[EXT_CSD_RPMB_MULT];
if (ext_csd[EXT_CSD_RPMB_MULT]) {
mmc_part_add(card, ext_csd[EXT_CSD_RPMB_MULT] << 17,
EXT_CSD_PART_CONFIG_ACC_RPMB,
"rpmb", 0, false,
MMC_BLK_DATA_AREA_RPMB);
}
}
card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT];
@ -615,6 +626,8 @@ MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
card->ext_csd.enhanced_area_offset);
MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult);
MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);
static struct attribute *mmc_std_attrs[] = {
&dev_attr_cid.attr,
@ -630,6 +643,8 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_serial.attr,
&dev_attr_enhanced_area_offset.attr,
&dev_attr_enhanced_area_size.attr,
&dev_attr_raw_rpmb_size_mult.attr,
&dev_attr_rel_sectors.attr,
NULL,
};
@ -1051,6 +1066,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
if (max_dtr > card->ext_csd.hs_max_dtr)
max_dtr = card->ext_csd.hs_max_dtr;
if (mmc_card_highspeed(card) && (max_dtr > 52000000))
max_dtr = 52000000;
} else if (max_dtr > card->csd.max_dtr) {
max_dtr = card->csd.max_dtr;
}

View File

@ -21,6 +21,8 @@
#include "core.h"
#include "mmc_ops.h"
#define MMC_OPS_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
{
int err;
@ -409,6 +411,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
{
int err;
struct mmc_command cmd = {0};
unsigned long timeout;
u32 status;
BUG_ON(!card);
@ -437,6 +440,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
return 0;
/* Must check status to be sure of no errors */
timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);
do {
err = mmc_send_status(card, &status);
if (err)
@ -445,6 +449,13 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
break;
if (mmc_host_is_spi(card->host))
break;
/* Timeout if the device never leaves the program state. */
if (time_after(jiffies, timeout)) {
pr_err("%s: Card stuck in programming state! %s\n",
mmc_hostname(card->host), __func__);
return -ETIMEDOUT;
}
} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
if (mmc_host_is_spi(card->host)) {

View File

@ -193,7 +193,21 @@ static int sdio_bus_remove(struct device *dev)
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int pm_no_operation(struct device *dev)
{
/*
* Prevent the PM core from calling SDIO device drivers' suspend
* callback routines, which it is not supposed to do, by using this
* empty function as the bus type suspend callaback for SDIO.
*/
return 0;
}
#endif
static const struct dev_pm_ops sdio_bus_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_no_operation, pm_no_operation)
SET_RUNTIME_PM_OPS(
pm_generic_runtime_suspend,
pm_generic_runtime_resume,
@ -258,8 +272,7 @@ static void sdio_release_func(struct device *dev)
sdio_free_func_cis(func);
if (func->info)
kfree(func->info);
kfree(func->info);
kfree(func);
}

View File

@ -188,8 +188,7 @@ EXPORT_SYMBOL_GPL(sdio_set_block_size);
*/
static inline unsigned int sdio_max_byte_size(struct sdio_func *func)
{
unsigned mval = min(func->card->host->max_seg_size,
func->card->host->max_blk_size);
unsigned mval = func->card->host->max_blk_size;
if (mmc_blksz_for_byte_mode(func->card))
mval = min(mval, func->cur_blksize);
@ -311,11 +310,8 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
/* Do the bulk of the transfer using block mode (if supported). */
if (func->card->cccr.multi_block && (size > sdio_max_byte_size(func))) {
/* Blocks per command is limited by host count, host transfer
* size (we only use a single sg entry) and the maximum for
* IO_RW_EXTENDED of 511 blocks. */
max_blocks = min(func->card->host->max_blk_count,
func->card->host->max_seg_size / func->cur_blksize);
max_blocks = min(max_blocks, 511u);
* size and the maximum for IO_RW_EXTENDED of 511 blocks. */
max_blocks = min(func->card->host->max_blk_count, 511u);
while (remainder >= func->cur_blksize) {
unsigned blocks;

View File

@ -124,7 +124,10 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
struct mmc_request mrq = {NULL};
struct mmc_command cmd = {0};
struct mmc_data data = {0};
struct scatterlist sg;
struct scatterlist sg, *sg_ptr;
struct sg_table sgtable;
unsigned int nents, left_size, i;
unsigned int seg_size = card->host->max_seg_size;
BUG_ON(!card);
BUG_ON(fn > 7);
@ -152,15 +155,36 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
/* Code in host drivers/fwk assumes that "blocks" always is >=1 */
data.blocks = blocks ? blocks : 1;
data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
data.sg = &sg;
data.sg_len = 1;
sg_init_one(&sg, buf, data.blksz * data.blocks);
left_size = data.blksz * data.blocks;
nents = (left_size - 1) / seg_size + 1;
if (nents > 1) {
if (sg_alloc_table(&sgtable, nents, GFP_KERNEL))
return -ENOMEM;
data.sg = sgtable.sgl;
data.sg_len = nents;
for_each_sg(data.sg, sg_ptr, data.sg_len, i) {
sg_set_page(sg_ptr, virt_to_page(buf + (i * seg_size)),
min(seg_size, left_size),
offset_in_page(buf + (i * seg_size)));
left_size = left_size - seg_size;
}
} else {
data.sg = &sg;
data.sg_len = 1;
sg_init_one(&sg, buf, left_size);
}
mmc_set_data_timeout(&data, card);
mmc_wait_for_req(card->host, &mrq);
if (nents > 1)
sg_free_table(&sgtable);
if (cmd.error)
return cmd.error;
if (data.error)

View File

@ -27,7 +27,13 @@ struct mmc_gpio {
static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
{
/* Schedule a card detection after a debounce timeout */
mmc_detect_change(dev_id, msecs_to_jiffies(100));
struct mmc_host *host = dev_id;
if (host->ops->card_event)
host->ops->card_event(host);
mmc_detect_change(host, msecs_to_jiffies(200));
return IRQ_HANDLED;
}

View File

@ -270,26 +270,8 @@ config MMC_AU1X
If unsure, say N.
choice
prompt "Atmel SD/MMC Driver"
depends on AVR32 || ARCH_AT91
default MMC_ATMELMCI if AVR32
help
Choose which driver to use for the Atmel MCI Silicon
config MMC_AT91
tristate "AT91 SD/MMC Card Interface support (DEPRECATED)"
depends on ARCH_AT91
help
This selects the AT91 MCI controller. This driver will
be removed soon (for more information have a look to
Documentation/feature-removal-schedule.txt). Please use
MMC_ATMEL_MCI.
If unsure, say N.
config MMC_ATMELMCI
tristate "Atmel Multimedia Card Interface support"
tristate "Atmel SD/MMC Driver (Multimedia Card Interface)"
depends on AVR32 || ARCH_AT91
help
This selects the Atmel Multimedia Card Interface driver. If
@ -298,8 +280,6 @@ config MMC_ATMELMCI
If unsure, say N.
endchoice
config MMC_ATMELMCI_DMA
bool "Atmel MCI DMA support"
depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE
@ -621,3 +601,14 @@ config MMC_USHC
Note: These controllers only support SDIO cards and do not
support MMC or SD memory cards.
config MMC_WMT
tristate "Wondermedia SD/MMC Host Controller support"
depends on ARCH_VT8500
default y
help
This selects support for the SD/MMC Host Controller on
Wondermedia WM8505/WM8650 based SoCs.
To compile this driver as a module, choose M here: the
module will be called wmt-sdmmc.

View File

@ -17,7 +17,6 @@ obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_OMAP) += omap.o
obj-$(CONFIG_MMC_OMAP_HS) += omap_hsmmc.o
obj-$(CONFIG_MMC_AT91) += at91_mci.o
obj-$(CONFIG_MMC_ATMELMCI) += atmel-mci.o
obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
obj-$(CONFIG_MMC_MSM) += msm_sdcc.o
@ -45,6 +44,7 @@ obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
obj-$(CONFIG_MMC_VUB300) += vub300.o
obj-$(CONFIG_MMC_USHC) += ushc.o
obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o
obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o
obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o

File diff suppressed because it is too large Load Diff

View File

@ -1,115 +0,0 @@
/*
* drivers/mmc/host/at91_mci.h
*
* Copyright (C) 2005 Ivan Kokshaysky
* Copyright (C) SAN People
*
* MultiMedia Card Interface (MCI) registers.
* Based on AT91RM9200 datasheet revision F.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef AT91_MCI_H
#define AT91_MCI_H
#define AT91_MCI_CR 0x00 /* Control Register */
#define AT91_MCI_MCIEN (1 << 0) /* Multi-Media Interface Enable */
#define AT91_MCI_MCIDIS (1 << 1) /* Multi-Media Interface Disable */
#define AT91_MCI_PWSEN (1 << 2) /* Power Save Mode Enable */
#define AT91_MCI_PWSDIS (1 << 3) /* Power Save Mode Disable */
#define AT91_MCI_SWRST (1 << 7) /* Software Reset */
#define AT91_MCI_MR 0x04 /* Mode Register */
#define AT91_MCI_CLKDIV (0xff << 0) /* Clock Divider */
#define AT91_MCI_PWSDIV (7 << 8) /* Power Saving Divider */
#define AT91_MCI_RDPROOF (1 << 11) /* Read Proof Enable [SAM926[03] only] */
#define AT91_MCI_WRPROOF (1 << 12) /* Write Proof Enable [SAM926[03] only] */
#define AT91_MCI_PDCFBYTE (1 << 13) /* PDC Force Byte Transfer [SAM926[03] only] */
#define AT91_MCI_PDCPADV (1 << 14) /* PDC Padding Value */
#define AT91_MCI_PDCMODE (1 << 15) /* PDC-orientated Mode */
#define AT91_MCI_BLKLEN (0xfff << 18) /* Data Block Length */
#define AT91_MCI_DTOR 0x08 /* Data Timeout Register */
#define AT91_MCI_DTOCYC (0xf << 0) /* Data Timeout Cycle Number */
#define AT91_MCI_DTOMUL (7 << 4) /* Data Timeout Multiplier */
#define AT91_MCI_DTOMUL_1 (0 << 4)
#define AT91_MCI_DTOMUL_16 (1 << 4)
#define AT91_MCI_DTOMUL_128 (2 << 4)
#define AT91_MCI_DTOMUL_256 (3 << 4)
#define AT91_MCI_DTOMUL_1K (4 << 4)
#define AT91_MCI_DTOMUL_4K (5 << 4)
#define AT91_MCI_DTOMUL_64K (6 << 4)
#define AT91_MCI_DTOMUL_1M (7 << 4)
#define AT91_MCI_SDCR 0x0c /* SD Card Register */
#define AT91_MCI_SDCSEL (3 << 0) /* SD Card Selector */
#define AT91_MCI_SDCBUS (1 << 7) /* 1-bit or 4-bit bus */
#define AT91_MCI_ARGR 0x10 /* Argument Register */
#define AT91_MCI_CMDR 0x14 /* Command Register */
#define AT91_MCI_CMDNB (0x3f << 0) /* Command Number */
#define AT91_MCI_RSPTYP (3 << 6) /* Response Type */
#define AT91_MCI_RSPTYP_NONE (0 << 6)
#define AT91_MCI_RSPTYP_48 (1 << 6)
#define AT91_MCI_RSPTYP_136 (2 << 6)
#define AT91_MCI_SPCMD (7 << 8) /* Special Command */
#define AT91_MCI_SPCMD_NONE (0 << 8)
#define AT91_MCI_SPCMD_INIT (1 << 8)
#define AT91_MCI_SPCMD_SYNC (2 << 8)
#define AT91_MCI_SPCMD_ICMD (4 << 8)
#define AT91_MCI_SPCMD_IRESP (5 << 8)
#define AT91_MCI_OPDCMD (1 << 11) /* Open Drain Command */
#define AT91_MCI_MAXLAT (1 << 12) /* Max Latency for Command to Response */
#define AT91_MCI_TRCMD (3 << 16) /* Transfer Command */
#define AT91_MCI_TRCMD_NONE (0 << 16)
#define AT91_MCI_TRCMD_START (1 << 16)
#define AT91_MCI_TRCMD_STOP (2 << 16)
#define AT91_MCI_TRDIR (1 << 18) /* Transfer Direction */
#define AT91_MCI_TRTYP (3 << 19) /* Transfer Type */
#define AT91_MCI_TRTYP_BLOCK (0 << 19)
#define AT91_MCI_TRTYP_MULTIPLE (1 << 19)
#define AT91_MCI_TRTYP_STREAM (2 << 19)
#define AT91_MCI_TRTYP_SDIO_BYTE (4 << 19)
#define AT91_MCI_TRTYP_SDIO_BLOCK (5 << 19)
#define AT91_MCI_BLKR 0x18 /* Block Register */
#define AT91_MCI_BLKR_BCNT(n) ((0xffff & (n)) << 0) /* Block count */
#define AT91_MCI_BLKR_BLKLEN(n) ((0xffff & (n)) << 16) /* Block length */
#define AT91_MCI_RSPR(n) (0x20 + ((n) * 4)) /* Response Registers 0-3 */
#define AT91_MCR_RDR 0x30 /* Receive Data Register */
#define AT91_MCR_TDR 0x34 /* Transmit Data Register */
#define AT91_MCI_SR 0x40 /* Status Register */
#define AT91_MCI_CMDRDY (1 << 0) /* Command Ready */
#define AT91_MCI_RXRDY (1 << 1) /* Receiver Ready */
#define AT91_MCI_TXRDY (1 << 2) /* Transmit Ready */
#define AT91_MCI_BLKE (1 << 3) /* Data Block Ended */
#define AT91_MCI_DTIP (1 << 4) /* Data Transfer in Progress */
#define AT91_MCI_NOTBUSY (1 << 5) /* Data Not Busy */
#define AT91_MCI_ENDRX (1 << 6) /* End of RX Buffer */
#define AT91_MCI_ENDTX (1 << 7) /* End fo TX Buffer */
#define AT91_MCI_SDIOIRQA (1 << 8) /* SDIO Interrupt for Slot A */
#define AT91_MCI_SDIOIRQB (1 << 9) /* SDIO Interrupt for Slot B */
#define AT91_MCI_RXBUFF (1 << 14) /* RX Buffer Full */
#define AT91_MCI_TXBUFE (1 << 15) /* TX Buffer Empty */
#define AT91_MCI_RINDE (1 << 16) /* Response Index Error */
#define AT91_MCI_RDIRE (1 << 17) /* Response Direction Error */
#define AT91_MCI_RCRCE (1 << 18) /* Response CRC Error */
#define AT91_MCI_RENDE (1 << 19) /* Response End Bit Error */
#define AT91_MCI_RTOE (1 << 20) /* Response Time-out Error */
#define AT91_MCI_DCRCE (1 << 21) /* Data CRC Error */
#define AT91_MCI_DTOE (1 << 22) /* Data Time-out Error */
#define AT91_MCI_OVRE (1 << 30) /* Overrun */
#define AT91_MCI_UNRE (1 << 31) /* Underrun */
#define AT91_MCI_IER 0x44 /* Interrupt Enable Register */
#define AT91_MCI_IDR 0x48 /* Interrupt Disable Register */
#define AT91_MCI_IMR 0x4c /* Interrupt Mask Register */
#endif

View File

@ -134,7 +134,7 @@ static struct pci_driver dw_mci_pci_driver = {
.name = "dw_mmc_pci",
.id_table = dw_mci_pci_id,
.probe = dw_mci_pci_probe,
.remove = dw_mci_pci_remove,
.remove = __devexit_p(dw_mci_pci_remove),
.driver = {
.pm = &dw_mci_pci_pmops
},

View File

@ -119,7 +119,8 @@ static const struct of_device_id dw_mci_pltfm_match[] = {
MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
static struct platform_driver dw_mci_pltfm_driver = {
.remove = __exit_p(dw_mci_pltfm_remove),
.probe = dw_mci_pltfm_probe,
.remove = __devexit_p(dw_mci_pltfm_remove),
.driver = {
.name = "dw_mmc",
.of_match_table = of_match_ptr(dw_mci_pltfm_match),
@ -127,18 +128,7 @@ static struct platform_driver dw_mci_pltfm_driver = {
},
};
static int __init dw_mci_init(void)
{
return platform_driver_probe(&dw_mci_pltfm_driver, dw_mci_pltfm_probe);
}
static void __exit dw_mci_exit(void)
{
platform_driver_unregister(&dw_mci_pltfm_driver);
}
module_init(dw_mci_init);
module_exit(dw_mci_exit);
module_platform_driver(dw_mci_pltfm_driver);
MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
MODULE_AUTHOR("NXP Semiconductor VietNam");

View File

@ -232,7 +232,7 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
{
struct mmc_data *data;
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci_drv_data *drv_data = slot->host->drv_data;
const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
u32 cmdr;
cmd->error = -EINPROGRESS;
@ -617,13 +617,13 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
cmd, arg, cmd_status);
}
static void dw_mci_setup_bus(struct dw_mci_slot *slot)
static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
{
struct dw_mci *host = slot->host;
u32 div;
u32 clk_en_a;
if (slot->clock != host->current_speed) {
if (slot->clock != host->current_speed || force_clkinit) {
div = host->bus_hz / slot->clock;
if (host->bus_hz % slot->clock && host->bus_hz > slot->clock)
/*
@ -683,9 +683,6 @@ static void __dw_mci_start_request(struct dw_mci *host,
if (host->pdata->select_slot)
host->pdata->select_slot(slot->id);
/* Slot specific timing and width adjustment */
dw_mci_setup_bus(slot);
host->cur_slot = slot;
host->mrq = mrq;
@ -773,22 +770,19 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci_drv_data *drv_data = slot->host->drv_data;
const struct dw_mci_drv_data *drv_data = slot->host->drv_data;
u32 regs;
/* set default 1 bit mode */
slot->ctype = SDMMC_CTYPE_1BIT;
switch (ios->bus_width) {
case MMC_BUS_WIDTH_1:
slot->ctype = SDMMC_CTYPE_1BIT;
break;
case MMC_BUS_WIDTH_4:
slot->ctype = SDMMC_CTYPE_4BIT;
break;
case MMC_BUS_WIDTH_8:
slot->ctype = SDMMC_CTYPE_8BIT;
break;
default:
/* set default 1 bit mode */
slot->ctype = SDMMC_CTYPE_1BIT;
}
regs = mci_readl(slot->host, UHS_REG);
@ -812,6 +806,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (drv_data && drv_data->set_ios)
drv_data->set_ios(slot->host, ios);
/* Slot specific timing and width adjustment */
dw_mci_setup_bus(slot, false);
switch (ios->power_mode) {
case MMC_POWER_UP:
set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
@ -1817,7 +1814,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
{
struct mmc_host *mmc;
struct dw_mci_slot *slot;
struct dw_mci_drv_data *drv_data = host->drv_data;
const struct dw_mci_drv_data *drv_data = host->drv_data;
int ctrl_id, ret;
u8 bus_width;
@ -1850,6 +1847,9 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
if (host->pdata->caps)
mmc->caps = host->pdata->caps;
if (host->pdata->pm_caps)
mmc->pm_caps = host->pdata->pm_caps;
if (host->dev->of_node) {
ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
if (ctrl_id < 0)
@ -1911,7 +1911,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
#endif /* CONFIG_MMC_DW_IDMAC */
}
host->vmmc = regulator_get(mmc_dev(mmc), "vmmc");
host->vmmc = devm_regulator_get(mmc_dev(mmc), "vmmc");
if (IS_ERR(host->vmmc)) {
pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
host->vmmc = NULL;
@ -1960,7 +1960,7 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
static void dw_mci_init_dma(struct dw_mci *host)
{
/* Alloc memory for sg translation */
host->sg_cpu = dma_alloc_coherent(host->dev, PAGE_SIZE,
host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
&host->sg_dma, GFP_KERNEL);
if (!host->sg_cpu) {
dev_err(host->dev, "%s: could not alloc DMA memory\n",
@ -2038,7 +2038,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
struct dw_mci_board *pdata;
struct device *dev = host->dev;
struct device_node *np = dev->of_node;
struct dw_mci_drv_data *drv_data = host->drv_data;
const struct dw_mci_drv_data *drv_data = host->drv_data;
int idx, ret;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
@ -2072,6 +2072,12 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
return ERR_PTR(ret);
}
if (of_find_property(np, "keep-power-in-suspend", NULL))
pdata->pm_caps |= MMC_PM_KEEP_POWER;
if (of_find_property(np, "enable-sdio-wakeup", NULL))
pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
return pdata;
}
@ -2084,7 +2090,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
int dw_mci_probe(struct dw_mci *host)
{
struct dw_mci_drv_data *drv_data = host->drv_data;
const struct dw_mci_drv_data *drv_data = host->drv_data;
int width, i, ret = 0;
u32 fifo_size;
int init_slots = 0;
@ -2103,26 +2109,24 @@ int dw_mci_probe(struct dw_mci *host)
return -ENODEV;
}
host->biu_clk = clk_get(host->dev, "biu");
host->biu_clk = devm_clk_get(host->dev, "biu");
if (IS_ERR(host->biu_clk)) {
dev_dbg(host->dev, "biu clock not available\n");
} else {
ret = clk_prepare_enable(host->biu_clk);
if (ret) {
dev_err(host->dev, "failed to enable biu clock\n");
clk_put(host->biu_clk);
return ret;
}
}
host->ciu_clk = clk_get(host->dev, "ciu");
host->ciu_clk = devm_clk_get(host->dev, "ciu");
if (IS_ERR(host->ciu_clk)) {
dev_dbg(host->dev, "ciu clock not available\n");
} else {
ret = clk_prepare_enable(host->ciu_clk);
if (ret) {
dev_err(host->dev, "failed to enable ciu clock\n");
clk_put(host->ciu_clk);
goto err_clk_biu;
}
}
@ -2224,7 +2228,8 @@ int dw_mci_probe(struct dw_mci *host)
if (!host->card_workqueue)
goto err_dmaunmap;
INIT_WORK(&host->card_work, dw_mci_work_routine_card);
ret = request_irq(host->irq, dw_mci_interrupt, host->irq_flags, "dw-mci", host);
ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
host->irq_flags, "dw-mci", host);
if (ret)
goto err_workqueue;
@ -2262,7 +2267,7 @@ int dw_mci_probe(struct dw_mci *host)
} else {
dev_dbg(host->dev, "attempted to initialize %d slots, "
"but failed on all\n", host->num_slots);
goto err_init_slot;
goto err_workqueue;
}
/*
@ -2282,33 +2287,24 @@ int dw_mci_probe(struct dw_mci *host)
return 0;
err_init_slot:
free_irq(host->irq, host);
err_workqueue:
destroy_workqueue(host->card_workqueue);
err_dmaunmap:
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
dma_free_coherent(host->dev, PAGE_SIZE,
host->sg_cpu, host->sg_dma);
if (host->vmmc) {
if (host->vmmc)
regulator_disable(host->vmmc);
regulator_put(host->vmmc);
}
err_clk_ciu:
if (!IS_ERR(host->ciu_clk)) {
if (!IS_ERR(host->ciu_clk))
clk_disable_unprepare(host->ciu_clk);
clk_put(host->ciu_clk);
}
err_clk_biu:
if (!IS_ERR(host->biu_clk)) {
if (!IS_ERR(host->biu_clk))
clk_disable_unprepare(host->biu_clk);
clk_put(host->biu_clk);
}
return ret;
}
EXPORT_SYMBOL(dw_mci_probe);
@ -2330,24 +2326,19 @@ void dw_mci_remove(struct dw_mci *host)
mci_writel(host, CLKENA, 0);
mci_writel(host, CLKSRC, 0);
free_irq(host->irq, host);
destroy_workqueue(host->card_workqueue);
dma_free_coherent(host->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
if (host->vmmc) {
if (host->vmmc)
regulator_disable(host->vmmc);
regulator_put(host->vmmc);
}
if (!IS_ERR(host->ciu_clk))
clk_disable_unprepare(host->ciu_clk);
if (!IS_ERR(host->biu_clk))
clk_disable_unprepare(host->biu_clk);
clk_put(host->ciu_clk);
clk_put(host->biu_clk);
}
EXPORT_SYMBOL(dw_mci_remove);
@ -2411,6 +2402,11 @@ int dw_mci_resume(struct dw_mci *host)
struct dw_mci_slot *slot = host->slot[i];
if (!slot)
continue;
if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) {
dw_mci_set_ios(slot->mmc, &slot->mmc->ios);
dw_mci_setup_bus(slot, true);
}
ret = mmc_resume_host(host->slot[i]->mmc);
if (ret < 0)
return ret;

View File

@ -240,7 +240,7 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
return 0;
for_each_sg(data->sg, sg, data->sg_len, i) {
if (sg->offset & 3 || sg->length & 3) {
if (sg->offset & 3 || sg->length & 3 || sg->length < 512) {
host->do_dma = 0;
return 0;
}

View File

@ -43,7 +43,6 @@
#include <linux/module.h>
#include <linux/pinctrl/consumer.h>
#include <linux/stmp_device.h>
#include <linux/mmc/mxs-mmc.h>
#include <linux/spi/mxs-spi.h>
#define DRIVER_NAME "mxs-mmc"
@ -593,13 +592,13 @@ static int mxs_mmc_probe(struct platform_device *pdev)
struct mxs_mmc_host *host;
struct mmc_host *mmc;
struct resource *iores, *dmares;
struct mxs_mmc_platform_data *pdata;
struct pinctrl *pinctrl;
int ret = 0, irq_err, irq_dma;
dma_cap_mask_t mask;
struct regulator *reg_vmmc;
enum of_gpio_flags flags;
struct mxs_ssp *ssp;
u32 bus_width = 0;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@ -682,25 +681,15 @@ static int mxs_mmc_probe(struct platform_device *pdev)
mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL;
pdata = mmc_dev(host->mmc)->platform_data;
if (!pdata) {
u32 bus_width = 0;
of_property_read_u32(np, "bus-width", &bus_width);
if (bus_width == 4)
mmc->caps |= MMC_CAP_4_BIT_DATA;
else if (bus_width == 8)
mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0,
&flags);
if (flags & OF_GPIO_ACTIVE_LOW)
host->wp_inverted = 1;
} else {
if (pdata->flags & SLOTF_8_BIT_CAPABLE)
mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
if (pdata->flags & SLOTF_4_BIT_CAPABLE)
mmc->caps |= MMC_CAP_4_BIT_DATA;
host->wp_gpio = pdata->wp_gpio;
}
of_property_read_u32(np, "bus-width", &bus_width);
if (bus_width == 4)
mmc->caps |= MMC_CAP_4_BIT_DATA;
else if (bus_width == 8)
mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags);
if (flags & OF_GPIO_ACTIVE_LOW)
host->wp_inverted = 1;
mmc->f_min = 400000;
mmc->f_max = 288000000;

View File

@ -37,6 +37,7 @@
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
#include <mach/hardware.h>
#include <plat/mmc.h>
@ -62,6 +63,7 @@
#define VS18 (1 << 26)
#define VS30 (1 << 25)
#define HSS (1 << 21)
#define SDVS18 (0x5 << 9)
#define SDVS30 (0x6 << 9)
#define SDVS33 (0x7 << 9)
@ -78,28 +80,17 @@
#define CLKD_SHIFT 6
#define DTO_MASK 0x000F0000
#define DTO_SHIFT 16
#define INT_EN_MASK 0x307F0033
#define BWR_ENABLE (1 << 4)
#define BRR_ENABLE (1 << 5)
#define DTO_ENABLE (1 << 20)
#define INIT_STREAM (1 << 1)
#define DP_SELECT (1 << 21)
#define DDIR (1 << 4)
#define DMA_EN 0x1
#define DMAE 0x1
#define MSBS (1 << 5)
#define BCE (1 << 1)
#define FOUR_BIT (1 << 1)
#define HSPE (1 << 2)
#define DDR (1 << 19)
#define DW8 (1 << 5)
#define CC 0x1
#define TC 0x02
#define OD 0x1
#define ERR (1 << 15)
#define CMD_TIMEOUT (1 << 16)
#define DATA_TIMEOUT (1 << 20)
#define CMD_CRC (1 << 17)
#define DATA_CRC (1 << 21)
#define CARD_ERR (1 << 28)
#define STAT_CLEAR 0xFFFFFFFF
#define INIT_STREAM_CMD 0x00000000
#define DUAL_VOLT_OCR_BIT 7
@ -108,6 +99,26 @@
#define SOFTRESET (1 << 1)
#define RESETDONE (1 << 0)
/* Interrupt masks for IE and ISE register */
#define CC_EN (1 << 0)
#define TC_EN (1 << 1)
#define BWR_EN (1 << 4)
#define BRR_EN (1 << 5)
#define ERR_EN (1 << 15)
#define CTO_EN (1 << 16)
#define CCRC_EN (1 << 17)
#define CEB_EN (1 << 18)
#define CIE_EN (1 << 19)
#define DTO_EN (1 << 20)
#define DCRC_EN (1 << 21)
#define DEB_EN (1 << 22)
#define CERR_EN (1 << 28)
#define BADA_EN (1 << 29)
#define INT_EN_MASK (BADA_EN | CERR_EN | DEB_EN | DCRC_EN |\
DTO_EN | CIE_EN | CEB_EN | CCRC_EN | CTO_EN | \
BRR_EN | BWR_EN | TC_EN | CC_EN)
#define MMC_AUTOSUSPEND_DELAY 100
#define MMC_TIMEOUT_MS 20
#define OMAP_MMC_MIN_CLOCK 400000
@ -302,7 +313,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
reg = regulator_get(host->dev, "vmmc");
if (IS_ERR(reg)) {
dev_dbg(host->dev, "vmmc regulator missing\n");
dev_err(host->dev, "vmmc regulator missing\n");
return PTR_ERR(reg);
} else {
mmc_slot(host).set_power = omap_hsmmc_set_power;
@ -455,13 +466,13 @@ static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
unsigned int irq_mask;
if (host->use_dma)
irq_mask = INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE);
irq_mask = INT_EN_MASK & ~(BRR_EN | BWR_EN);
else
irq_mask = INT_EN_MASK;
/* Disable timeout for erases */
if (cmd->opcode == MMC_ERASE)
irq_mask &= ~DTO_ENABLE;
irq_mask &= ~DTO_EN;
OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
@ -494,6 +505,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
struct mmc_ios *ios = &host->mmc->ios;
unsigned long regval;
unsigned long timeout;
unsigned long clkdiv;
dev_vdbg(mmc_dev(host->mmc), "Set clock to %uHz\n", ios->clock);
@ -501,7 +513,8 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
regval = OMAP_HSMMC_READ(host->base, SYSCTL);
regval = regval & ~(CLKD_MASK | DTO_MASK);
regval = regval | (calc_divisor(host, ios) << 6) | (DTO << 16);
clkdiv = calc_divisor(host, ios);
regval = regval | (clkdiv << 6) | (DTO << 16);
OMAP_HSMMC_WRITE(host->base, SYSCTL, regval);
OMAP_HSMMC_WRITE(host->base, SYSCTL,
OMAP_HSMMC_READ(host->base, SYSCTL) | ICE);
@ -512,6 +525,27 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
&& time_before(jiffies, timeout))
cpu_relax();
/*
* Enable High-Speed Support
* Pre-Requisites
* - Controller should support High-Speed-Enable Bit
* - Controller should not be using DDR Mode
* - Controller should advertise that it supports High Speed
* in capabilities register
* - MMC/SD clock coming out of controller > 25MHz
*/
if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) &&
(ios->timing != MMC_TIMING_UHS_DDR50) &&
((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) {
regval = OMAP_HSMMC_READ(host->base, HCTL);
if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000)
regval |= HSPE;
else
regval &= ~HSPE;
OMAP_HSMMC_WRITE(host->base, HCTL, regval);
}
omap_hsmmc_start_clock(host);
}
@ -676,8 +710,8 @@ static void send_init_stream(struct omap_hsmmc_host *host)
OMAP_HSMMC_WRITE(host->base, CMD, INIT_STREAM_CMD);
timeout = jiffies + msecs_to_jiffies(MMC_TIMEOUT_MS);
while ((reg != CC) && time_before(jiffies, timeout))
reg = OMAP_HSMMC_READ(host->base, STAT) & CC;
while ((reg != CC_EN) && time_before(jiffies, timeout))
reg = OMAP_HSMMC_READ(host->base, STAT) & CC_EN;
OMAP_HSMMC_WRITE(host->base, CON,
OMAP_HSMMC_READ(host->base, CON) & ~INIT_STREAM);
@ -768,7 +802,7 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
}
if (host->use_dma)
cmdreg |= DMA_EN;
cmdreg |= DMAE;
host->req_in_progress = 1;
@ -968,16 +1002,20 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
__func__);
}
static void hsmmc_command_incomplete(struct omap_hsmmc_host *host, int err)
static void hsmmc_command_incomplete(struct omap_hsmmc_host *host,
int err, int end_cmd)
{
omap_hsmmc_reset_controller_fsm(host, SRC);
host->cmd->error = err;
if (end_cmd) {
omap_hsmmc_reset_controller_fsm(host, SRC);
if (host->cmd)
host->cmd->error = err;
}
if (host->data) {
omap_hsmmc_reset_controller_fsm(host, SRD);
omap_hsmmc_dma_cleanup(host, err);
}
} else if (host->mrq && host->mrq->cmd)
host->mrq->cmd->error = err;
}
static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
@ -988,23 +1026,25 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
data = host->data;
dev_vdbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
if (status & ERR) {
if (status & ERR_EN) {
omap_hsmmc_dbg_report_irq(host, status);
if (status & (CMD_TIMEOUT | DATA_TIMEOUT))
hsmmc_command_incomplete(host, -ETIMEDOUT);
else if (status & (CMD_CRC | DATA_CRC))
hsmmc_command_incomplete(host, -EILSEQ);
end_cmd = 1;
if (status & (CTO_EN | CCRC_EN))
end_cmd = 1;
if (status & (CTO_EN | DTO_EN))
hsmmc_command_incomplete(host, -ETIMEDOUT, end_cmd);
else if (status & (CCRC_EN | DCRC_EN))
hsmmc_command_incomplete(host, -EILSEQ, end_cmd);
if (host->data || host->response_busy) {
end_trans = 1;
end_trans = !end_cmd;
host->response_busy = 0;
}
}
if (end_cmd || ((status & CC) && host->cmd))
if (end_cmd || ((status & CC_EN) && host->cmd))
omap_hsmmc_cmd_done(host, host->cmd);
if ((end_trans || (status & TC)) && host->mrq)
if ((end_trans || (status & TC_EN)) && host->mrq)
omap_hsmmc_xfer_done(host, data);
}
@ -1101,7 +1141,7 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
return 0;
err:
dev_dbg(mmc_dev(host->mmc), "Unable to switch operating voltage\n");
dev_err(mmc_dev(host->mmc), "Unable to switch operating voltage\n");
return ret;
}
@ -1360,7 +1400,7 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
if (host->use_dma) {
ret = omap_hsmmc_start_dma_transfer(host, req);
if (ret != 0) {
dev_dbg(mmc_dev(host->mmc), "MMC start dma failure\n");
dev_err(mmc_dev(host->mmc), "MMC start dma failure\n");
return ret;
}
}
@ -1678,7 +1718,7 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
{
struct omap_mmc_platform_data *pdata;
struct device_node *np = dev->of_node;
u32 bus_width;
u32 bus_width, max_freq;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
@ -1705,6 +1745,12 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
if (of_find_property(np, "ti,needs-special-reset", NULL))
pdata->slots[0].features |= HSMMC_HAS_UPDATED_RESET;
if (!of_property_read_u32(np, "max-frequency", &max_freq))
pdata->max_freq = max_freq;
if (of_find_property(np, "ti,needs-special-hs-handling", NULL))
pdata->slots[0].features |= HSMMC_HAS_HSPE_SUPPORT;
return pdata;
}
#else
@ -1725,6 +1771,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
const struct of_device_id *match;
dma_cap_mask_t mask;
unsigned tx_req, rx_req;
struct pinctrl *pinctrl;
match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
if (match) {
@ -1821,7 +1868,6 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
* MMC can still work without debounce clock.
*/
if (IS_ERR(host->dbclk)) {
dev_warn(mmc_dev(host->mmc), "Failed to get debounce clk\n");
host->dbclk = NULL;
} else if (clk_prepare_enable(host->dbclk) != 0) {
dev_warn(mmc_dev(host->mmc), "Failed to enable debounce clk\n");
@ -1889,13 +1935,13 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
ret = request_irq(host->irq, omap_hsmmc_irq, 0,
mmc_hostname(mmc), host);
if (ret) {
dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
dev_err(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
goto err_irq;
}
if (pdata->init != NULL) {
if (pdata->init(&pdev->dev) != 0) {
dev_dbg(mmc_dev(host->mmc),
dev_err(mmc_dev(host->mmc),
"Unable to configure MMC IRQs\n");
goto err_irq_cd_init;
}
@ -1918,7 +1964,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
mmc_hostname(mmc), host);
if (ret) {
dev_dbg(mmc_dev(host->mmc),
dev_err(mmc_dev(host->mmc),
"Unable to grab MMC CD IRQ\n");
goto err_irq_cd;
}
@ -1928,6 +1974,11 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
omap_hsmmc_disable_irq(host);
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(pinctrl))
dev_warn(&pdev->dev,
"pins are not configured from the driver\n");
omap_hsmmc_protect_card(host);
mmc_add_host(mmc);
@ -2027,6 +2078,25 @@ static int __devexit omap_hsmmc_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM
static int omap_hsmmc_prepare(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
if (host->pdata->suspend)
return host->pdata->suspend(dev, host->slot_id);
return 0;
}
static void omap_hsmmc_complete(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
if (host->pdata->resume)
host->pdata->resume(dev, host->slot_id);
}
static int omap_hsmmc_suspend(struct device *dev)
{
int ret = 0;
@ -2040,23 +2110,10 @@ static int omap_hsmmc_suspend(struct device *dev)
pm_runtime_get_sync(host->dev);
host->suspended = 1;
if (host->pdata->suspend) {
ret = host->pdata->suspend(dev, host->slot_id);
if (ret) {
dev_dbg(dev, "Unable to handle MMC board"
" level suspend\n");
host->suspended = 0;
return ret;
}
}
ret = mmc_suspend_host(host->mmc);
if (ret) {
host->suspended = 0;
if (host->pdata->resume) {
if (host->pdata->resume(dev, host->slot_id))
dev_dbg(dev, "Unmask interrupt failed\n");
}
goto err;
}
@ -2093,12 +2150,6 @@ static int omap_hsmmc_resume(struct device *dev)
if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER))
omap_hsmmc_conf_bus_power(host);
if (host->pdata->resume) {
ret = host->pdata->resume(dev, host->slot_id);
if (ret)
dev_dbg(dev, "Unmask interrupt failed\n");
}
omap_hsmmc_protect_card(host);
/* Notify the core to resume the host */
@ -2114,8 +2165,10 @@ static int omap_hsmmc_resume(struct device *dev)
}
#else
#define omap_hsmmc_prepare NULL
#define omap_hsmmc_complete NULL
#define omap_hsmmc_suspend NULL
#define omap_hsmmc_resume NULL
#define omap_hsmmc_resume NULL
#endif
static int omap_hsmmc_runtime_suspend(struct device *dev)
@ -2143,6 +2196,8 @@ static int omap_hsmmc_runtime_resume(struct device *dev)
static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
.suspend = omap_hsmmc_suspend,
.resume = omap_hsmmc_resume,
.prepare = omap_hsmmc_prepare,
.complete = omap_hsmmc_complete,
.runtime_suspend = omap_hsmmc_runtime_suspend,
.runtime_resume = omap_hsmmc_runtime_resume,
};

View File

@ -19,20 +19,30 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/err.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/mmc/host.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include "sdhci-pltfm.h"
struct sdhci_dove_priv {
struct clk *clk;
int gpio_cd;
};
static irqreturn_t sdhci_dove_carddetect_irq(int irq, void *data)
{
struct sdhci_host *host = data;
tasklet_schedule(&host->card_tasklet);
return IRQ_HANDLED;
}
static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)
{
u16 ret;
@ -50,16 +60,25 @@ static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)
static u32 sdhci_dove_readl(struct sdhci_host *host, int reg)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_dove_priv *priv = pltfm_host->priv;
u32 ret;
ret = readl(host->ioaddr + reg);
switch (reg) {
case SDHCI_CAPABILITIES:
ret = readl(host->ioaddr + reg);
/* Mask the support for 3.0V */
ret &= ~SDHCI_CAN_VDD_300;
break;
default:
ret = readl(host->ioaddr + reg);
case SDHCI_PRESENT_STATE:
if (gpio_is_valid(priv->gpio_cd)) {
if (gpio_get_value(priv->gpio_cd) == 0)
ret |= SDHCI_CARD_PRESENT;
else
ret &= ~SDHCI_CARD_PRESENT;
}
break;
}
return ret;
}
@ -92,25 +111,70 @@ static int __devinit sdhci_dove_probe(struct platform_device *pdev)
return -ENOMEM;
}
priv->clk = clk_get(&pdev->dev, NULL);
if (!IS_ERR(priv->clk))
clk_prepare_enable(priv->clk);
priv->clk = devm_clk_get(&pdev->dev, NULL);
ret = sdhci_pltfm_register(pdev, &sdhci_dove_pdata);
if (ret)
goto sdhci_dove_register_fail;
if (pdev->dev.of_node) {
priv->gpio_cd = of_get_named_gpio(pdev->dev.of_node,
"cd-gpios", 0);
} else {
priv->gpio_cd = -EINVAL;
}
if (gpio_is_valid(priv->gpio_cd)) {
ret = gpio_request(priv->gpio_cd, "sdhci-cd");
if (ret) {
dev_err(&pdev->dev, "card detect gpio request failed: %d\n",
ret);
return ret;
}
gpio_direction_input(priv->gpio_cd);
}
host = sdhci_pltfm_init(pdev, &sdhci_dove_pdata);
if (IS_ERR(host)) {
ret = PTR_ERR(host);
goto err_sdhci_pltfm_init;
}
host = platform_get_drvdata(pdev);
pltfm_host = sdhci_priv(host);
pltfm_host->priv = priv;
if (!IS_ERR(priv->clk))
clk_prepare_enable(priv->clk);
sdhci_get_of_property(pdev);
ret = sdhci_add_host(host);
if (ret)
goto err_sdhci_add;
/*
* We must request the IRQ after sdhci_add_host(), as the tasklet only
* gets setup in sdhci_add_host() and we oops.
*/
if (gpio_is_valid(priv->gpio_cd)) {
ret = request_irq(gpio_to_irq(priv->gpio_cd),
sdhci_dove_carddetect_irq,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
mmc_hostname(host->mmc), host);
if (ret) {
dev_err(&pdev->dev, "card detect irq request failed: %d\n",
ret);
goto err_request_irq;
}
}
return 0;
sdhci_dove_register_fail:
if (!IS_ERR(priv->clk)) {
err_request_irq:
sdhci_remove_host(host, 0);
err_sdhci_add:
if (!IS_ERR(priv->clk))
clk_disable_unprepare(priv->clk);
clk_put(priv->clk);
}
sdhci_pltfm_free(pdev);
err_sdhci_pltfm_init:
if (gpio_is_valid(priv->gpio_cd))
gpio_free(priv->gpio_cd);
return ret;
}
@ -122,10 +186,14 @@ static int __devexit sdhci_dove_remove(struct platform_device *pdev)
sdhci_pltfm_unregister(pdev);
if (!IS_ERR(priv->clk)) {
clk_disable_unprepare(priv->clk);
clk_put(priv->clk);
if (gpio_is_valid(priv->gpio_cd)) {
free_irq(gpio_to_irq(priv->gpio_cd), host);
gpio_free(priv->gpio_cd);
}
if (!IS_ERR(priv->clk))
clk_disable_unprepare(priv->clk);
return 0;
}

View File

@ -456,10 +456,10 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
pltfm_host = sdhci_priv(host);
imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL);
imx_data = devm_kzalloc(&pdev->dev, sizeof(*imx_data), GFP_KERNEL);
if (!imx_data) {
err = -ENOMEM;
goto err_imx_data;
goto free_sdhci;
}
if (of_id)
@ -470,19 +470,19 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(imx_data->clk_ipg)) {
err = PTR_ERR(imx_data->clk_ipg);
goto err_clk_get;
goto free_sdhci;
}
imx_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(imx_data->clk_ahb)) {
err = PTR_ERR(imx_data->clk_ahb);
goto err_clk_get;
goto free_sdhci;
}
imx_data->clk_per = devm_clk_get(&pdev->dev, "per");
if (IS_ERR(imx_data->clk_per)) {
err = PTR_ERR(imx_data->clk_per);
goto err_clk_get;
goto free_sdhci;
}
pltfm_host->clk = imx_data->clk_per;
@ -494,7 +494,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
imx_data->pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(imx_data->pinctrl)) {
err = PTR_ERR(imx_data->pinctrl);
goto pin_err;
goto disable_clk;
}
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
@ -519,7 +519,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
if (!host->mmc->parent->platform_data) {
dev_err(mmc_dev(host->mmc), "no board data!\n");
err = -EINVAL;
goto no_board_data;
goto disable_clk;
}
imx_data->boarddata = *((struct esdhc_platform_data *)
host->mmc->parent->platform_data);
@ -527,7 +527,8 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
/* write_protect */
if (boarddata->wp_type == ESDHC_WP_GPIO) {
err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP");
err = devm_gpio_request_one(&pdev->dev, boarddata->wp_gpio,
GPIOF_IN, "ESDHC_WP");
if (err) {
dev_warn(mmc_dev(host->mmc),
"no write-protect pin available!\n");
@ -543,19 +544,21 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
switch (boarddata->cd_type) {
case ESDHC_CD_GPIO:
err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD");
err = devm_gpio_request_one(&pdev->dev, boarddata->cd_gpio,
GPIOF_IN, "ESDHC_CD");
if (err) {
dev_err(mmc_dev(host->mmc),
"no card-detect pin available!\n");
goto no_card_detect_pin;
goto disable_clk;
}
err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq,
err = devm_request_irq(&pdev->dev,
gpio_to_irq(boarddata->cd_gpio), cd_irq,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
mmc_hostname(host->mmc), host);
if (err) {
dev_err(mmc_dev(host->mmc), "request irq error\n");
goto no_card_detect_irq;
goto disable_clk;
}
/* fall through */
@ -574,27 +577,15 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
err = sdhci_add_host(host);
if (err)
goto err_add_host;
goto disable_clk;
return 0;
err_add_host:
if (gpio_is_valid(boarddata->cd_gpio))
free_irq(gpio_to_irq(boarddata->cd_gpio), host);
no_card_detect_irq:
if (gpio_is_valid(boarddata->cd_gpio))
gpio_free(boarddata->cd_gpio);
if (gpio_is_valid(boarddata->wp_gpio))
gpio_free(boarddata->wp_gpio);
no_card_detect_pin:
no_board_data:
pin_err:
disable_clk:
clk_disable_unprepare(imx_data->clk_per);
clk_disable_unprepare(imx_data->clk_ipg);
clk_disable_unprepare(imx_data->clk_ahb);
err_clk_get:
kfree(imx_data);
err_imx_data:
free_sdhci:
sdhci_pltfm_free(pdev);
return err;
}
@ -604,25 +595,14 @@ static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev)
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv;
struct esdhc_platform_data *boarddata = &imx_data->boarddata;
int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
sdhci_remove_host(host, dead);
if (gpio_is_valid(boarddata->wp_gpio))
gpio_free(boarddata->wp_gpio);
if (gpio_is_valid(boarddata->cd_gpio)) {
free_irq(gpio_to_irq(boarddata->cd_gpio), host);
gpio_free(boarddata->cd_gpio);
}
clk_disable_unprepare(imx_data->clk_per);
clk_disable_unprepare(imx_data->clk_ipg);
clk_disable_unprepare(imx_data->clk_ahb);
kfree(imx_data);
sdhci_pltfm_free(pdev);
return 0;

View File

@ -22,6 +22,7 @@
#include "sdhci-esdhc.h"
#define VENDOR_V_22 0x12
#define VENDOR_V_23 0x13
static u32 esdhc_readl(struct sdhci_host *host, int reg)
{
u32 ret;
@ -85,6 +86,18 @@ static u8 esdhc_readb(struct sdhci_host *host, int reg)
return ret;
}
static void esdhc_writel(struct sdhci_host *host, u32 val, int reg)
{
/*
* Enable IRQSTATEN[BGESEN] is just to set IRQSTAT[BGE]
* when SYSCTL[RSTD]) is set for some special operations.
* No any impact other operation.
*/
if (reg == SDHCI_INT_ENABLE)
val |= SDHCI_INT_BLK_GAP;
sdhci_be32bs_writel(host, val, reg);
}
static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
{
if (reg == SDHCI_BLOCK_SIZE) {
@ -121,6 +134,41 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
sdhci_be32bs_writeb(host, val, reg);
}
/*
* For Abort or Suspend after Stop at Block Gap, ignore the ADMA
* error(IRQSTAT[ADMAE]) if both Transfer Complete(IRQSTAT[TC])
* and Block Gap Event(IRQSTAT[BGE]) are also set.
* For Continue, apply soft reset for data(SYSCTL[RSTD]);
* and re-issue the entire read transaction from beginning.
*/
static void esdhci_of_adma_workaround(struct sdhci_host *host, u32 intmask)
{
u32 tmp;
bool applicable;
dma_addr_t dmastart;
dma_addr_t dmanow;
tmp = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
applicable = (intmask & SDHCI_INT_DATA_END) &&
(intmask & SDHCI_INT_BLK_GAP) &&
(tmp == VENDOR_V_23);
if (!applicable)
return;
host->data->error = 0;
dmastart = sg_dma_address(host->data->sg);
dmanow = dmastart + host->data->bytes_xfered;
/*
* Force update to the next DMA block boundary.
*/
dmanow = (dmanow & ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
SDHCI_DEFAULT_BOUNDARY_SIZE;
host->data->bytes_xfered = dmanow - dmastart;
sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
}
static int esdhc_of_enable_dma(struct sdhci_host *host)
{
setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
@ -177,13 +225,16 @@ static void esdhc_of_platform_init(struct sdhci_host *host)
vvn = (vvn & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
if (vvn == VENDOR_V_22)
host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;
if (vvn > VENDOR_V_22)
host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
}
static struct sdhci_ops sdhci_esdhc_ops = {
.read_l = esdhc_readl,
.read_w = esdhc_readw,
.read_b = esdhc_readb,
.write_l = sdhci_be32bs_writel,
.write_l = esdhc_writel,
.write_w = esdhc_writew,
.write_b = esdhc_writeb,
.set_clock = esdhc_of_set_clock,
@ -195,6 +246,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.platform_suspend = esdhc_of_suspend,
.platform_resume = esdhc_of_resume,
#endif
.adma_workaround = esdhci_of_adma_workaround,
};
static struct sdhci_pltfm_data sdhci_esdhc_pdata = {

View File

@ -114,6 +114,7 @@ static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot)
SDHCI_TIMEOUT_CLK_UNIT |
SDHCI_CAN_VDD_330 |
SDHCI_CAN_DO_HISPD |
SDHCI_CAN_DO_SDMA;
return 0;
}

View File

@ -78,6 +78,9 @@ void sdhci_get_of_property(struct platform_device *pdev)
if (of_get_property(np, "broken-cd", NULL))
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
if (of_get_property(np, "no-1-8-v", NULL))
host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
@ -89,6 +92,12 @@ void sdhci_get_of_property(struct platform_device *pdev)
clk = of_get_property(np, "clock-frequency", &size);
if (clk && size == sizeof(*clk) && *clk)
pltfm_host->clock = be32_to_cpup(clk);
if (of_find_property(np, "keep-power-in-suspend", NULL))
host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
if (of_find_property(np, "enable-sdio-wakeup", NULL))
host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
}
}
#else

View File

@ -163,10 +163,18 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
return 0;
}
static u32 pxav3_get_max_clock(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
return clk_get_rate(pltfm_host->clk);
}
static struct sdhci_ops pxav3_sdhci_ops = {
.platform_reset_exit = pxav3_set_private_registers,
.set_uhs_signaling = pxav3_set_uhs_signaling,
.platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
.get_max_clock = pxav3_get_max_clock,
};
#ifdef CONFIG_OF
@ -249,7 +257,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
| SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
| SDHCI_QUIRK_32BIT_ADMA_SIZE;
| SDHCI_QUIRK_32BIT_ADMA_SIZE
| SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN;
/* enable 1/8V DDR capable */
host->mmc->caps |= MMC_CAP_1_8V_DDR;
@ -271,6 +280,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
if (pdata->quirks)
host->quirks |= pdata->quirks;
if (pdata->quirks2)
host->quirks2 |= pdata->quirks2;
if (pdata->host_caps)
host->mmc->caps |= pdata->host_caps;
if (pdata->host_caps2)

View File

@ -24,6 +24,7 @@
#include <linux/of_gpio.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/pinctrl/consumer.h>
#include <linux/mmc/host.h>
@ -57,6 +58,7 @@ struct sdhci_s3c {
int ext_cd_irq;
int ext_cd_gpio;
int *gpios;
struct pinctrl *pctrl;
struct clk *clk_io;
struct clk *clk_bus[MAX_BUS_CLK];
@ -373,7 +375,9 @@ static struct sdhci_ops sdhci_s3c_ops = {
static void sdhci_s3c_notify_change(struct platform_device *dev, int state)
{
struct sdhci_host *host = platform_get_drvdata(dev);
#ifdef CONFIG_PM_RUNTIME
struct sdhci_s3c *sc = sdhci_priv(host);
#endif
unsigned long flags;
if (host) {
@ -413,7 +417,7 @@ static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc)
struct s3c_sdhci_platdata *pdata = sc->pdata;
struct device *dev = &sc->pdev->dev;
if (gpio_request(pdata->ext_cd_gpio, "SDHCI EXT CD") == 0) {
if (devm_gpio_request(dev, pdata->ext_cd_gpio, "SDHCI EXT CD") == 0) {
sc->ext_cd_gpio = pdata->ext_cd_gpio;
sc->ext_cd_irq = gpio_to_irq(pdata->ext_cd_gpio);
if (sc->ext_cd_irq &&
@ -456,12 +460,12 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
return -ENOMEM;
/* get the card detection method */
if (of_get_property(node, "broken-cd", 0)) {
if (of_get_property(node, "broken-cd", NULL)) {
pdata->cd_type = S3C_SDHCI_CD_NONE;
goto setup_bus;
}
if (of_get_property(node, "non-removable", 0)) {
if (of_get_property(node, "non-removable", NULL)) {
pdata->cd_type = S3C_SDHCI_CD_PERMANENT;
goto setup_bus;
}
@ -484,8 +488,9 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
return -EINVAL;
}
dev_info(dev, "assuming no card detect line available\n");
pdata->cd_type = S3C_SDHCI_CD_NONE;
/* assuming internal card detect that will be configured by pinctrl */
pdata->cd_type = S3C_SDHCI_CD_INTERNAL;
goto setup_bus;
found_cd:
if (pdata->cd_type == S3C_SDHCI_CD_GPIO) {
@ -494,7 +499,7 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
if (of_get_property(node, "cd-inverted", NULL))
pdata->ext_cd_gpio_invert = 1;
} else if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) {
ret = gpio_request(gpio, "sdhci-cd");
ret = devm_gpio_request(dev, gpio, "sdhci-cd");
if (ret) {
dev_err(dev, "card detect gpio request failed\n");
return -EINVAL;
@ -503,33 +508,28 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
}
setup_bus:
if (!IS_ERR(ourhost->pctrl))
return 0;
/* get the gpios for command, clock and data lines */
for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) {
gpio = of_get_gpio(node, cnt);
if (!gpio_is_valid(gpio)) {
dev_err(dev, "invalid gpio[%d]\n", cnt);
goto err_free_dt_cd_gpio;
return -EINVAL;
}
ourhost->gpios[cnt] = gpio;
}
for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) {
ret = gpio_request(ourhost->gpios[cnt], "sdhci-gpio");
ret = devm_gpio_request(dev, ourhost->gpios[cnt], "sdhci-gpio");
if (ret) {
dev_err(dev, "gpio[%d] request failed\n", cnt);
goto err_free_dt_gpios;
return -EINVAL;
}
}
return 0;
err_free_dt_gpios:
while (--cnt >= 0)
gpio_free(ourhost->gpios[cnt]);
err_free_dt_cd_gpio:
if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL)
gpio_free(ourhost->ext_cd_gpio);
return -EINVAL;
}
#else
static int __devinit sdhci_s3c_parse_dt(struct device *dev,
@ -586,13 +586,15 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
ret = -ENOMEM;
goto err_pdata;
goto err_pdata_io_clk;
}
sc->pctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (pdev->dev.of_node) {
ret = sdhci_s3c_parse_dt(&pdev->dev, host, pdata);
if (ret)
goto err_pdata;
goto err_pdata_io_clk;
} else {
memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));
sc->ext_cd_gpio = -1; /* invalid gpio number */
@ -610,7 +612,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
if (IS_ERR(sc->clk_io)) {
dev_err(dev, "failed to get io clock\n");
ret = PTR_ERR(sc->clk_io);
goto err_io_clk;
goto err_pdata_io_clk;
}
/* enable the local io clock and keep it running for the moment. */
@ -773,13 +775,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
clk_disable_unprepare(sc->clk_io);
clk_put(sc->clk_io);
err_io_clk:
for (ptr = 0; ptr < NUM_GPIOS(sc->pdata->max_width); ptr++)
gpio_free(sc->gpios[ptr]);
if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL)
gpio_free(sc->ext_cd_gpio);
err_pdata:
err_pdata_io_clk:
sdhci_free_host(host);
return ret;
@ -798,9 +794,6 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
if (sc->ext_cd_irq)
free_irq(sc->ext_cd_irq, sc);
if (gpio_is_valid(sc->ext_cd_gpio))
gpio_free(sc->ext_cd_gpio);
#ifdef CONFIG_PM_RUNTIME
if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL)
clk_prepare_enable(sc->clk_io);
@ -821,11 +814,6 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
clk_disable_unprepare(sc->clk_io);
clk_put(sc->clk_io);
if (pdev->dev.of_node) {
for (ptr = 0; ptr < NUM_GPIOS(sc->pdata->max_width); ptr++)
gpio_free(sc->gpios[ptr]);
}
sdhci_free_host(host);
platform_set_drvdata(pdev, NULL);

View File

@ -146,6 +146,11 @@ static int __devinit sdhci_probe(struct platform_device *pdev)
goto put_clk;
}
ret = clk_set_rate(sdhci->clk, 50000000);
if (ret)
dev_dbg(&pdev->dev, "Error setting desired clk, clk=%lu\n",
clk_get_rate(sdhci->clk));
if (np) {
sdhci->data = sdhci_probe_config_dt(pdev);
if (IS_ERR(sdhci->data)) {
@ -297,7 +302,7 @@ static int sdhci_suspend(struct device *dev)
ret = sdhci_suspend_host(host);
if (!ret)
clk_disable_unprepare(sdhci->clk);
clk_disable(sdhci->clk);
return ret;
}
@ -308,7 +313,7 @@ static int sdhci_resume(struct device *dev)
struct spear_sdhci *sdhci = dev_get_platdata(dev);
int ret;
ret = clk_prepare_enable(sdhci->clk);
ret = clk_enable(sdhci->clk);
if (ret) {
dev_dbg(dev, "Resume: Error enabling clock\n");
return ret;

View File

@ -1618,7 +1618,7 @@ static int sdhci_do_3_3v_signal_voltage_switch(struct sdhci_host *host,
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
if (host->vqmmc) {
ret = regulator_set_voltage(host->vqmmc, 3300000, 3300000);
ret = regulator_set_voltage(host->vqmmc, 2700000, 3600000);
if (ret) {
pr_warning("%s: Switching to 3.3V signalling voltage "
" failed\n", mmc_hostname(host->mmc));
@ -1662,7 +1662,7 @@ static int sdhci_do_1_8v_signal_voltage_switch(struct sdhci_host *host,
*/
if (host->vqmmc)
ret = regulator_set_voltage(host->vqmmc,
1800000, 1800000);
1700000, 1950000);
else
ret = 0;
@ -1994,30 +1994,11 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable)
sdhci_runtime_pm_put(host);
}
static const struct mmc_host_ops sdhci_ops = {
.request = sdhci_request,
.set_ios = sdhci_set_ios,
.get_ro = sdhci_get_ro,
.hw_reset = sdhci_hw_reset,
.enable_sdio_irq = sdhci_enable_sdio_irq,
.start_signal_voltage_switch = sdhci_start_signal_voltage_switch,
.execute_tuning = sdhci_execute_tuning,
.enable_preset_value = sdhci_enable_preset_value,
};
/*****************************************************************************\
* *
* Tasklets *
* *
\*****************************************************************************/
static void sdhci_tasklet_card(unsigned long param)
static void sdhci_card_event(struct mmc_host *mmc)
{
struct sdhci_host *host;
struct sdhci_host *host = mmc_priv(mmc);
unsigned long flags;
host = (struct sdhci_host*)param;
spin_lock_irqsave(&host->lock, flags);
/* Check host->mrq first in case we are runtime suspended */
@ -2036,6 +2017,31 @@ static void sdhci_tasklet_card(unsigned long param)
}
spin_unlock_irqrestore(&host->lock, flags);
}
static const struct mmc_host_ops sdhci_ops = {
.request = sdhci_request,
.set_ios = sdhci_set_ios,
.get_ro = sdhci_get_ro,
.hw_reset = sdhci_hw_reset,
.enable_sdio_irq = sdhci_enable_sdio_irq,
.start_signal_voltage_switch = sdhci_start_signal_voltage_switch,
.execute_tuning = sdhci_execute_tuning,
.enable_preset_value = sdhci_enable_preset_value,
.card_event = sdhci_card_event,
};
/*****************************************************************************\
* *
* Tasklets *
* *
\*****************************************************************************/
static void sdhci_tasklet_card(unsigned long param)
{
struct sdhci_host *host = (struct sdhci_host*)param;
sdhci_card_event(host->mmc);
mmc_detect_change(host->mmc, msecs_to_jiffies(200));
}
@ -2282,6 +2288,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
pr_err("%s: ADMA error\n", mmc_hostname(host->mmc));
sdhci_show_adma_error(host);
host->data->error = -EIO;
if (host->ops->adma_workaround)
host->ops->adma_workaround(host, intmask);
}
if (host->data->error)
@ -2858,10 +2866,16 @@ int sdhci_add_host(struct sdhci_host *host)
mmc_hostname(mmc));
host->vqmmc = NULL;
}
}
else if (regulator_is_supported_voltage(host->vqmmc, 1800000, 1800000))
} else {
regulator_enable(host->vqmmc);
else
if (!regulator_is_supported_voltage(host->vqmmc, 1700000,
1950000))
caps[1] &= ~(SDHCI_SUPPORT_SDR104 |
SDHCI_SUPPORT_SDR50 |
SDHCI_SUPPORT_DDR50);
}
if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V)
caps[1] &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
SDHCI_SUPPORT_DDR50);
@ -2919,21 +2933,18 @@ int sdhci_add_host(struct sdhci_host *host)
mmc_hostname(mmc));
host->vmmc = NULL;
}
} else
regulator_enable(host->vmmc);
}
#ifdef CONFIG_REGULATOR
if (host->vmmc) {
ret = regulator_is_supported_voltage(host->vmmc, 3300000,
3300000);
ret = regulator_is_supported_voltage(host->vmmc, 2700000,
3600000);
if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_330)))
caps[0] &= ~SDHCI_CAN_VDD_330;
ret = regulator_is_supported_voltage(host->vmmc, 3000000,
3000000);
if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_300)))
caps[0] &= ~SDHCI_CAN_VDD_300;
ret = regulator_is_supported_voltage(host->vmmc, 1800000,
1800000);
ret = regulator_is_supported_voltage(host->vmmc, 1700000,
1950000);
if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_180)))
caps[0] &= ~SDHCI_CAN_VDD_180;
}

View File

@ -120,6 +120,7 @@
#define SDHCI_SIGNAL_ENABLE 0x38
#define SDHCI_INT_RESPONSE 0x00000001
#define SDHCI_INT_DATA_END 0x00000002
#define SDHCI_INT_BLK_GAP 0x00000004
#define SDHCI_INT_DMA_END 0x00000008
#define SDHCI_INT_SPACE_AVAIL 0x00000010
#define SDHCI_INT_DATA_AVAIL 0x00000020
@ -146,7 +147,8 @@
#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR)
SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \
SDHCI_INT_BLK_GAP)
#define SDHCI_INT_ALL_MASK ((unsigned int)-1)
#define SDHCI_ACMD12_ERR 0x3C
@ -278,6 +280,7 @@ struct sdhci_ops {
void (*hw_reset)(struct sdhci_host *host);
void (*platform_suspend)(struct sdhci_host *host);
void (*platform_resume)(struct sdhci_host *host);
void (*adma_workaround)(struct sdhci_host *host, u32 intmask);
void (*platform_init)(struct sdhci_host *host);
};

View File

@ -1306,7 +1306,6 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
struct sh_mmcif_plat_data *pd = pdev->dev.platform_data;
struct resource *res;
void __iomem *reg;
char clk_name[8];
irq[0] = platform_get_irq(pdev, 0);
irq[1] = platform_get_irq(pdev, 1);
@ -1356,11 +1355,10 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
host->power = false;
snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id);
host->hclk = clk_get(&pdev->dev, clk_name);
host->hclk = clk_get(&pdev->dev, NULL);
if (IS_ERR(host->hclk)) {
ret = PTR_ERR(host->hclk);
dev_err(&pdev->dev, "cannot get clock \"%s\": %d\n", clk_name, ret);
dev_err(&pdev->dev, "cannot get clock: %d\n", ret);
goto eclkget;
}
ret = sh_mmcif_clk_update(host);

View File

@ -123,7 +123,6 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
struct tmio_mmc_data *mmc_data;
struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
struct tmio_mmc_host *host;
char clk_name[8];
int irq, ret, i = 0;
bool multiplexed_isr = true;
@ -144,11 +143,10 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
}
}
snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
priv->clk = clk_get(&pdev->dev, clk_name);
priv->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
ret = PTR_ERR(priv->clk);
dev_err(&pdev->dev, "cannot get clock: %d\n", ret);
goto eclkget;
}
@ -250,7 +248,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n",
mmc_hostname(host->mmc), (unsigned long)
(platform_get_resource(pdev, IORESOURCE_MEM, 0)->start),
mmc_data->hclk / 1000000);
host->mmc->f_max / 1000000);
return ret;

View File

@ -2362,6 +2362,7 @@ error4:
error1:
usb_free_urb(command_out_urb);
error0:
usb_put_dev(udev);
return retval;
}

1029
drivers/mmc/host/wmt-sdmmc.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -85,6 +85,7 @@ struct mmc_ext_csd {
bool boot_ro_lockable;
u8 raw_exception_status; /* 53 */
u8 raw_partition_support; /* 160 */
u8 raw_rpmb_size_mult; /* 168 */
u8 raw_erased_mem_count; /* 181 */
u8 raw_ext_csd_structure; /* 194 */
u8 raw_card_type; /* 196 */
@ -206,6 +207,7 @@ struct mmc_part {
#define MMC_BLK_DATA_AREA_MAIN (1<<0)
#define MMC_BLK_DATA_AREA_BOOT (1<<1)
#define MMC_BLK_DATA_AREA_GP (1<<2)
#define MMC_BLK_DATA_AREA_RPMB (1<<3)
};
/*

View File

@ -170,6 +170,8 @@ extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
extern unsigned int mmc_calc_max_discard(struct mmc_card *card);
extern int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
extern int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
bool is_rel_write);
extern int mmc_hw_reset(struct mmc_host *host);
extern int mmc_hw_reset_check(struct mmc_host *host);
extern int mmc_can_reset(struct mmc_card *card);

View File

@ -229,8 +229,9 @@ struct dw_mci_board {
u32 quirks; /* Workaround / Quirk flags */
unsigned int bus_hz; /* Clock speed at the cclk_in pad */
unsigned int caps; /* Capabilities */
unsigned int caps2; /* More capabilities */
u32 caps; /* Capabilities */
u32 caps2; /* More capabilities */
u32 pm_caps; /* PM capabilities */
/*
* Override fifo depth. If 0, autodetect it from the FIFOTH register,
* but note that this may not be reliable after a bootloader has used

View File

@ -53,12 +53,12 @@ struct mmc_ios {
#define MMC_TIMING_LEGACY 0
#define MMC_TIMING_MMC_HS 1
#define MMC_TIMING_SD_HS 2
#define MMC_TIMING_UHS_SDR12 MMC_TIMING_LEGACY
#define MMC_TIMING_UHS_SDR25 MMC_TIMING_SD_HS
#define MMC_TIMING_UHS_SDR50 3
#define MMC_TIMING_UHS_SDR104 4
#define MMC_TIMING_UHS_DDR50 5
#define MMC_TIMING_MMC_HS200 6
#define MMC_TIMING_UHS_SDR12 3
#define MMC_TIMING_UHS_SDR25 4
#define MMC_TIMING_UHS_SDR50 5
#define MMC_TIMING_UHS_SDR104 6
#define MMC_TIMING_UHS_DDR50 7
#define MMC_TIMING_MMC_HS200 8
#define MMC_SDR_MODE 0
#define MMC_1_2V_DDR_MODE 1
@ -136,6 +136,7 @@ struct mmc_host_ops {
void (*enable_preset_value)(struct mmc_host *host, bool enable);
int (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
void (*hw_reset)(struct mmc_host *host);
void (*card_event)(struct mmc_host *host);
};
struct mmc_card;
@ -211,7 +212,7 @@ struct mmc_host {
#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */
#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */
unsigned long caps; /* Host capabilities */
u32 caps; /* Host capabilities */
#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */
#define MMC_CAP_MMC_HIGHSPEED (1 << 1) /* Can do MMC high-speed timing */
@ -241,7 +242,7 @@ struct mmc_host {
#define MMC_CAP_CMD23 (1 << 30) /* CMD23 supported. */
#define MMC_CAP_HW_RESET (1 << 31) /* Hardware reset */
unsigned int caps2; /* More host capabilities */
u32 caps2; /* More host capabilities */
#define MMC_CAP2_BOOTPART_NOACC (1 << 0) /* Boot partition no access */
#define MMC_CAP2_CACHE_CTRL (1 << 1) /* Allow cache control */

View File

@ -286,6 +286,7 @@ struct _mmc_csd {
#define EXT_CSD_BKOPS_START 164 /* W */
#define EXT_CSD_SANITIZE_START 165 /* W */
#define EXT_CSD_WR_REL_PARAM 166 /* RO */
#define EXT_CSD_RPMB_MULT 168 /* RO */
#define EXT_CSD_BOOT_WP 173 /* R/W */
#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */
#define EXT_CSD_PART_CONFIG 179 /* R/W */
@ -339,6 +340,7 @@ struct _mmc_csd {
#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7)
#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1)
#define EXT_CSD_PART_CONFIG_ACC_RPMB (0x3)
#define EXT_CSD_PART_CONFIG_ACC_GP0 (0x4)
#define EXT_CSD_PART_SUPPORT_PART_EN (0x1)

View File

@ -1,19 +0,0 @@
/*
* Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
*
* 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.
*/
#ifndef __LINUX_MMC_MXS_MMC_H__
#define __LINUX_MMC_MXS_MMC_H__
struct mxs_mmc_platform_data {
int wp_gpio; /* write protect pin */
unsigned int flags;
#define SLOTF_4_BIT_CAPABLE (1 << 0)
#define SLOTF_8_BIT_CAPABLE (1 << 1)
};
#endif /* __LINUX_MMC_MXS_MMC_H__ */

View File

@ -92,6 +92,8 @@ struct sdhci_host {
#define SDHCI_QUIRK2_HOST_OFF_CARD_ON (1<<0)
#define SDHCI_QUIRK2_HOST_NO_CMD23 (1<<1)
/* The system physically doesn't support 1.8v, even if the host does */
#define SDHCI_QUIRK2_NO_1_8_V (1<<2)
int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
@ -158,8 +160,8 @@ struct sdhci_host {
struct timer_list timer; /* Timer for timeouts */
unsigned int caps; /* Alternative CAPABILITY_0 */
unsigned int caps1; /* Alternative CAPABILITY_1 */
u32 caps; /* Alternative CAPABILITY_0 */
u32 caps1; /* Alternative CAPABILITY_1 */
unsigned int ocr_avail_sdio; /* OCR bit masks */
unsigned int ocr_avail_sd;

View File

@ -38,6 +38,7 @@
* @max_speed: the maximum speed supported
* @host_caps: Standard MMC host capabilities bit field.
* @quirks: quirks of platfrom
* @quirks2: quirks2 of platfrom
* @pm_caps: pm_caps of platfrom
*/
struct sdhci_pxa_platdata {
@ -48,9 +49,10 @@ struct sdhci_pxa_platdata {
unsigned int ext_cd_gpio;
bool ext_cd_gpio_invert;
unsigned int max_speed;
unsigned int host_caps;
unsigned int host_caps2;
u32 host_caps;
u32 host_caps2;
unsigned int quirks;
unsigned int quirks2;
unsigned int pm_caps;
};