Commit 11b84c58 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 29594404 71e69211
...@@ -21,6 +21,12 @@ Optional properties: ...@@ -21,6 +21,12 @@ Optional properties:
- cd-inverted: when present, polarity on the cd gpio line is inverted - cd-inverted: when present, polarity on the cd gpio line is inverted
- wp-inverted: when present, polarity on the wp gpio line is inverted - wp-inverted: when present, polarity on the wp gpio line is inverted
- max-frequency: maximum operating clock frequency - 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: Example:
...@@ -33,4 +39,6 @@ sdhci@ab000000 { ...@@ -33,4 +39,6 @@ sdhci@ab000000 {
cd-inverted; cd-inverted;
wp-gpios = <&gpio 70 0>; wp-gpios = <&gpio 70 0>;
max-frequency = <50000000>; max-frequency = <50000000>;
keep-power-in-suspend;
enable-sdio-wakeup;
} }
...@@ -12,10 +12,6 @@ is used. The Samsung's SDHCI controller bindings extends this as listed below. ...@@ -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 [A] The property "samsung,cd-pinmux-gpio" can be used as stated in the
"Optional Board Specific Properties" section below. "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: Required SoC Specific Properties:
- compatible: should be one of the following - compatible: should be one of the following
- "samsung,s3c6410-sdhci": For controllers compatible with s3c6410 sdhci - "samsung,s3c6410-sdhci": For controllers compatible with s3c6410 sdhci
...@@ -24,14 +20,18 @@ Required SoC Specific Properties: ...@@ -24,14 +20,18 @@ Required SoC Specific Properties:
controller. controller.
Required Board Specific Properties: Required Board Specific Properties:
- gpios: Should specify the gpios used for clock, command and data lines. The - Samsung GPIO variant (will be completely replaced by pinctrl):
gpio specifier format depends on the gpio controller. - 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: Optional Board Specific Properties:
- samsung,cd-pinmux-gpio: Specifies the card detect line that is routed - 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 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 should be used only if none of the mmc core card-detect properties are
used. used. Only for Samsung GPIO variant.
Example: Example:
sdhci@12530000 { sdhci@12530000 {
...@@ -40,12 +40,18 @@ Example: ...@@ -40,12 +40,18 @@ Example:
interrupts = <0 75 0>; interrupts = <0 75 0>;
bus-width = <4>; bus-width = <4>;
cd-gpios = <&gpk2 2 2 3 3>; cd-gpios = <&gpk2 2 2 3 3>;
/* Samsung GPIO variant */
gpios = <&gpk2 0 2 0 3>, /* clock line */ gpios = <&gpk2 0 2 0 3>, /* clock line */
<&gpk2 1 2 0 3>, /* command line */ <&gpk2 1 2 0 3>, /* command line */
<&gpk2 3 2 3 3>, /* data line 0 */ <&gpk2 3 2 3 3>, /* data line 0 */
<&gpk2 4 2 3 3>, /* data line 1 */ <&gpk2 4 2 3 3>, /* data line 1 */
<&gpk2 5 2 3 3>, /* data line 2 */ <&gpk2 5 2 3 3>, /* data line 2 */
<&gpk2 6 2 3 3>; /* data line 3 */ <&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 Note: This example shows both SoC specific and board specific properties
......
...@@ -19,6 +19,7 @@ ti,dual-volt: boolean, supports dual voltage cards ...@@ -19,6 +19,7 @@ ti,dual-volt: boolean, supports dual voltage cards
"supply-name" examples are "vmmc", "vmmc_aux" etc "supply-name" examples are "vmmc", "vmmc_aux" etc
ti,non-removable: non-removable slot (like eMMC) ti,non-removable: non-removable slot (like eMMC)
ti,needs-special-reset: Requires a special softreset sequence ti,needs-special-reset: Requires a special softreset sequence
ti,needs-special-hs-handling: HSMMC IP needs special setting for handling High Speed
Example: Example:
mmc1: mmc@0x4809c000 { mmc1: mmc@0x4809c000 {
......
* 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;
};
...@@ -25,6 +25,8 @@ All attributes are read-only. ...@@ -25,6 +25,8 @@ All attributes are read-only.
serial Product Serial Number (from CID Register) serial Product Serial Number (from CID Register)
erase_size Erase group size erase_size Erase group size
preferred_erase_size Preferred erase 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: Note on Erase Size and Preferred Erase Size:
...@@ -65,6 +67,11 @@ 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. "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 SD/MMC/SDIO Clock Gating Attribute
================================== ==================================
......
...@@ -1237,6 +1237,7 @@ F: drivers/video/wm8505fb* ...@@ -1237,6 +1237,7 @@ F: drivers/video/wm8505fb*
F: drivers/video/wmt_ge_rops.* F: drivers/video/wmt_ge_rops.*
F: drivers/tty/serial/vt8500_serial.c F: drivers/tty/serial/vt8500_serial.c
F: drivers/rtc/rtc-vt8500-c F: drivers/rtc/rtc-vt8500-c
F: drivers/mmc/host/wmt-sdmmc.c
ARM/ZIPIT Z2 SUPPORT ARM/ZIPIT Z2 SUPPORT
M: Marek Vasut <marek.vasut@gmail.com> M: Marek Vasut <marek.vasut@gmail.com>
...@@ -1368,14 +1369,6 @@ S: Maintained ...@@ -1368,14 +1369,6 @@ S: Maintained
F: drivers/atm/ F: drivers/atm/
F: include/linux/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 ATMEL AT91 / AT32 MCI DRIVER
M: Ludovic Desroches <ludovic.desroches@atmel.com> M: Ludovic Desroches <ludovic.desroches@atmel.com>
S: Maintained S: Maintained
......
...@@ -70,16 +70,6 @@ struct at91_cf_data { ...@@ -70,16 +70,6 @@ struct at91_cf_data {
extern void __init at91_add_device_cf(struct at91_cf_data *data); extern void __init at91_add_device_cf(struct at91_cf_data *data);
/* MMC / SD */ /* 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 */ /* atmel-mci platform config */
extern void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data); extern void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data);
......
...@@ -126,6 +126,7 @@ struct omap_mmc_platform_data { ...@@ -126,6 +126,7 @@ struct omap_mmc_platform_data {
/* we can put the features above into this variable */ /* we can put the features above into this variable */
#define HSMMC_HAS_PBIAS (1 << 0) #define HSMMC_HAS_PBIAS (1 << 0)
#define HSMMC_HAS_UPDATED_RESET (1 << 1) #define HSMMC_HAS_UPDATED_RESET (1 << 1)
#define HSMMC_HAS_HSPE_SUPPORT (1 << 2)
unsigned features; unsigned features;
int switch_pin; /* gpio (card detect) */ int switch_pin; /* gpio (card detect) */
......
...@@ -57,6 +57,7 @@ MODULE_ALIAS("mmc:block"); ...@@ -57,6 +57,7 @@ MODULE_ALIAS("mmc:block");
#define INAND_CMD38_ARG_SECERASE 0x80 #define INAND_CMD38_ARG_SECERASE 0x80
#define INAND_CMD38_ARG_SECTRIM1 0x81 #define INAND_CMD38_ARG_SECTRIM1 0x81
#define INAND_CMD38_ARG_SECTRIM2 0x88 #define INAND_CMD38_ARG_SECTRIM2 0x88
#define MMC_BLK_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
static DEFINE_MUTEX(block_mutex); static DEFINE_MUTEX(block_mutex);
...@@ -126,6 +127,10 @@ enum mmc_blk_status { ...@@ -126,6 +127,10 @@ enum mmc_blk_status {
module_param(perdev_minors, int, 0444); module_param(perdev_minors, int, 0444);
MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device"); 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) static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
{ {
struct mmc_blk_data *md; struct mmc_blk_data *md;
...@@ -357,6 +362,38 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( ...@@ -357,6 +362,38 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
return ERR_PTR(err); 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, static int mmc_blk_ioctl_cmd(struct block_device *bdev,
struct mmc_ioc_cmd __user *ic_ptr) struct mmc_ioc_cmd __user *ic_ptr)
{ {
...@@ -368,6 +405,8 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, ...@@ -368,6 +405,8 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
struct mmc_request mrq = {NULL}; struct mmc_request mrq = {NULL};
struct scatterlist sg; struct scatterlist sg;
int err; int err;
int is_rpmb = false;
u32 status = 0;
/* /*
* The caller must have CAP_SYS_RAWIO, and must be calling this on the * 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, ...@@ -387,6 +426,9 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
goto cmd_err; goto cmd_err;
} }
if (md->area_type & MMC_BLK_DATA_AREA_RPMB)
is_rpmb = true;
card = md->queue.card; card = md->queue.card;
if (IS_ERR(card)) { if (IS_ERR(card)) {
err = PTR_ERR(card); err = PTR_ERR(card);
...@@ -437,12 +479,23 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, ...@@ -437,12 +479,23 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
mmc_claim_host(card->host); mmc_claim_host(card->host);
err = mmc_blk_part_switch(card, md);
if (err)
goto cmd_rel_host;
if (idata->ic.is_acmd) { if (idata->ic.is_acmd) {
err = mmc_app_cmd(card->host, card); err = mmc_app_cmd(card->host, card);
if (err) if (err)
goto cmd_rel_host; 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); mmc_wait_for_req(card->host, &mrq);
if (cmd.error) { if (cmd.error) {
...@@ -478,6 +531,18 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, ...@@ -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: cmd_rel_host:
mmc_release_host(card->host); mmc_release_host(card->host);
...@@ -1034,6 +1099,9 @@ static int mmc_blk_err_check(struct mmc_card *card, ...@@ -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) { if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
u32 status; u32 status;
unsigned long timeout;
timeout = jiffies + msecs_to_jiffies(MMC_BLK_TIMEOUT_MS);
do { do {
int err = get_card_status(card, &status, 5); int err = get_card_status(card, &status, 5);
if (err) { if (err) {
...@@ -1041,6 +1109,17 @@ static int mmc_blk_err_check(struct mmc_card *card, ...@@ -1041,6 +1109,17 @@ static int mmc_blk_err_check(struct mmc_card *card,
req->rq_disk->disk_name, err); req->rq_disk->disk_name, err);
return MMC_BLK_CMD_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, * Some cards mishandle the status bits,
* so make sure to check both the busy * 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, ...@@ -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->queue = md->queue.queue;
md->disk->driverfs_dev = parent; md->disk->driverfs_dev = parent;
set_disk_ro(md->disk, md->read_only || default_ro); 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: * As discussed on lkml, GENHD_FL_REMOVABLE should:
......
...@@ -68,6 +68,16 @@ static int mmc_queue_thread(void *d) ...@@ -68,6 +68,16 @@ static int mmc_queue_thread(void *d)
if (req || mq->mqrq_prev->req) { if (req || mq->mqrq_prev->req) {
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
mq->issue_fn(mq, req); 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 { } else {
if (kthread_should_stop()) { if (kthread_should_stop()) {
set_current_state(TASK_RUNNING); set_current_state(TASK_RUNNING);
...@@ -77,13 +87,6 @@ static int mmc_queue_thread(void *d) ...@@ -77,13 +87,6 @@ static int mmc_queue_thread(void *d)
schedule(); schedule();
down(&mq->thread_sem); 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); } while (1);
up(&mq->thread_sem); up(&mq->thread_sem);
......
...@@ -225,8 +225,7 @@ static void mmc_release_card(struct device *dev) ...@@ -225,8 +225,7 @@ static void mmc_release_card(struct device *dev)
sdio_free_common_cis(card); sdio_free_common_cis(card);
if (card->info) kfree(card->info);
kfree(card->info);
kfree(card); kfree(card);
} }
......
...@@ -42,6 +42,9 @@ ...@@ -42,6 +42,9 @@
#include "sd_ops.h" #include "sd_ops.h"
#include "sdio_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 * Background operations can take a long time, depending on the housekeeping
* operations the card has to perform. * operations the card has to perform.
...@@ -1631,6 +1634,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, ...@@ -1631,6 +1634,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
{ {
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
unsigned int qty = 0; unsigned int qty = 0;
unsigned long timeout;
int err; int err;
/* /*
...@@ -1708,6 +1712,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, ...@@ -1708,6 +1712,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
if (mmc_host_is_spi(card->host)) if (mmc_host_is_spi(card->host))
goto out; goto out;
timeout = jiffies + msecs_to_jiffies(MMC_CORE_TIMEOUT_MS);
do { do {
memset(&cmd, 0, sizeof(struct mmc_command)); memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SEND_STATUS; cmd.opcode = MMC_SEND_STATUS;
...@@ -1721,8 +1726,19 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, ...@@ -1721,8 +1726,19 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
err = -EIO; err = -EIO;
goto out; 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) || } 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: out:
return err; return err;
} }
...@@ -1942,6 +1958,20 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen) ...@@ -1942,6 +1958,20 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
} }
EXPORT_SYMBOL(mmc_set_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) static void mmc_hw_reset_for_init(struct mmc_host *host)
{ {
if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset) if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
......
...@@ -144,6 +144,22 @@ static int mmc_ios_show(struct seq_file *s, void *data) ...@@ -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); 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; return 0;
} }
......
...@@ -239,7 +239,7 @@ static void mmc_select_card_type(struct mmc_card *card) ...@@ -239,7 +239,7 @@ static void mmc_select_card_type(struct mmc_card *card)
{ {
struct mmc_host *host = card->host; struct mmc_host *host = card->host;
u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK; 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; unsigned int hs_max_dtr = 0;
if (card_type & EXT_CSD_CARD_TYPE_26) 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) ...@@ -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.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
card->ext_csd.rst_n_function = ext_csd[EXT_CSD_RST_N_FUNCTION]; 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]; 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); ...@@ -615,6 +626,8 @@ MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
MMC_DEV_ATTR(enhanced_area_offset, "%llu\n", MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
card->ext_csd.enhanced_area_offset); card->ext_csd.enhanced_area_offset);
MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size); 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[] = { static struct attribute *mmc_std_attrs[] = {
&dev_attr_cid.attr, &dev_attr_cid.attr,
...@@ -630,6 +643,8 @@ static struct attribute *mmc_std_attrs[] = { ...@@ -630,6 +643,8 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_serial.attr, &dev_attr_serial.attr,
&dev_attr_enhanced_area_offset.attr, &dev_attr_enhanced_area_offset.attr,
&dev_attr_enhanced_area_size.attr, &dev_attr_enhanced_area_size.attr,
&dev_attr_raw_rpmb_size_mult.attr,
&dev_attr_rel_sectors.attr,
NULL, NULL,
}; };
...@@ -1051,6 +1066,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, ...@@ -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 (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
if (max_dtr > card->ext_csd.hs_max_dtr) if (max_dtr > card->ext_csd.hs_max_dtr)
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) { } else if (max_dtr > card->csd.max_dtr) {
max_dtr = card->csd.max_dtr; max_dtr = card->csd.max_dtr;
} }
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include "core.h" #include "core.h"
#include "mmc_ops.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) static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
{ {
int err; int err;
...@@ -409,6 +411,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, ...@@ -409,6 +411,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
{ {
int err; int err;
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
unsigned long timeout;
u32 status; u32 status;
BUG_ON(!card); BUG_ON(!card);
...@@ -437,6 +440,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, ...@@ -437,6 +440,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
return 0; return 0;
/* Must check status to be sure of no errors */ /* Must check status to be sure of no errors */
timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);
do { do {
err = mmc_send_status(card, &status); err = mmc_send_status(card, &status);
if (err) if (err)
...@@ -445,6 +449,13 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, ...@@ -445,6 +449,13 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
break; break;
if (mmc_host_is_spi(card->host)) if (mmc_host_is_spi(card->host))
break; 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); } while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
if (mmc_host_is_spi(card->host)) { if (mmc_host_is_spi(card->host)) {
......
...@@ -193,7 +193,21 @@ static int sdio_bus_remove(struct device *dev) ...@@ -193,7 +193,21 @@ static int sdio_bus_remove(struct device *dev)
} }
#ifdef CONFIG_PM #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 = { 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( SET_RUNTIME_PM_OPS(
pm_generic_runtime_suspend, pm_generic_runtime_suspend,
pm_generic_runtime_resume, pm_generic_runtime_resume,
...@@ -258,8 +272,7 @@ static void sdio_release_func(struct device *dev) ...@@ -258,8 +272,7 @@ static void sdio_release_func(struct device *dev)
sdio_free_func_cis(func); sdio_free_func_cis(func);
if (func->info) kfree(func->info);
kfree(func->info);
kfree(func); kfree(func);
} }
......
...@@ -188,8 +188,7 @@ EXPORT_SYMBOL_GPL(sdio_set_block_size); ...@@ -188,8 +188,7 @@ EXPORT_SYMBOL_GPL(sdio_set_block_size);
*/ */
static inline unsigned int sdio_max_byte_size(struct sdio_func *func) static inline unsigned int sdio_max_byte_size(struct sdio_func *func)
{ {
unsigned mval = min(func->card->host->max_seg_size, unsigned mval = func->card->host->max_blk_size;
func->card->host->max_blk_size);
if (mmc_blksz_for_byte_mode(func->card)) if (mmc_blksz_for_byte_mode(func->card))
mval = min(mval, func->cur_blksize); mval = min(mval, func->cur_blksize);
...@@ -311,11 +310,8 @@ static int sdio_io_rw_ext_helper(struct sdio_func *func, int write, ...@@ -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). */ /* Do the bulk of the transfer using block mode (if supported). */
if (func->card->cccr.multi_block && (size > sdio_max_byte_size(func))) { if (func->card->cccr.multi_block && (size > sdio_max_byte_size(func))) {
/* Blocks per command is limited by host count, host transfer /* Blocks per command is limited by host count, host transfer
* size (we only use a single sg entry) and the maximum for * size and the maximum for IO_RW_EXTENDED of 511 blocks. */
* IO_RW_EXTENDED of 511 blocks. */ max_blocks = min(func->card->host->max_blk_count, 511u);
max_blocks = min(func->card->host->max_blk_count,
func->card->host->max_seg_size / func->cur_blksize);
max_blocks = min(max_blocks, 511u);
while (remainder >= func->cur_blksize) { while (remainder >= func->cur_blksize) {
unsigned blocks; unsigned blocks;
......
...@@ -124,7 +124,10 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, ...@@ -124,7 +124,10 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
struct mmc_request mrq = {NULL}; struct mmc_request mrq = {NULL};
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
struct mmc_data data = {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(!card);
BUG_ON(fn > 7); BUG_ON(fn > 7);
...@@ -152,15 +155,36 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn, ...@@ -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 */ /* Code in host drivers/fwk assumes that "blocks" always is >=1 */
data.blocks = blocks ? blocks : 1; data.blocks = blocks ? blocks : 1;
data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; 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_set_data_timeout(&data, card);
mmc_wait_for_req(card->host, &mrq); mmc_wait_for_req(card->host, &mrq);
if (nents > 1)
sg_free_table(&sgtable);
if (cmd.error) if (cmd.error)
return cmd.error; return cmd.error;
if (data.error) if (data.error)
......
...@@ -27,7 +27,13 @@ struct mmc_gpio { ...@@ -27,7 +27,13 @@ struct mmc_gpio {
static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id) static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
{ {
/* Schedule a card detection after a debounce timeout */ /* 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; return IRQ_HANDLED;
} }
......
...@@ -270,26 +270,8 @@ config MMC_AU1X ...@@ -270,26 +270,8 @@ config MMC_AU1X
If unsure, say N. 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 config MMC_ATMELMCI
tristate "Atmel Multimedia Card Interface support" tristate "Atmel SD/MMC Driver (Multimedia Card Interface)"
depends on AVR32 || ARCH_AT91 depends on AVR32 || ARCH_AT91
help help
This selects the Atmel Multimedia Card Interface driver. If This selects the Atmel Multimedia Card Interface driver. If
...@@ -298,8 +280,6 @@ config MMC_ATMELMCI ...@@ -298,8 +280,6 @@ config MMC_ATMELMCI
If unsure, say N. If unsure, say N.
endchoice
config MMC_ATMELMCI_DMA config MMC_ATMELMCI_DMA
bool "Atmel MCI DMA support" bool "Atmel MCI DMA support"
depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE
...@@ -621,3 +601,14 @@ config MMC_USHC ...@@ -621,3 +601,14 @@ config MMC_USHC
Note: These controllers only support SDIO cards and do not Note: These controllers only support SDIO cards and do not
support MMC or SD memory cards. 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.
...@@ -17,7 +17,6 @@ obj-$(CONFIG_MMC_WBSD) += wbsd.o ...@@ -17,7 +17,6 @@ obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_OMAP) += omap.o obj-$(CONFIG_MMC_OMAP) += omap.o
obj-$(CONFIG_MMC_OMAP_HS) += omap_hsmmc.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_ATMELMCI) += atmel-mci.o
obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
obj-$(CONFIG_MMC_MSM) += msm_sdcc.o obj-$(CONFIG_MMC_MSM) += msm_sdcc.o
...@@ -45,6 +44,7 @@ obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o ...@@ -45,6 +44,7 @@ obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
obj-$(CONFIG_MMC_VUB300) += vub300.o obj-$(CONFIG_MMC_VUB300) += vub300.o
obj-$(CONFIG_MMC_USHC) += ushc.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_PLTFM) += sdhci-pltfm.o
obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o
......
This diff is collapsed.
/*
* 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
...@@ -134,7 +134,7 @@ static struct pci_driver dw_mci_pci_driver = { ...@@ -134,7 +134,7 @@ static struct pci_driver dw_mci_pci_driver = {
.name = "dw_mmc_pci", .name = "dw_mmc_pci",
.id_table = dw_mci_pci_id, .id_table = dw_mci_pci_id,
.probe = dw_mci_pci_probe, .probe = dw_mci_pci_probe,
.remove = dw_mci_pci_remove, .remove = __devexit_p(dw_mci_pci_remove),
.driver = { .driver = {
.pm = &dw_mci_pci_pmops .pm = &dw_mci_pci_pmops
}, },
......
...@@ -119,7 +119,8 @@ static const struct of_device_id dw_mci_pltfm_match[] = { ...@@ -119,7 +119,8 @@ static const struct of_device_id dw_mci_pltfm_match[] = {
MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match); MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
static struct platform_driver dw_mci_pltfm_driver = { 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 = { .driver = {
.name = "dw_mmc", .name = "dw_mmc",
.of_match_table = of_match_ptr(dw_mci_pltfm_match), .of_match_table = of_match_ptr(dw_mci_pltfm_match),
...@@ -127,18 +128,7 @@ static struct platform_driver dw_mci_pltfm_driver = { ...@@ -127,18 +128,7 @@ static struct platform_driver dw_mci_pltfm_driver = {
}, },
}; };
static int __init dw_mci_init(void) module_platform_driver(dw_mci_pltfm_driver);
{
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_DESCRIPTION("DW Multimedia Card Interface driver"); MODULE_DESCRIPTION("DW Multimedia Card Interface driver");
MODULE_AUTHOR("NXP Semiconductor VietNam"); MODULE_AUTHOR("NXP Semiconductor VietNam");
......
...@@ -232,7 +232,7 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) ...@@ -232,7 +232,7 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
{ {
struct mmc_data *data; struct mmc_data *data;
struct dw_mci_slot *slot = mmc_priv(mmc); 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; u32 cmdr;
cmd->error = -EINPROGRESS; cmd->error = -EINPROGRESS;
...@@ -617,13 +617,13 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg) ...@@ -617,13 +617,13 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
cmd, arg, cmd_status); 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; struct dw_mci *host = slot->host;
u32 div; u32 div;
u32 clk_en_a; u32 clk_en_a;
if (slot->clock != host->current_speed) { if (slot->clock != host->current_speed || force_clkinit) {
div = host->bus_hz / slot->clock; div = host->bus_hz / slot->clock;
if (host->bus_hz % slot->clock && 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, ...@@ -683,9 +683,6 @@ static void __dw_mci_start_request(struct dw_mci *host,
if (host->pdata->select_slot) if (host->pdata->select_slot)
host->pdata->select_slot(slot->id); host->pdata->select_slot(slot->id);
/* Slot specific timing and width adjustment */
dw_mci_setup_bus(slot);
host->cur_slot = slot; host->cur_slot = slot;
host->mrq = mrq; host->mrq = mrq;
...@@ -773,22 +770,19 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *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) 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_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; u32 regs;
/* set default 1 bit mode */
slot->ctype = SDMMC_CTYPE_1BIT;
switch (ios->bus_width) { switch (ios->bus_width) {
case MMC_BUS_WIDTH_1:
slot->ctype = SDMMC_CTYPE_1BIT;
break;
case MMC_BUS_WIDTH_4: case MMC_BUS_WIDTH_4:
slot->ctype = SDMMC_CTYPE_4BIT; slot->ctype = SDMMC_CTYPE_4BIT;
break; break;
case MMC_BUS_WIDTH_8: case MMC_BUS_WIDTH_8:
slot->ctype = SDMMC_CTYPE_8BIT; slot->ctype = SDMMC_CTYPE_8BIT;
break; break;
default:
/* set default 1 bit mode */
slot->ctype = SDMMC_CTYPE_1BIT;
} }
regs = mci_readl(slot->host, UHS_REG); 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) ...@@ -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) if (drv_data && drv_data->set_ios)
drv_data->set_ios(slot->host, ios); drv_data->set_ios(slot->host, ios);
/* Slot specific timing and width adjustment */
dw_mci_setup_bus(slot, false);
switch (ios->power_mode) { switch (ios->power_mode) {
case MMC_POWER_UP: case MMC_POWER_UP:
set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); 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) ...@@ -1817,7 +1814,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
{ {
struct mmc_host *mmc; struct mmc_host *mmc;
struct dw_mci_slot *slot; 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; int ctrl_id, ret;
u8 bus_width; u8 bus_width;
...@@ -1850,6 +1847,9 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) ...@@ -1850,6 +1847,9 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
if (host->pdata->caps) if (host->pdata->caps)
mmc->caps = 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) { if (host->dev->of_node) {
ctrl_id = of_alias_get_id(host->dev->of_node, "mshc"); ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
if (ctrl_id < 0) if (ctrl_id < 0)
...@@ -1911,7 +1911,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) ...@@ -1911,7 +1911,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
#endif /* CONFIG_MMC_DW_IDMAC */ #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)) { if (IS_ERR(host->vmmc)) {
pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc)); pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
host->vmmc = NULL; host->vmmc = NULL;
...@@ -1960,7 +1960,7 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) ...@@ -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) static void dw_mci_init_dma(struct dw_mci *host)
{ {
/* Alloc memory for sg translation */ /* 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); &host->sg_dma, GFP_KERNEL);
if (!host->sg_cpu) { if (!host->sg_cpu) {
dev_err(host->dev, "%s: could not alloc DMA memory\n", 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) ...@@ -2038,7 +2038,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
struct dw_mci_board *pdata; struct dw_mci_board *pdata;
struct device *dev = host->dev; struct device *dev = host->dev;
struct device_node *np = dev->of_node; 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; int idx, ret;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 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) ...@@ -2072,6 +2072,12 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
return ERR_PTR(ret); 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; return pdata;
} }
...@@ -2084,7 +2090,7 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) ...@@ -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) 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; int width, i, ret = 0;
u32 fifo_size; u32 fifo_size;
int init_slots = 0; int init_slots = 0;
...@@ -2103,26 +2109,24 @@ int dw_mci_probe(struct dw_mci *host) ...@@ -2103,26 +2109,24 @@ int dw_mci_probe(struct dw_mci *host)
return -ENODEV; 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)) { if (IS_ERR(host->biu_clk)) {
dev_dbg(host->dev, "biu clock not available\n"); dev_dbg(host->dev, "biu clock not available\n");
} else { } else {
ret = clk_prepare_enable(host->biu_clk); ret = clk_prepare_enable(host->biu_clk);
if (ret) { if (ret) {
dev_err(host->dev, "failed to enable biu clock\n"); dev_err(host->dev, "failed to enable biu clock\n");
clk_put(host->biu_clk);
return ret; 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)) { if (IS_ERR(host->ciu_clk)) {
dev_dbg(host->dev, "ciu clock not available\n"); dev_dbg(host->dev, "ciu clock not available\n");
} else { } else {
ret = clk_prepare_enable(host->ciu_clk); ret = clk_prepare_enable(host->ciu_clk);
if (ret) { if (ret) {
dev_err(host->dev, "failed to enable ciu clock\n"); dev_err(host->dev, "failed to enable ciu clock\n");
clk_put(host->ciu_clk);
goto err_clk_biu; goto err_clk_biu;
} }
} }
...@@ -2224,7 +2228,8 @@ int dw_mci_probe(struct dw_mci *host) ...@@ -2224,7 +2228,8 @@ int dw_mci_probe(struct dw_mci *host)
if (!host->card_workqueue) if (!host->card_workqueue)
goto err_dmaunmap; goto err_dmaunmap;
INIT_WORK(&host->card_work, dw_mci_work_routine_card); 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) if (ret)
goto err_workqueue; goto err_workqueue;
...@@ -2262,7 +2267,7 @@ int dw_mci_probe(struct dw_mci *host) ...@@ -2262,7 +2267,7 @@ int dw_mci_probe(struct dw_mci *host)
} else { } else {
dev_dbg(host->dev, "attempted to initialize %d slots, " dev_dbg(host->dev, "attempted to initialize %d slots, "
"but failed on all\n", host->num_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) ...@@ -2282,33 +2287,24 @@ int dw_mci_probe(struct dw_mci *host)
return 0; return 0;
err_init_slot:
free_irq(host->irq, host);
err_workqueue: err_workqueue:
destroy_workqueue(host->card_workqueue); destroy_workqueue(host->card_workqueue);
err_dmaunmap: err_dmaunmap:
if (host->use_dma && host->dma_ops->exit) if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host); 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_disable(host->vmmc);
regulator_put(host->vmmc);
}
err_clk_ciu: err_clk_ciu:
if (!IS_ERR(host->ciu_clk)) { if (!IS_ERR(host->ciu_clk))
clk_disable_unprepare(host->ciu_clk); clk_disable_unprepare(host->ciu_clk);
clk_put(host->ciu_clk);
}
err_clk_biu: err_clk_biu:
if (!IS_ERR(host->biu_clk)) { if (!IS_ERR(host->biu_clk))
clk_disable_unprepare(host->biu_clk); clk_disable_unprepare(host->biu_clk);
clk_put(host->biu_clk);
}
return ret; return ret;
} }
EXPORT_SYMBOL(dw_mci_probe); EXPORT_SYMBOL(dw_mci_probe);
...@@ -2330,24 +2326,19 @@ void dw_mci_remove(struct dw_mci *host) ...@@ -2330,24 +2326,19 @@ void dw_mci_remove(struct dw_mci *host)
mci_writel(host, CLKENA, 0); mci_writel(host, CLKENA, 0);
mci_writel(host, CLKSRC, 0); mci_writel(host, CLKSRC, 0);
free_irq(host->irq, host);
destroy_workqueue(host->card_workqueue); 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) if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host); host->dma_ops->exit(host);
if (host->vmmc) { if (host->vmmc)
regulator_disable(host->vmmc); regulator_disable(host->vmmc);
regulator_put(host->vmmc);
}
if (!IS_ERR(host->ciu_clk)) if (!IS_ERR(host->ciu_clk))
clk_disable_unprepare(host->ciu_clk); clk_disable_unprepare(host->ciu_clk);
if (!IS_ERR(host->biu_clk)) if (!IS_ERR(host->biu_clk))
clk_disable_unprepare(host->biu_clk); clk_disable_unprepare(host->biu_clk);
clk_put(host->ciu_clk);
clk_put(host->biu_clk);
} }
EXPORT_SYMBOL(dw_mci_remove); EXPORT_SYMBOL(dw_mci_remove);
...@@ -2411,6 +2402,11 @@ int dw_mci_resume(struct dw_mci *host) ...@@ -2411,6 +2402,11 @@ int dw_mci_resume(struct dw_mci *host)
struct dw_mci_slot *slot = host->slot[i]; struct dw_mci_slot *slot = host->slot[i];
if (!slot) if (!slot)
continue; 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); ret = mmc_resume_host(host->slot[i]->mmc);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -240,7 +240,7 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) ...@@ -240,7 +240,7 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
return 0; return 0;
for_each_sg(data->sg, sg, data->sg_len, i) { 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; host->do_dma = 0;
return 0; return 0;
} }
......
...@@ -43,7 +43,6 @@ ...@@ -43,7 +43,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/stmp_device.h> #include <linux/stmp_device.h>
#include <linux/mmc/mxs-mmc.h>
#include <linux/spi/mxs-spi.h> #include <linux/spi/mxs-spi.h>
#define DRIVER_NAME "mxs-mmc" #define DRIVER_NAME "mxs-mmc"
...@@ -593,13 +592,13 @@ static int mxs_mmc_probe(struct platform_device *pdev) ...@@ -593,13 +592,13 @@ static int mxs_mmc_probe(struct platform_device *pdev)
struct mxs_mmc_host *host; struct mxs_mmc_host *host;
struct mmc_host *mmc; struct mmc_host *mmc;
struct resource *iores, *dmares; struct resource *iores, *dmares;
struct mxs_mmc_platform_data *pdata;
struct pinctrl *pinctrl; struct pinctrl *pinctrl;
int ret = 0, irq_err, irq_dma; int ret = 0, irq_err, irq_dma;
dma_cap_mask_t mask; dma_cap_mask_t mask;
struct regulator *reg_vmmc; struct regulator *reg_vmmc;
enum of_gpio_flags flags; enum of_gpio_flags flags;
struct mxs_ssp *ssp; struct mxs_ssp *ssp;
u32 bus_width = 0;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
...@@ -682,25 +681,15 @@ static int mxs_mmc_probe(struct platform_device *pdev) ...@@ -682,25 +681,15 @@ static int mxs_mmc_probe(struct platform_device *pdev)
mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL; MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL;
pdata = mmc_dev(host->mmc)->platform_data; of_property_read_u32(np, "bus-width", &bus_width);
if (!pdata) { if (bus_width == 4)
u32 bus_width = 0; mmc->caps |= MMC_CAP_4_BIT_DATA;
of_property_read_u32(np, "bus-width", &bus_width); else if (bus_width == 8)
if (bus_width == 4) mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
mmc->caps |= MMC_CAP_4_BIT_DATA; host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags);
else if (bus_width == 8)
mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; if (flags & OF_GPIO_ACTIVE_LOW)
host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, host->wp_inverted = 1;
&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;
}
mmc->f_min = 400000; mmc->f_min = 400000;
mmc->f_max = 288000000; mmc->f_max = 288000000;
......
This diff is collapsed.
...@@ -19,20 +19,30 @@ ...@@ -19,20 +19,30 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <linux/err.h>
#include <linux/io.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h> #include <linux/gpio.h>
#include <linux/io.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h>
#include "sdhci-pltfm.h" #include "sdhci-pltfm.h"
struct sdhci_dove_priv { struct sdhci_dove_priv {
struct clk *clk; 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) static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)
{ {
u16 ret; u16 ret;
...@@ -50,16 +60,25 @@ static u16 sdhci_dove_readw(struct sdhci_host *host, int reg) ...@@ -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) 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; u32 ret;
ret = readl(host->ioaddr + reg);
switch (reg) { switch (reg) {
case SDHCI_CAPABILITIES: case SDHCI_CAPABILITIES:
ret = readl(host->ioaddr + reg);
/* Mask the support for 3.0V */ /* Mask the support for 3.0V */
ret &= ~SDHCI_CAN_VDD_300; ret &= ~SDHCI_CAN_VDD_300;
break; break;
default: case SDHCI_PRESENT_STATE:
ret = readl(host->ioaddr + reg); 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; return ret;
} }
...@@ -92,25 +111,70 @@ static int __devinit sdhci_dove_probe(struct platform_device *pdev) ...@@ -92,25 +111,70 @@ static int __devinit sdhci_dove_probe(struct platform_device *pdev)
return -ENOMEM; return -ENOMEM;
} }
priv->clk = clk_get(&pdev->dev, NULL); priv->clk = devm_clk_get(&pdev->dev, NULL);
if (!IS_ERR(priv->clk))
clk_prepare_enable(priv->clk);
ret = sdhci_pltfm_register(pdev, &sdhci_dove_pdata); if (pdev->dev.of_node) {
if (ret) priv->gpio_cd = of_get_named_gpio(pdev->dev.of_node,
goto sdhci_dove_register_fail; "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 = sdhci_priv(host);
pltfm_host->priv = priv; 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; return 0;
sdhci_dove_register_fail: err_request_irq:
if (!IS_ERR(priv->clk)) { sdhci_remove_host(host, 0);
err_sdhci_add:
if (!IS_ERR(priv->clk))
clk_disable_unprepare(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; return ret;
} }
...@@ -122,10 +186,14 @@ static int __devexit sdhci_dove_remove(struct platform_device *pdev) ...@@ -122,10 +186,14 @@ static int __devexit sdhci_dove_remove(struct platform_device *pdev)
sdhci_pltfm_unregister(pdev); sdhci_pltfm_unregister(pdev);
if (!IS_ERR(priv->clk)) { if (gpio_is_valid(priv->gpio_cd)) {
clk_disable_unprepare(priv->clk); free_irq(gpio_to_irq(priv->gpio_cd), host);
clk_put(priv->clk); gpio_free(priv->gpio_cd);
} }
if (!IS_ERR(priv->clk))
clk_disable_unprepare(priv->clk);
return 0; return 0;
} }
......
...@@ -456,10 +456,10 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) ...@@ -456,10 +456,10 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
pltfm_host = sdhci_priv(host); 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) { if (!imx_data) {
err = -ENOMEM; err = -ENOMEM;
goto err_imx_data; goto free_sdhci;
} }
if (of_id) if (of_id)
...@@ -470,19 +470,19 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) ...@@ -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"); imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(imx_data->clk_ipg)) { if (IS_ERR(imx_data->clk_ipg)) {
err = PTR_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"); imx_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
if (IS_ERR(imx_data->clk_ahb)) { if (IS_ERR(imx_data->clk_ahb)) {
err = PTR_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"); imx_data->clk_per = devm_clk_get(&pdev->dev, "per");
if (IS_ERR(imx_data->clk_per)) { if (IS_ERR(imx_data->clk_per)) {
err = PTR_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; pltfm_host->clk = imx_data->clk_per;
...@@ -494,7 +494,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) ...@@ -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); imx_data->pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(imx_data->pinctrl)) { if (IS_ERR(imx_data->pinctrl)) {
err = PTR_ERR(imx_data->pinctrl); err = PTR_ERR(imx_data->pinctrl);
goto pin_err; goto disable_clk;
} }
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
...@@ -519,7 +519,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) ...@@ -519,7 +519,7 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
if (!host->mmc->parent->platform_data) { if (!host->mmc->parent->platform_data) {
dev_err(mmc_dev(host->mmc), "no board data!\n"); dev_err(mmc_dev(host->mmc), "no board data!\n");
err = -EINVAL; err = -EINVAL;
goto no_board_data; goto disable_clk;
} }
imx_data->boarddata = *((struct esdhc_platform_data *) imx_data->boarddata = *((struct esdhc_platform_data *)
host->mmc->parent->platform_data); host->mmc->parent->platform_data);
...@@ -527,7 +527,8 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) ...@@ -527,7 +527,8 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
/* write_protect */ /* write_protect */
if (boarddata->wp_type == ESDHC_WP_GPIO) { 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) { if (err) {
dev_warn(mmc_dev(host->mmc), dev_warn(mmc_dev(host->mmc),
"no write-protect pin available!\n"); "no write-protect pin available!\n");
...@@ -543,19 +544,21 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) ...@@ -543,19 +544,21 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
switch (boarddata->cd_type) { switch (boarddata->cd_type) {
case ESDHC_CD_GPIO: 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) { if (err) {
dev_err(mmc_dev(host->mmc), dev_err(mmc_dev(host->mmc),
"no card-detect pin available!\n"); "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, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
mmc_hostname(host->mmc), host); mmc_hostname(host->mmc), host);
if (err) { if (err) {
dev_err(mmc_dev(host->mmc), "request irq error\n"); dev_err(mmc_dev(host->mmc), "request irq error\n");
goto no_card_detect_irq; goto disable_clk;
} }
/* fall through */ /* fall through */
...@@ -574,27 +577,15 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) ...@@ -574,27 +577,15 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev)
err = sdhci_add_host(host); err = sdhci_add_host(host);
if (err) if (err)
goto err_add_host; goto disable_clk;
return 0; return 0;
err_add_host: disable_clk:
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:
clk_disable_unprepare(imx_data->clk_per); clk_disable_unprepare(imx_data->clk_per);
clk_disable_unprepare(imx_data->clk_ipg); clk_disable_unprepare(imx_data->clk_ipg);
clk_disable_unprepare(imx_data->clk_ahb); clk_disable_unprepare(imx_data->clk_ahb);
err_clk_get: free_sdhci:
kfree(imx_data);
err_imx_data:
sdhci_pltfm_free(pdev); sdhci_pltfm_free(pdev);
return err; return err;
} }
...@@ -604,25 +595,14 @@ static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev) ...@@ -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_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv; 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); int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
sdhci_remove_host(host, dead); 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_per);
clk_disable_unprepare(imx_data->clk_ipg); clk_disable_unprepare(imx_data->clk_ipg);
clk_disable_unprepare(imx_data->clk_ahb); clk_disable_unprepare(imx_data->clk_ahb);
kfree(imx_data);
sdhci_pltfm_free(pdev); sdhci_pltfm_free(pdev);
return 0; return 0;
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "sdhci-esdhc.h" #include "sdhci-esdhc.h"
#define VENDOR_V_22 0x12 #define VENDOR_V_22 0x12
#define VENDOR_V_23 0x13
static u32 esdhc_readl(struct sdhci_host *host, int reg) static u32 esdhc_readl(struct sdhci_host *host, int reg)
{ {
u32 ret; u32 ret;
...@@ -85,6 +86,18 @@ static u8 esdhc_readb(struct sdhci_host *host, int reg) ...@@ -85,6 +86,18 @@ static u8 esdhc_readb(struct sdhci_host *host, int reg)
return ret; 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) static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
{ {
if (reg == SDHCI_BLOCK_SIZE) { if (reg == SDHCI_BLOCK_SIZE) {
...@@ -121,6 +134,41 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg) ...@@ -121,6 +134,41 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
sdhci_be32bs_writeb(host, val, 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) static int esdhc_of_enable_dma(struct sdhci_host *host)
{ {
setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP); setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
...@@ -177,13 +225,16 @@ static void esdhc_of_platform_init(struct sdhci_host *host) ...@@ -177,13 +225,16 @@ static void esdhc_of_platform_init(struct sdhci_host *host)
vvn = (vvn & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT; vvn = (vvn & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
if (vvn == VENDOR_V_22) if (vvn == VENDOR_V_22)
host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23; 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 = { static struct sdhci_ops sdhci_esdhc_ops = {
.read_l = esdhc_readl, .read_l = esdhc_readl,
.read_w = esdhc_readw, .read_w = esdhc_readw,
.read_b = esdhc_readb, .read_b = esdhc_readb,
.write_l = sdhci_be32bs_writel, .write_l = esdhc_writel,
.write_w = esdhc_writew, .write_w = esdhc_writew,
.write_b = esdhc_writeb, .write_b = esdhc_writeb,
.set_clock = esdhc_of_set_clock, .set_clock = esdhc_of_set_clock,
...@@ -195,6 +246,7 @@ static struct sdhci_ops sdhci_esdhc_ops = { ...@@ -195,6 +246,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.platform_suspend = esdhc_of_suspend, .platform_suspend = esdhc_of_suspend,
.platform_resume = esdhc_of_resume, .platform_resume = esdhc_of_resume,
#endif #endif
.adma_workaround = esdhci_of_adma_workaround,
}; };
static struct sdhci_pltfm_data sdhci_esdhc_pdata = { static struct sdhci_pltfm_data sdhci_esdhc_pdata = {
......
...@@ -114,6 +114,7 @@ static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot) ...@@ -114,6 +114,7 @@ static int ricoh_mmc_probe_slot(struct sdhci_pci_slot *slot)
SDHCI_TIMEOUT_CLK_UNIT | SDHCI_TIMEOUT_CLK_UNIT |
SDHCI_CAN_VDD_330 | SDHCI_CAN_VDD_330 |
SDHCI_CAN_DO_HISPD |
SDHCI_CAN_DO_SDMA; SDHCI_CAN_DO_SDMA;
return 0; return 0;
} }
......
...@@ -78,6 +78,9 @@ void sdhci_get_of_property(struct platform_device *pdev) ...@@ -78,6 +78,9 @@ void sdhci_get_of_property(struct platform_device *pdev)
if (of_get_property(np, "broken-cd", NULL)) if (of_get_property(np, "broken-cd", NULL))
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; 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")) if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_DMA; host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
...@@ -89,6 +92,12 @@ void sdhci_get_of_property(struct platform_device *pdev) ...@@ -89,6 +92,12 @@ void sdhci_get_of_property(struct platform_device *pdev)
clk = of_get_property(np, "clock-frequency", &size); clk = of_get_property(np, "clock-frequency", &size);
if (clk && size == sizeof(*clk) && *clk) if (clk && size == sizeof(*clk) && *clk)
pltfm_host->clock = be32_to_cpup(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 #else
......
...@@ -163,10 +163,18 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) ...@@ -163,10 +163,18 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
return 0; 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 = { static struct sdhci_ops pxav3_sdhci_ops = {
.platform_reset_exit = pxav3_set_private_registers, .platform_reset_exit = pxav3_set_private_registers,
.set_uhs_signaling = pxav3_set_uhs_signaling, .set_uhs_signaling = pxav3_set_uhs_signaling,
.platform_send_init_74_clocks = pxav3_gen_init_74_clocks, .platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
.get_max_clock = pxav3_get_max_clock,
}; };
#ifdef CONFIG_OF #ifdef CONFIG_OF
...@@ -249,7 +257,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev) ...@@ -249,7 +257,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
| SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | 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 */ /* enable 1/8V DDR capable */
host->mmc->caps |= MMC_CAP_1_8V_DDR; host->mmc->caps |= MMC_CAP_1_8V_DDR;
...@@ -271,6 +280,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev) ...@@ -271,6 +280,8 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
if (pdata->quirks) if (pdata->quirks)
host->quirks |= pdata->quirks; host->quirks |= pdata->quirks;
if (pdata->quirks2)
host->quirks2 |= pdata->quirks2;
if (pdata->host_caps) if (pdata->host_caps)
host->mmc->caps |= pdata->host_caps; host->mmc->caps |= pdata->host_caps;
if (pdata->host_caps2) if (pdata->host_caps2)
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/pinctrl/consumer.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
...@@ -57,6 +58,7 @@ struct sdhci_s3c { ...@@ -57,6 +58,7 @@ struct sdhci_s3c {
int ext_cd_irq; int ext_cd_irq;
int ext_cd_gpio; int ext_cd_gpio;
int *gpios; int *gpios;
struct pinctrl *pctrl;
struct clk *clk_io; struct clk *clk_io;
struct clk *clk_bus[MAX_BUS_CLK]; struct clk *clk_bus[MAX_BUS_CLK];
...@@ -373,7 +375,9 @@ static struct sdhci_ops sdhci_s3c_ops = { ...@@ -373,7 +375,9 @@ static struct sdhci_ops sdhci_s3c_ops = {
static void sdhci_s3c_notify_change(struct platform_device *dev, int state) static void sdhci_s3c_notify_change(struct platform_device *dev, int state)
{ {
struct sdhci_host *host = platform_get_drvdata(dev); struct sdhci_host *host = platform_get_drvdata(dev);
#ifdef CONFIG_PM_RUNTIME
struct sdhci_s3c *sc = sdhci_priv(host); struct sdhci_s3c *sc = sdhci_priv(host);
#endif
unsigned long flags; unsigned long flags;
if (host) { if (host) {
...@@ -413,7 +417,7 @@ static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc) ...@@ -413,7 +417,7 @@ static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc)
struct s3c_sdhci_platdata *pdata = sc->pdata; struct s3c_sdhci_platdata *pdata = sc->pdata;
struct device *dev = &sc->pdev->dev; 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_gpio = pdata->ext_cd_gpio;
sc->ext_cd_irq = gpio_to_irq(pdata->ext_cd_gpio); sc->ext_cd_irq = gpio_to_irq(pdata->ext_cd_gpio);
if (sc->ext_cd_irq && if (sc->ext_cd_irq &&
...@@ -456,12 +460,12 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev, ...@@ -456,12 +460,12 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
return -ENOMEM; return -ENOMEM;
/* get the card detection method */ /* 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; pdata->cd_type = S3C_SDHCI_CD_NONE;
goto setup_bus; 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; pdata->cd_type = S3C_SDHCI_CD_PERMANENT;
goto setup_bus; goto setup_bus;
} }
...@@ -484,8 +488,9 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev, ...@@ -484,8 +488,9 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
return -EINVAL; return -EINVAL;
} }
dev_info(dev, "assuming no card detect line available\n"); /* assuming internal card detect that will be configured by pinctrl */
pdata->cd_type = S3C_SDHCI_CD_NONE; pdata->cd_type = S3C_SDHCI_CD_INTERNAL;
goto setup_bus;
found_cd: found_cd:
if (pdata->cd_type == S3C_SDHCI_CD_GPIO) { if (pdata->cd_type == S3C_SDHCI_CD_GPIO) {
...@@ -494,7 +499,7 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev, ...@@ -494,7 +499,7 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
if (of_get_property(node, "cd-inverted", NULL)) if (of_get_property(node, "cd-inverted", NULL))
pdata->ext_cd_gpio_invert = 1; pdata->ext_cd_gpio_invert = 1;
} else if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { } 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) { if (ret) {
dev_err(dev, "card detect gpio request failed\n"); dev_err(dev, "card detect gpio request failed\n");
return -EINVAL; return -EINVAL;
...@@ -503,33 +508,28 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev, ...@@ -503,33 +508,28 @@ static int __devinit sdhci_s3c_parse_dt(struct device *dev,
} }
setup_bus: setup_bus:
if (!IS_ERR(ourhost->pctrl))
return 0;
/* get the gpios for command, clock and data lines */ /* get the gpios for command, clock and data lines */
for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) { for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) {
gpio = of_get_gpio(node, cnt); gpio = of_get_gpio(node, cnt);
if (!gpio_is_valid(gpio)) { if (!gpio_is_valid(gpio)) {
dev_err(dev, "invalid gpio[%d]\n", cnt); dev_err(dev, "invalid gpio[%d]\n", cnt);
goto err_free_dt_cd_gpio; return -EINVAL;
} }
ourhost->gpios[cnt] = gpio; ourhost->gpios[cnt] = gpio;
} }
for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) { 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) { if (ret) {
dev_err(dev, "gpio[%d] request failed\n", cnt); dev_err(dev, "gpio[%d] request failed\n", cnt);
goto err_free_dt_gpios; return -EINVAL;
} }
} }
return 0; 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 #else
static int __devinit sdhci_s3c_parse_dt(struct device *dev, static int __devinit sdhci_s3c_parse_dt(struct device *dev,
...@@ -586,13 +586,15 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) ...@@ -586,13 +586,15 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) { if (!pdata) {
ret = -ENOMEM; ret = -ENOMEM;
goto err_pdata; goto err_pdata_io_clk;
} }
sc->pctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (pdev->dev.of_node) { if (pdev->dev.of_node) {
ret = sdhci_s3c_parse_dt(&pdev->dev, host, pdata); ret = sdhci_s3c_parse_dt(&pdev->dev, host, pdata);
if (ret) if (ret)
goto err_pdata; goto err_pdata_io_clk;
} else { } else {
memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata)); memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));
sc->ext_cd_gpio = -1; /* invalid gpio number */ sc->ext_cd_gpio = -1; /* invalid gpio number */
...@@ -610,7 +612,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) ...@@ -610,7 +612,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
if (IS_ERR(sc->clk_io)) { if (IS_ERR(sc->clk_io)) {
dev_err(dev, "failed to get io clock\n"); dev_err(dev, "failed to get io clock\n");
ret = PTR_ERR(sc->clk_io); 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. */ /* 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) ...@@ -773,13 +775,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
clk_disable_unprepare(sc->clk_io); clk_disable_unprepare(sc->clk_io);
clk_put(sc->clk_io); clk_put(sc->clk_io);
err_io_clk: err_pdata_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:
sdhci_free_host(host); sdhci_free_host(host);
return ret; return ret;
...@@ -798,9 +794,6 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev) ...@@ -798,9 +794,6 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
if (sc->ext_cd_irq) if (sc->ext_cd_irq)
free_irq(sc->ext_cd_irq, sc); 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 #ifdef CONFIG_PM_RUNTIME
if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL) if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL)
clk_prepare_enable(sc->clk_io); clk_prepare_enable(sc->clk_io);
...@@ -821,11 +814,6 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev) ...@@ -821,11 +814,6 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
clk_disable_unprepare(sc->clk_io); clk_disable_unprepare(sc->clk_io);
clk_put(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); sdhci_free_host(host);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
......
...@@ -146,6 +146,11 @@ static int __devinit sdhci_probe(struct platform_device *pdev) ...@@ -146,6 +146,11 @@ static int __devinit sdhci_probe(struct platform_device *pdev)
goto put_clk; 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) { if (np) {
sdhci->data = sdhci_probe_config_dt(pdev); sdhci->data = sdhci_probe_config_dt(pdev);
if (IS_ERR(sdhci->data)) { if (IS_ERR(sdhci->data)) {
...@@ -297,7 +302,7 @@ static int sdhci_suspend(struct device *dev) ...@@ -297,7 +302,7 @@ static int sdhci_suspend(struct device *dev)
ret = sdhci_suspend_host(host); ret = sdhci_suspend_host(host);
if (!ret) if (!ret)
clk_disable_unprepare(sdhci->clk); clk_disable(sdhci->clk);
return ret; return ret;
} }
...@@ -308,7 +313,7 @@ static int sdhci_resume(struct device *dev) ...@@ -308,7 +313,7 @@ static int sdhci_resume(struct device *dev)
struct spear_sdhci *sdhci = dev_get_platdata(dev); struct spear_sdhci *sdhci = dev_get_platdata(dev);
int ret; int ret;
ret = clk_prepare_enable(sdhci->clk); ret = clk_enable(sdhci->clk);
if (ret) { if (ret) {
dev_dbg(dev, "Resume: Error enabling clock\n"); dev_dbg(dev, "Resume: Error enabling clock\n");
return ret; return ret;
......
...@@ -1618,7 +1618,7 @@ static int sdhci_do_3_3v_signal_voltage_switch(struct sdhci_host *host, ...@@ -1618,7 +1618,7 @@ static int sdhci_do_3_3v_signal_voltage_switch(struct sdhci_host *host,
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
if (host->vqmmc) { if (host->vqmmc) {
ret = regulator_set_voltage(host->vqmmc, 3300000, 3300000); ret = regulator_set_voltage(host->vqmmc, 2700000, 3600000);
if (ret) { if (ret) {
pr_warning("%s: Switching to 3.3V signalling voltage " pr_warning("%s: Switching to 3.3V signalling voltage "
" failed\n", mmc_hostname(host->mmc)); " failed\n", mmc_hostname(host->mmc));
...@@ -1662,7 +1662,7 @@ static int sdhci_do_1_8v_signal_voltage_switch(struct sdhci_host *host, ...@@ -1662,7 +1662,7 @@ static int sdhci_do_1_8v_signal_voltage_switch(struct sdhci_host *host,
*/ */
if (host->vqmmc) if (host->vqmmc)
ret = regulator_set_voltage(host->vqmmc, ret = regulator_set_voltage(host->vqmmc,
1800000, 1800000); 1700000, 1950000);
else else
ret = 0; ret = 0;
...@@ -1994,30 +1994,11 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) ...@@ -1994,30 +1994,11 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable)
sdhci_runtime_pm_put(host); sdhci_runtime_pm_put(host);
} }
static const struct mmc_host_ops sdhci_ops = { static void sdhci_card_event(struct mmc_host *mmc)
.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)
{ {
struct sdhci_host *host; struct sdhci_host *host = mmc_priv(mmc);
unsigned long flags; unsigned long flags;
host = (struct sdhci_host*)param;
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
/* Check host->mrq first in case we are runtime suspended */ /* Check host->mrq first in case we are runtime suspended */
...@@ -2036,6 +2017,31 @@ static void sdhci_tasklet_card(unsigned long param) ...@@ -2036,6 +2017,31 @@ static void sdhci_tasklet_card(unsigned long param)
} }
spin_unlock_irqrestore(&host->lock, flags); 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)); mmc_detect_change(host->mmc, msecs_to_jiffies(200));
} }
...@@ -2282,6 +2288,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) ...@@ -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)); pr_err("%s: ADMA error\n", mmc_hostname(host->mmc));
sdhci_show_adma_error(host); sdhci_show_adma_error(host);
host->data->error = -EIO; host->data->error = -EIO;
if (host->ops->adma_workaround)
host->ops->adma_workaround(host, intmask);
} }
if (host->data->error) if (host->data->error)
...@@ -2858,10 +2866,16 @@ int sdhci_add_host(struct sdhci_host *host) ...@@ -2858,10 +2866,16 @@ int sdhci_add_host(struct sdhci_host *host)
mmc_hostname(mmc)); mmc_hostname(mmc));
host->vqmmc = NULL; host->vqmmc = NULL;
} }
} } else {
else if (regulator_is_supported_voltage(host->vqmmc, 1800000, 1800000))
regulator_enable(host->vqmmc); 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 | caps[1] &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
SDHCI_SUPPORT_DDR50); SDHCI_SUPPORT_DDR50);
...@@ -2919,21 +2933,18 @@ int sdhci_add_host(struct sdhci_host *host) ...@@ -2919,21 +2933,18 @@ int sdhci_add_host(struct sdhci_host *host)
mmc_hostname(mmc)); mmc_hostname(mmc));
host->vmmc = NULL; host->vmmc = NULL;
} }
} else }
regulator_enable(host->vmmc);
#ifdef CONFIG_REGULATOR #ifdef CONFIG_REGULATOR
if (host->vmmc) { if (host->vmmc) {
ret = regulator_is_supported_voltage(host->vmmc, 3300000, ret = regulator_is_supported_voltage(host->vmmc, 2700000,
3300000); 3600000);
if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_330))) if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_330)))
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))) if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_300)))
caps[0] &= ~SDHCI_CAN_VDD_300; caps[0] &= ~SDHCI_CAN_VDD_300;
ret = regulator_is_supported_voltage(host->vmmc, 1800000, ret = regulator_is_supported_voltage(host->vmmc, 1700000,
1800000); 1950000);
if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_180))) if ((ret <= 0) || (!(caps[0] & SDHCI_CAN_VDD_180)))
caps[0] &= ~SDHCI_CAN_VDD_180; caps[0] &= ~SDHCI_CAN_VDD_180;
} }
......
...@@ -120,6 +120,7 @@ ...@@ -120,6 +120,7 @@
#define SDHCI_SIGNAL_ENABLE 0x38 #define SDHCI_SIGNAL_ENABLE 0x38
#define SDHCI_INT_RESPONSE 0x00000001 #define SDHCI_INT_RESPONSE 0x00000001
#define SDHCI_INT_DATA_END 0x00000002 #define SDHCI_INT_DATA_END 0x00000002
#define SDHCI_INT_BLK_GAP 0x00000004
#define SDHCI_INT_DMA_END 0x00000008 #define SDHCI_INT_DMA_END 0x00000008
#define SDHCI_INT_SPACE_AVAIL 0x00000010 #define SDHCI_INT_SPACE_AVAIL 0x00000010
#define SDHCI_INT_DATA_AVAIL 0x00000020 #define SDHCI_INT_DATA_AVAIL 0x00000020
...@@ -146,7 +147,8 @@ ...@@ -146,7 +147,8 @@
#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \ #define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \ SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \ 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_INT_ALL_MASK ((unsigned int)-1)
#define SDHCI_ACMD12_ERR 0x3C #define SDHCI_ACMD12_ERR 0x3C
...@@ -278,6 +280,7 @@ struct sdhci_ops { ...@@ -278,6 +280,7 @@ struct sdhci_ops {
void (*hw_reset)(struct sdhci_host *host); void (*hw_reset)(struct sdhci_host *host);
void (*platform_suspend)(struct sdhci_host *host); void (*platform_suspend)(struct sdhci_host *host);
void (*platform_resume)(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); void (*platform_init)(struct sdhci_host *host);
}; };
......
...@@ -1306,7 +1306,6 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) ...@@ -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 sh_mmcif_plat_data *pd = pdev->dev.platform_data;
struct resource *res; struct resource *res;
void __iomem *reg; void __iomem *reg;
char clk_name[8];
irq[0] = platform_get_irq(pdev, 0); irq[0] = platform_get_irq(pdev, 0);
irq[1] = platform_get_irq(pdev, 1); irq[1] = platform_get_irq(pdev, 1);
...@@ -1356,11 +1355,10 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev) ...@@ -1356,11 +1355,10 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
host->power = false; host->power = false;
snprintf(clk_name, sizeof(clk_name), "mmc%d", pdev->id); host->hclk = clk_get(&pdev->dev, NULL);
host->hclk = clk_get(&pdev->dev, clk_name);
if (IS_ERR(host->hclk)) { if (IS_ERR(host->hclk)) {
ret = PTR_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; goto eclkget;
} }
ret = sh_mmcif_clk_update(host); ret = sh_mmcif_clk_update(host);
......
...@@ -123,7 +123,6 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) ...@@ -123,7 +123,6 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
struct tmio_mmc_data *mmc_data; struct tmio_mmc_data *mmc_data;
struct sh_mobile_sdhi_info *p = pdev->dev.platform_data; struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
struct tmio_mmc_host *host; struct tmio_mmc_host *host;
char clk_name[8];
int irq, ret, i = 0; int irq, ret, i = 0;
bool multiplexed_isr = true; bool multiplexed_isr = true;
...@@ -144,11 +143,10 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) ...@@ -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, NULL);
priv->clk = clk_get(&pdev->dev, clk_name);
if (IS_ERR(priv->clk)) { if (IS_ERR(priv->clk)) {
dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
ret = PTR_ERR(priv->clk); ret = PTR_ERR(priv->clk);
dev_err(&pdev->dev, "cannot get clock: %d\n", ret);
goto eclkget; goto eclkget;
} }
...@@ -250,7 +248,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev) ...@@ -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", dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n",
mmc_hostname(host->mmc), (unsigned long) mmc_hostname(host->mmc), (unsigned long)
(platform_get_resource(pdev, IORESOURCE_MEM, 0)->start), (platform_get_resource(pdev, IORESOURCE_MEM, 0)->start),
mmc_data->hclk / 1000000); host->mmc->f_max / 1000000);
return ret; return ret;
......
...@@ -2362,6 +2362,7 @@ static int vub300_probe(struct usb_interface *interface, ...@@ -2362,6 +2362,7 @@ static int vub300_probe(struct usb_interface *interface,
error1: error1:
usb_free_urb(command_out_urb); usb_free_urb(command_out_urb);
error0: error0:
usb_put_dev(udev);
return retval; return retval;
} }
......
This diff is collapsed.
...@@ -85,6 +85,7 @@ struct mmc_ext_csd { ...@@ -85,6 +85,7 @@ struct mmc_ext_csd {
bool boot_ro_lockable; bool boot_ro_lockable;
u8 raw_exception_status; /* 53 */ u8 raw_exception_status; /* 53 */
u8 raw_partition_support; /* 160 */ u8 raw_partition_support; /* 160 */
u8 raw_rpmb_size_mult; /* 168 */
u8 raw_erased_mem_count; /* 181 */ u8 raw_erased_mem_count; /* 181 */
u8 raw_ext_csd_structure; /* 194 */ u8 raw_ext_csd_structure; /* 194 */
u8 raw_card_type; /* 196 */ u8 raw_card_type; /* 196 */
...@@ -206,6 +207,7 @@ struct mmc_part { ...@@ -206,6 +207,7 @@ struct mmc_part {
#define MMC_BLK_DATA_AREA_MAIN (1<<0) #define MMC_BLK_DATA_AREA_MAIN (1<<0)
#define MMC_BLK_DATA_AREA_BOOT (1<<1) #define MMC_BLK_DATA_AREA_BOOT (1<<1)
#define MMC_BLK_DATA_AREA_GP (1<<2) #define MMC_BLK_DATA_AREA_GP (1<<2)
#define MMC_BLK_DATA_AREA_RPMB (1<<3)
}; };
/* /*
......
...@@ -170,6 +170,8 @@ extern int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from, ...@@ -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 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_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(struct mmc_host *host);
extern int mmc_hw_reset_check(struct mmc_host *host); extern int mmc_hw_reset_check(struct mmc_host *host);
extern int mmc_can_reset(struct mmc_card *card); extern int mmc_can_reset(struct mmc_card *card);
......
...@@ -229,8 +229,9 @@ struct dw_mci_board { ...@@ -229,8 +229,9 @@ struct dw_mci_board {
u32 quirks; /* Workaround / Quirk flags */ u32 quirks; /* Workaround / Quirk flags */
unsigned int bus_hz; /* Clock speed at the cclk_in pad */ unsigned int bus_hz; /* Clock speed at the cclk_in pad */
unsigned int caps; /* Capabilities */ u32 caps; /* Capabilities */
unsigned int caps2; /* More capabilities */ u32 caps2; /* More capabilities */
u32 pm_caps; /* PM capabilities */
/* /*
* Override fifo depth. If 0, autodetect it from the FIFOTH register, * Override fifo depth. If 0, autodetect it from the FIFOTH register,
* but note that this may not be reliable after a bootloader has used * but note that this may not be reliable after a bootloader has used
......
...@@ -53,12 +53,12 @@ struct mmc_ios { ...@@ -53,12 +53,12 @@ struct mmc_ios {
#define MMC_TIMING_LEGACY 0 #define MMC_TIMING_LEGACY 0
#define MMC_TIMING_MMC_HS 1 #define MMC_TIMING_MMC_HS 1
#define MMC_TIMING_SD_HS 2 #define MMC_TIMING_SD_HS 2
#define MMC_TIMING_UHS_SDR12 MMC_TIMING_LEGACY #define MMC_TIMING_UHS_SDR12 3
#define MMC_TIMING_UHS_SDR25 MMC_TIMING_SD_HS #define MMC_TIMING_UHS_SDR25 4
#define MMC_TIMING_UHS_SDR50 3 #define MMC_TIMING_UHS_SDR50 5
#define MMC_TIMING_UHS_SDR104 4 #define MMC_TIMING_UHS_SDR104 6
#define MMC_TIMING_UHS_DDR50 5 #define MMC_TIMING_UHS_DDR50 7
#define MMC_TIMING_MMC_HS200 6 #define MMC_TIMING_MMC_HS200 8
#define MMC_SDR_MODE 0 #define MMC_SDR_MODE 0
#define MMC_1_2V_DDR_MODE 1 #define MMC_1_2V_DDR_MODE 1
...@@ -136,6 +136,7 @@ struct mmc_host_ops { ...@@ -136,6 +136,7 @@ struct mmc_host_ops {
void (*enable_preset_value)(struct mmc_host *host, bool enable); void (*enable_preset_value)(struct mmc_host *host, bool enable);
int (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv); int (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
void (*hw_reset)(struct mmc_host *host); void (*hw_reset)(struct mmc_host *host);
void (*card_event)(struct mmc_host *host);
}; };
struct mmc_card; struct mmc_card;
...@@ -211,7 +212,7 @@ struct mmc_host { ...@@ -211,7 +212,7 @@ struct mmc_host {
#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */ #define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */
#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */ #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_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 */ #define MMC_CAP_MMC_HIGHSPEED (1 << 1) /* Can do MMC high-speed timing */
...@@ -241,7 +242,7 @@ struct mmc_host { ...@@ -241,7 +242,7 @@ struct mmc_host {
#define MMC_CAP_CMD23 (1 << 30) /* CMD23 supported. */ #define MMC_CAP_CMD23 (1 << 30) /* CMD23 supported. */
#define MMC_CAP_HW_RESET (1 << 31) /* Hardware reset */ #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_BOOTPART_NOACC (1 << 0) /* Boot partition no access */
#define MMC_CAP2_CACHE_CTRL (1 << 1) /* Allow cache control */ #define MMC_CAP2_CACHE_CTRL (1 << 1) /* Allow cache control */
......
...@@ -286,6 +286,7 @@ struct _mmc_csd { ...@@ -286,6 +286,7 @@ struct _mmc_csd {
#define EXT_CSD_BKOPS_START 164 /* W */ #define EXT_CSD_BKOPS_START 164 /* W */
#define EXT_CSD_SANITIZE_START 165 /* W */ #define EXT_CSD_SANITIZE_START 165 /* W */
#define EXT_CSD_WR_REL_PARAM 166 /* RO */ #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_BOOT_WP 173 /* R/W */
#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ #define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */
#define EXT_CSD_PART_CONFIG 179 /* R/W */ #define EXT_CSD_PART_CONFIG 179 /* R/W */
...@@ -339,6 +340,7 @@ struct _mmc_csd { ...@@ -339,6 +340,7 @@ struct _mmc_csd {
#define EXT_CSD_PART_CONFIG_ACC_MASK (0x7) #define EXT_CSD_PART_CONFIG_ACC_MASK (0x7)
#define EXT_CSD_PART_CONFIG_ACC_BOOT0 (0x1) #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_CONFIG_ACC_GP0 (0x4)
#define EXT_CSD_PART_SUPPORT_PART_EN (0x1) #define EXT_CSD_PART_SUPPORT_PART_EN (0x1)
......
/*
* 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__ */
...@@ -92,6 +92,8 @@ struct sdhci_host { ...@@ -92,6 +92,8 @@ struct sdhci_host {
#define SDHCI_QUIRK2_HOST_OFF_CARD_ON (1<<0) #define SDHCI_QUIRK2_HOST_OFF_CARD_ON (1<<0)
#define SDHCI_QUIRK2_HOST_NO_CMD23 (1<<1) #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 */ int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */ void __iomem *ioaddr; /* Mapped address */
...@@ -158,8 +160,8 @@ struct sdhci_host { ...@@ -158,8 +160,8 @@ struct sdhci_host {
struct timer_list timer; /* Timer for timeouts */ struct timer_list timer; /* Timer for timeouts */
unsigned int caps; /* Alternative CAPABILITY_0 */ u32 caps; /* Alternative CAPABILITY_0 */
unsigned int caps1; /* Alternative CAPABILITY_1 */ u32 caps1; /* Alternative CAPABILITY_1 */
unsigned int ocr_avail_sdio; /* OCR bit masks */ unsigned int ocr_avail_sdio; /* OCR bit masks */
unsigned int ocr_avail_sd; unsigned int ocr_avail_sd;
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
* @max_speed: the maximum speed supported * @max_speed: the maximum speed supported
* @host_caps: Standard MMC host capabilities bit field. * @host_caps: Standard MMC host capabilities bit field.
* @quirks: quirks of platfrom * @quirks: quirks of platfrom
* @quirks2: quirks2 of platfrom
* @pm_caps: pm_caps of platfrom * @pm_caps: pm_caps of platfrom
*/ */
struct sdhci_pxa_platdata { struct sdhci_pxa_platdata {
...@@ -48,9 +49,10 @@ struct sdhci_pxa_platdata { ...@@ -48,9 +49,10 @@ struct sdhci_pxa_platdata {
unsigned int ext_cd_gpio; unsigned int ext_cd_gpio;
bool ext_cd_gpio_invert; bool ext_cd_gpio_invert;
unsigned int max_speed; unsigned int max_speed;
unsigned int host_caps; u32 host_caps;
unsigned int host_caps2; u32 host_caps2;
unsigned int quirks; unsigned int quirks;
unsigned int quirks2;
unsigned int pm_caps; unsigned int pm_caps;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment