Commit 17319295 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull MMC update from Chris Ball:
 "MMC highlights for 3.10:

  Core:
   - Introduce MMC_CAP2_NO_PRESCAN_POWERUP to allow skipping
     mmc_power_up() at boot/initialization time if it's already
     happened, for performance (faster boot time) reasons.
   - Fix a bit width test failure that resulted in old eMMC cards being
     put into 1-bit mode when 4-bit mode was available.
   - Expose fwrev/hwrev for MMCv4 parts.
   - Improve card removal logic in the case where the card's removed
     slowly; we were missing card removal events if the card retained
     contact with the slot pads for long enough to reply to a CMD13
     while being removed.

  Drivers:
   - davinci_mmc: Support using PIO instead of DMA.
   - dw_mmc: Add support for Exynos4412.
   - mxcmmc: DT support, use slot-gpio API.
   - mxs-mmc: Add broken-cd/cd-inverted/non-removable DT property
     support.
   - sdhci-sirf: New sdhci-pltfm driver for CSR SiRF SoCs:
       SiRFprimaII: unicore ARM Cortex-A9
       SiRFatlas6: unicore ARM Cortex-A9
       SiRFmarco: dual core ARM Cortex-A9 SMP
   - sdhci-tegra: Add support for Tegra114 platforms, use
     mmc_of_parse()"

* tag 'mmc-updates-for-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (66 commits)
  mmc: sdhci-tegra: fix MODULE_DEVICE_TABLE
  mmc: core: fix init controller performance regression, updated patch
  mmc: mxcmmc: enable DMA support on mpc512x
  mmc: mxcmmc: constify mxcmci_devtype
  mmc: mxcmmc: use slot-gpio API for write-protect detection
  mmc: mxcmmc: add mpc512x SDHC support
  mmc: mxcmmc: fix race conditions for host->req and host->data access
  mmc: mxcmmc: DT support
  mmc: dw_mmc: let device core setup the default pin configuration
  mmc: mxs-mmc: add broken-cd property
  mmc: mxs-mmc: add non-removable property
  mmc: mxs-mmc: add cd-inverted property
  mmc: core: call pm_runtime_put_noidle in pm_runtime_get_sync failed case
  mmc: mxcmmc: Fix bug when card is present during boot
  mmc: core: fix performance regression initializing MMC host controllers
  Revert "mmc: core: wait while adding MMC host to ensure root mounts successfully"
  mmc: atmel-mci: pio hang on block errors
  mmc: core: Fix bit width test failing on old eMMC cards
  mmc: dw_mmc: Use pr_info instead of printk
  mmc: dw_mmc: Check return value of regulator_enable
  ...
parents e72a5d1c e4404fab
* Freescale Secure Digital Host Controller for i.MX2/3 series
This file documents differences to the properties defined in mmc.txt.
Required properties:
- compatible : Should be "fsl,<chip>-mmc", chip can be imx21 or imx31
Optional properties:
- dmas: One DMA phandle with arguments as defined by the devicetree bindings
of the used DMA controller.
- dma-names: Has to be "rx-tx".
Example:
sdhci1: sdhci@10014000 {
compatible = "fsl,imx27-mmc", "fsl,imx21-mmc";
reg = <0x10014000 0x1000>;
interrupts = <11>;
dmas = <&dma 7>;
dma-names = "rx-tx";
bus-width = <4>;
cd-gpios = <&gpio3 29>;
status = "okay";
};
...@@ -5,13 +5,6 @@ MMC, SD and eMMC storage mediums. This file documents differences between the ...@@ -5,13 +5,6 @@ MMC, SD and eMMC storage mediums. This file documents differences between the
core mmc properties described by mmc.txt and the properties used by the core mmc properties described by mmc.txt and the properties used by the
Samsung implmentation of the SDHCI controller. Samsung implmentation of the SDHCI controller.
Note: The mmc core bindings documentation states that if none of the core
card-detect bindings are used, then the standard sdhci card detect mechanism
is used. The Samsung's SDHCI controller bindings extends this as listed below.
[A] The property "samsung,cd-pinmux-gpio" can be used as stated in the
"Optional Board Specific Properties" section below.
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
...@@ -20,18 +13,8 @@ Required SoC Specific Properties: ...@@ -20,18 +13,8 @@ Required SoC Specific Properties:
controller. controller.
Required Board Specific Properties: Required Board Specific Properties:
- Samsung GPIO variant (will be completely replaced by pinctrl): - pinctrl-0: Should specify pin control groups used for this controller.
- gpios: Should specify the gpios used for clock, command and data lines. The - pinctrl-names: Should contain only one value - "default".
gpio specifier format depends on the gpio controller.
- Pinctrl variant (preferred if available):
- pinctrl-0: Should specify pin control groups used for this controller.
- pinctrl-names: Should contain only one value - "default".
Optional Board Specific Properties:
- samsung,cd-pinmux-gpio: Specifies the card detect line that is routed
through a pinmux to the card-detect pin of the card slot. This property
should be used only if none of the mmc core card-detect properties are
used. Only for Samsung GPIO variant.
Example: Example:
sdhci@12530000 { sdhci@12530000 {
...@@ -39,19 +22,9 @@ Example: ...@@ -39,19 +22,9 @@ Example:
reg = <0x12530000 0x100>; reg = <0x12530000 0x100>;
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 0>;
/* Samsung GPIO variant */
gpios = <&gpk2 0 2 0 3>, /* clock line */
<&gpk2 1 2 0 3>, /* command line */
<&gpk2 3 2 3 3>, /* data line 0 */
<&gpk2 4 2 3 3>, /* data line 1 */
<&gpk2 5 2 3 3>, /* data line 2 */
<&gpk2 6 2 3 3>; /* data line 3 */
/* Pinctrl variant */
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4>;
}; };
Note: This example shows both SoC specific and board specific properties Note: This example shows both SoC specific and board specific properties
......
* SiRFprimII/marco/atlas6 SDHCI Controller
This file documents differences between the core properties in mmc.txt
and the properties used by the sdhci-sirf driver.
Required properties:
- compatible: sirf,prima2-sdhc
Optional properties:
- cd-gpios: card detect gpio, with zero flags.
Example:
sd0: sdhci@56000000 {
compatible = "sirf,prima2-sdhc";
reg = <0xcd000000 0x100000>;
cd-gpios = <&gpio 6 0>;
};
...@@ -22,6 +22,7 @@ All attributes are read-only. ...@@ -22,6 +22,7 @@ All attributes are read-only.
manfid Manufacturer ID (from CID Register) manfid Manufacturer ID (from CID Register)
name Product Name (from CID Register) name Product Name (from CID Register)
oemid OEM/Application ID (from CID Register) oemid OEM/Application ID (from CID Register)
prv Product Revision (from CID Register) (SD and MMCv4 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
......
...@@ -801,6 +801,7 @@ S: Maintained ...@@ -801,6 +801,7 @@ S: Maintained
F: arch/arm/mach-prima2/ F: arch/arm/mach-prima2/
F: drivers/dma/sirf-dma.c F: drivers/dma/sirf-dma.c
F: drivers/i2c/busses/i2c-sirf.c F: drivers/i2c/busses/i2c-sirf.c
F: drivers/mmc/host/sdhci-sirf.c
F: drivers/pinctrl/pinctrl-sirf.c F: drivers/pinctrl/pinctrl-sirf.c
F: drivers/spi/spi-sirf.c F: drivers/spi/spi-sirf.c
......
...@@ -173,7 +173,6 @@ CONFIG_MMC=y ...@@ -173,7 +173,6 @@ CONFIG_MMC=y
# CONFIG_MMC_BLOCK_BOUNCE is not set # CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_SDIO_UART=m CONFIG_SDIO_UART=m
CONFIG_MMC_ATMELMCI=y CONFIG_MMC_ATMELMCI=y
CONFIG_MMC_ATMELMCI_DMA=y
CONFIG_LEDS_ATMEL_PWM=y CONFIG_LEDS_ATMEL_PWM=y
CONFIG_LEDS_GPIO=y CONFIG_LEDS_GPIO=y
CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_LEDS_TRIGGER_TIMER=y
......
...@@ -122,7 +122,6 @@ CONFIG_USB_G_SERIAL=m ...@@ -122,7 +122,6 @@ CONFIG_USB_G_SERIAL=m
CONFIG_USB_CDC_COMPOSITE=m CONFIG_USB_CDC_COMPOSITE=m
CONFIG_MMC=y CONFIG_MMC=y
CONFIG_MMC_ATMELMCI=y CONFIG_MMC_ATMELMCI=y
CONFIG_MMC_ATMELMCI_DMA=y
CONFIG_NEW_LEDS=y CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y CONFIG_LEDS_CLASS=y
CONFIG_LEDS_ATMEL_PWM=m CONFIG_LEDS_ATMEL_PWM=m
......
...@@ -102,7 +102,6 @@ CONFIG_FRAMEBUFFER_CONSOLE=y ...@@ -102,7 +102,6 @@ CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_LOGO=y CONFIG_LOGO=y
CONFIG_MMC=y CONFIG_MMC=y
CONFIG_MMC_ATMELMCI=y CONFIG_MMC_ATMELMCI=y
CONFIG_MMC_ATMELMCI_DMA=y
CONFIG_NEW_LEDS=y CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y CONFIG_LEDS_CLASS=y
CONFIG_LEDS_ATMEL_PWM=y CONFIG_LEDS_ATMEL_PWM=y
......
...@@ -152,6 +152,8 @@ sdhc@1500 { ...@@ -152,6 +152,8 @@ sdhc@1500 {
compatible = "fsl,mpc5121-sdhc"; compatible = "fsl,mpc5121-sdhc";
reg = <0x1500 0x100>; reg = <0x1500 0x100>;
interrupts = <8 0x8>; interrupts = <8 0x8>;
dmas = <&dma0 30>;
dma-names = "rx-tx";
}; };
i2c@1700 { i2c@1700 {
......
...@@ -1932,8 +1932,14 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ...@@ -1932,8 +1932,14 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
} }
out: out:
if (!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) if ((!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) ||
/* release host only when there are no more requests */ (req && (req->cmd_flags & MMC_REQ_SPECIAL_MASK)))
/*
* Release host when there are no more requests
* and after special request(discard, flush) is done.
* In case sepecial request, there is no reentry to
* the 'mmc_blk_issue_rq' with 'mqrq_prev->req'.
*/
mmc_release_host(card->host); mmc_release_host(card->host);
return ret; return ret;
} }
......
...@@ -22,9 +22,6 @@ ...@@ -22,9 +22,6 @@
#define MMC_QUEUE_BOUNCESZ 65536 #define MMC_QUEUE_BOUNCESZ 65536
#define MMC_REQ_SPECIAL_MASK (REQ_DISCARD | REQ_FLUSH)
/* /*
* Prepare a MMC request. This just filters out odd stuff. * Prepare a MMC request. This just filters out odd stuff.
*/ */
......
#ifndef MMC_QUEUE_H #ifndef MMC_QUEUE_H
#define MMC_QUEUE_H #define MMC_QUEUE_H
#define MMC_REQ_SPECIAL_MASK (REQ_DISCARD | REQ_FLUSH)
struct request; struct request;
struct task_struct; struct task_struct;
......
...@@ -2289,6 +2289,19 @@ int _mmc_detect_card_removed(struct mmc_host *host) ...@@ -2289,6 +2289,19 @@ int _mmc_detect_card_removed(struct mmc_host *host)
return 1; return 1;
ret = host->bus_ops->alive(host); ret = host->bus_ops->alive(host);
/*
* Card detect status and alive check may be out of sync if card is
* removed slowly, when card detect switch changes while card/slot
* pads are still contacted in hardware (refer to "SD Card Mechanical
* Addendum, Appendix C: Card Detection Switch"). So reschedule a
* detect work 200ms later for this case.
*/
if (!ret && host->ops->get_cd && !host->ops->get_cd(host)) {
mmc_detect_change(host, msecs_to_jiffies(200));
pr_debug("%s: card removed too slowly\n", mmc_hostname(host));
}
if (ret) { if (ret) {
mmc_card_set_removed(host->card); mmc_card_set_removed(host->card);
pr_debug("%s: card remove detected\n", mmc_hostname(host)); pr_debug("%s: card remove detected\n", mmc_hostname(host));
...@@ -2403,6 +2416,9 @@ void mmc_start_host(struct mmc_host *host) ...@@ -2403,6 +2416,9 @@ void mmc_start_host(struct mmc_host *host)
{ {
host->f_init = max(freqs[0], host->f_min); host->f_init = max(freqs[0], host->f_min);
host->rescan_disable = 0; host->rescan_disable = 0;
if (host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)
mmc_power_off(host);
else
mmc_power_up(host); mmc_power_up(host);
mmc_detect_change(host, 0); mmc_detect_change(host, 0);
} }
......
...@@ -96,6 +96,7 @@ static int mmc_decode_cid(struct mmc_card *card) ...@@ -96,6 +96,7 @@ static int mmc_decode_cid(struct mmc_card *card)
card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8); card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8); card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8); card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
card->cid.prv = UNSTUFF_BITS(resp, 48, 8);
card->cid.serial = UNSTUFF_BITS(resp, 16, 32); card->cid.serial = UNSTUFF_BITS(resp, 16, 32);
card->cid.month = UNSTUFF_BITS(resp, 12, 4); card->cid.month = UNSTUFF_BITS(resp, 12, 4);
card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997; card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
...@@ -368,13 +369,13 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) ...@@ -368,13 +369,13 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]; ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
card->ext_csd.raw_trim_mult = card->ext_csd.raw_trim_mult =
ext_csd[EXT_CSD_TRIM_MULT]; ext_csd[EXT_CSD_TRIM_MULT];
card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT];
if (card->ext_csd.rev >= 4) { if (card->ext_csd.rev >= 4) {
/* /*
* Enhanced area feature support -- check whether the eMMC * Enhanced area feature support -- check whether the eMMC
* card has the Enhanced area enabled. If so, export enhanced * card has the Enhanced area enabled. If so, export enhanced
* area offset and size to user by adding sysfs interface. * area offset and size to user by adding sysfs interface.
*/ */
card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT];
if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) && if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) &&
(ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) {
hc_erase_grp_sz = hc_erase_grp_sz =
...@@ -627,6 +628,7 @@ MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev); ...@@ -627,6 +628,7 @@ MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid); MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name); MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid); MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
MMC_DEV_ATTR(prv, "0x%x\n", card->cid.prv);
MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial); 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);
...@@ -645,6 +647,7 @@ static struct attribute *mmc_std_attrs[] = { ...@@ -645,6 +647,7 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_manfid.attr, &dev_attr_manfid.attr,
&dev_attr_name.attr, &dev_attr_name.attr,
&dev_attr_oemid.attr, &dev_attr_oemid.attr,
&dev_attr_prv.attr,
&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,
......
...@@ -861,9 +861,11 @@ static void mmc_sdio_detect(struct mmc_host *host) ...@@ -861,9 +861,11 @@ static void mmc_sdio_detect(struct mmc_host *host)
/* Make sure card is powered before detecting it */ /* Make sure card is powered before detecting it */
if (host->caps & MMC_CAP_POWER_OFF_CARD) { if (host->caps & MMC_CAP_POWER_OFF_CARD) {
err = pm_runtime_get_sync(&host->card->dev); err = pm_runtime_get_sync(&host->card->dev);
if (err < 0) if (err < 0) {
pm_runtime_put_noidle(&host->card->dev);
goto out; goto out;
} }
}
mmc_claim_host(host); mmc_claim_host(host);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/acpi.h>
#include <linux/mmc/card.h> #include <linux/mmc/card.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
...@@ -137,7 +138,7 @@ static int sdio_bus_probe(struct device *dev) ...@@ -137,7 +138,7 @@ static int sdio_bus_probe(struct device *dev)
if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) { if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) {
ret = pm_runtime_get_sync(dev); ret = pm_runtime_get_sync(dev);
if (ret < 0) if (ret < 0)
goto out; goto disable_runtimepm;
} }
/* Set the default block size so the driver is sure it's something /* Set the default block size so the driver is sure it's something
...@@ -157,7 +158,6 @@ static int sdio_bus_probe(struct device *dev) ...@@ -157,7 +158,6 @@ static int sdio_bus_probe(struct device *dev)
disable_runtimepm: disable_runtimepm:
if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
pm_runtime_put_noidle(dev); pm_runtime_put_noidle(dev);
out:
return ret; return ret;
} }
...@@ -299,6 +299,19 @@ struct sdio_func *sdio_alloc_func(struct mmc_card *card) ...@@ -299,6 +299,19 @@ struct sdio_func *sdio_alloc_func(struct mmc_card *card)
return func; return func;
} }
#ifdef CONFIG_ACPI
static void sdio_acpi_set_handle(struct sdio_func *func)
{
struct mmc_host *host = func->card->host;
u64 addr = (host->slotno << 16) | func->num;
ACPI_HANDLE_SET(&func->dev,
acpi_get_child(ACPI_HANDLE(host->parent), addr));
}
#else
static inline void sdio_acpi_set_handle(struct sdio_func *func) {}
#endif
/* /*
* Register a new SDIO function with the driver model. * Register a new SDIO function with the driver model.
*/ */
...@@ -308,9 +321,12 @@ int sdio_add_func(struct sdio_func *func) ...@@ -308,9 +321,12 @@ int sdio_add_func(struct sdio_func *func)
dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num); dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num);
sdio_acpi_set_handle(func);
ret = device_add(&func->dev); ret = device_add(&func->dev);
if (ret == 0) if (ret == 0) {
sdio_func_set_present(func); sdio_func_set_present(func);
acpi_dev_pm_attach(&func->dev, false);
}
return ret; return ret;
} }
...@@ -326,6 +342,7 @@ void sdio_remove_func(struct sdio_func *func) ...@@ -326,6 +342,7 @@ void sdio_remove_func(struct sdio_func *func)
if (!sdio_func_present(func)) if (!sdio_func_present(func))
return; return;
acpi_dev_pm_detach(&func->dev, false);
device_del(&func->dev); device_del(&func->dev);
put_device(&func->dev); put_device(&func->dev);
} }
......
...@@ -190,6 +190,17 @@ config MMC_SDHCI_S3C ...@@ -190,6 +190,17 @@ config MMC_SDHCI_S3C
If unsure, say N. If unsure, say N.
config MMC_SDHCI_SIRF
tristate "SDHCI support on CSR SiRFprimaII and SiRFmarco SoCs"
depends on ARCH_SIRF
depends on MMC_SDHCI_PLTFM
help
This selects the SDHCI support for SiRF System-on-Chip devices.
If you have a controller with this interface, say Y or M here.
If unsure, say N.
config MMC_SDHCI_PXAV3 config MMC_SDHCI_PXAV3
tristate "Marvell MMP2 SD Host Controller support (PXAV3)" tristate "Marvell MMP2 SD Host Controller support (PXAV3)"
depends on CLKDEV_LOOKUP depends on CLKDEV_LOOKUP
...@@ -300,16 +311,6 @@ config MMC_ATMELMCI ...@@ -300,16 +311,6 @@ config MMC_ATMELMCI
If unsure, say N. If unsure, say N.
config MMC_ATMELMCI_DMA
bool "Atmel MCI DMA support"
depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE
help
Say Y here to have the Atmel MCI driver use a DMA engine to
do data transfers and thus increase the throughput and
reduce the CPU utilization.
If unsure, say N.
config MMC_MSM config MMC_MSM
tristate "Qualcomm SDCC Controller Support" tristate "Qualcomm SDCC Controller Support"
depends on MMC && ARCH_MSM depends on MMC && ARCH_MSM
...@@ -319,12 +320,12 @@ config MMC_MSM ...@@ -319,12 +320,12 @@ config MMC_MSM
support for SDIO devices. support for SDIO devices.
config MMC_MXC config MMC_MXC
tristate "Freescale i.MX21/27/31 Multimedia Card Interface support" tristate "Freescale i.MX21/27/31 or MPC512x Multimedia Card support"
depends on ARCH_MXC depends on ARCH_MXC || PPC_MPC512x
help help
This selects the Freescale i.MX21, i.MX27 and i.MX31 Multimedia card This selects the Freescale i.MX21, i.MX27, i.MX31 or MPC512x
Interface. If you have a i.MX platform with a Multimedia Card slot, Multimedia Card Interface. If you have an i.MX or MPC512x platform
say Y or M here. with a Multimedia Card slot, say Y or M here.
If unsure, say N. If unsure, say N.
......
...@@ -13,6 +13,7 @@ obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o ...@@ -13,6 +13,7 @@ obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o
obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o
obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o
obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o
obj-$(CONFIG_MMC_SDHCI_SIRF) += sdhci-sirf.o
obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o
obj-$(CONFIG_MMC_WBSD) += wbsd.o obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
......
...@@ -476,7 +476,7 @@ static int goldfish_mmc_probe(struct platform_device *pdev) ...@@ -476,7 +476,7 @@ static int goldfish_mmc_probe(struct platform_device *pdev)
host->mmc = mmc; host->mmc = mmc;
pr_err("mmc: Mapping %lX to %lX\n", (long)res->start, (long)res->end); pr_err("mmc: Mapping %lX to %lX\n", (long)res->start, (long)res->end);
host->reg_base = ioremap(res->start, res->end - res->start + 1); host->reg_base = ioremap(res->start, resource_size(res));
if (host->reg_base == NULL) { if (host->reg_base == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto ioremap_failed; goto ioremap_failed;
......
...@@ -178,6 +178,7 @@ struct atmel_mci { ...@@ -178,6 +178,7 @@ struct atmel_mci {
void __iomem *regs; void __iomem *regs;
struct scatterlist *sg; struct scatterlist *sg;
unsigned int sg_len;
unsigned int pio_offset; unsigned int pio_offset;
unsigned int *buffer; unsigned int *buffer;
unsigned int buf_size; unsigned int buf_size;
...@@ -892,6 +893,7 @@ static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data) ...@@ -892,6 +893,7 @@ static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data)
data->error = -EINPROGRESS; data->error = -EINPROGRESS;
host->sg = data->sg; host->sg = data->sg;
host->sg_len = data->sg_len;
host->data = data; host->data = data;
host->data_chan = NULL; host->data_chan = NULL;
...@@ -1826,7 +1828,8 @@ static void atmci_read_data_pio(struct atmel_mci *host) ...@@ -1826,7 +1828,8 @@ static void atmci_read_data_pio(struct atmel_mci *host)
if (offset == sg->length) { if (offset == sg->length) {
flush_dcache_page(sg_page(sg)); flush_dcache_page(sg_page(sg));
host->sg = sg = sg_next(sg); host->sg = sg = sg_next(sg);
if (!sg) host->sg_len--;
if (!sg || !host->sg_len)
goto done; goto done;
offset = 0; offset = 0;
...@@ -1839,7 +1842,8 @@ static void atmci_read_data_pio(struct atmel_mci *host) ...@@ -1839,7 +1842,8 @@ static void atmci_read_data_pio(struct atmel_mci *host)
flush_dcache_page(sg_page(sg)); flush_dcache_page(sg_page(sg));
host->sg = sg = sg_next(sg); host->sg = sg = sg_next(sg);
if (!sg) host->sg_len--;
if (!sg || !host->sg_len)
goto done; goto done;
offset = 4 - remaining; offset = 4 - remaining;
...@@ -1890,7 +1894,8 @@ static void atmci_write_data_pio(struct atmel_mci *host) ...@@ -1890,7 +1894,8 @@ static void atmci_write_data_pio(struct atmel_mci *host)
nbytes += 4; nbytes += 4;
if (offset == sg->length) { if (offset == sg->length) {
host->sg = sg = sg_next(sg); host->sg = sg = sg_next(sg);
if (!sg) host->sg_len--;
if (!sg || !host->sg_len)
goto done; goto done;
offset = 0; offset = 0;
...@@ -1904,7 +1909,8 @@ static void atmci_write_data_pio(struct atmel_mci *host) ...@@ -1904,7 +1909,8 @@ static void atmci_write_data_pio(struct atmel_mci *host)
nbytes += remaining; nbytes += remaining;
host->sg = sg = sg_next(sg); host->sg = sg = sg_next(sg);
if (!sg) { host->sg_len--;
if (!sg || !host->sg_len) {
atmci_writel(host, ATMCI_TDR, value); atmci_writel(host, ATMCI_TDR, value);
goto done; goto done;
} }
...@@ -2487,10 +2493,8 @@ static int __exit atmci_remove(struct platform_device *pdev) ...@@ -2487,10 +2493,8 @@ static int __exit atmci_remove(struct platform_device *pdev)
atmci_readl(host, ATMCI_SR); atmci_readl(host, ATMCI_SR);
clk_disable(host->mck); clk_disable(host->mck);
#ifdef CONFIG_MMC_ATMELMCI_DMA
if (host->dma.chan) if (host->dma.chan)
dma_release_channel(host->dma.chan); dma_release_channel(host->dma.chan);
#endif
free_irq(platform_get_irq(pdev, 0), host); free_irq(platform_get_irq(pdev, 0), host);
iounmap(host->regs); iounmap(host->regs);
......
...@@ -1264,12 +1264,14 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev) ...@@ -1264,12 +1264,14 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
r = platform_get_resource(pdev, IORESOURCE_DMA, 0); r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!r) if (!r)
goto out; dev_warn(&pdev->dev, "RX DMA resource not specified\n");
else
host->rxdma = r->start; host->rxdma = r->start;
r = platform_get_resource(pdev, IORESOURCE_DMA, 1); r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!r) if (!r)
goto out; dev_warn(&pdev->dev, "TX DMA resource not specified\n");
else
host->txdma = r->start; host->txdma = r->start;
host->mem_res = mem; host->mem_res = mem;
...@@ -1488,18 +1490,7 @@ static struct platform_driver davinci_mmcsd_driver = { ...@@ -1488,18 +1490,7 @@ static struct platform_driver davinci_mmcsd_driver = {
.id_table = davinci_mmc_devtype, .id_table = davinci_mmc_devtype,
}; };
static int __init davinci_mmcsd_init(void) module_platform_driver_probe(davinci_mmcsd_driver, davinci_mmcsd_probe);
{
return platform_driver_probe(&davinci_mmcsd_driver,
davinci_mmcsd_probe);
}
module_init(davinci_mmcsd_init);
static void __exit davinci_mmcsd_exit(void)
{
platform_driver_unregister(&davinci_mmcsd_driver);
}
module_exit(davinci_mmcsd_exit);
MODULE_AUTHOR("Texas Instruments India"); MODULE_AUTHOR("Texas Instruments India");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
...@@ -152,45 +152,8 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host) ...@@ -152,45 +152,8 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
return 0; return 0;
} }
static int dw_mci_exynos_setup_bus(struct dw_mci *host, /* Common capabilities of Exynos4/Exynos5 SoC */
struct device_node *slot_np, u8 bus_width) static unsigned long exynos_dwmmc_caps[4] = {
{
int idx, gpio, ret;
if (!slot_np)
return -EINVAL;
/* cmd + clock + bus-width pins */
for (idx = 0; idx < NUM_PINS(bus_width); idx++) {
gpio = of_get_gpio(slot_np, idx);
if (!gpio_is_valid(gpio)) {
dev_err(host->dev, "invalid gpio: %d\n", gpio);
return -EINVAL;
}
ret = devm_gpio_request(host->dev, gpio, "dw-mci-bus");
if (ret) {
dev_err(host->dev, "gpio [%d] request failed\n", gpio);
return -EBUSY;
}
}
if (host->pdata->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
return 0;
gpio = of_get_named_gpio(slot_np, "samsung,cd-pinmux-gpio", 0);
if (gpio_is_valid(gpio)) {
if (devm_gpio_request(host->dev, gpio, "dw-mci-cd"))
dev_err(host->dev, "gpio [%d] request failed\n", gpio);
} else {
dev_info(host->dev, "cd gpio not available");
}
return 0;
}
/* Exynos5250 controller specific capabilities */
static unsigned long exynos5250_dwmmc_caps[4] = {
MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23, MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
MMC_CAP_CMD23, MMC_CAP_CMD23,
...@@ -198,24 +161,25 @@ static unsigned long exynos5250_dwmmc_caps[4] = { ...@@ -198,24 +161,25 @@ static unsigned long exynos5250_dwmmc_caps[4] = {
MMC_CAP_CMD23, MMC_CAP_CMD23,
}; };
static const struct dw_mci_drv_data exynos5250_drv_data = { static const struct dw_mci_drv_data exynos_drv_data = {
.caps = exynos5250_dwmmc_caps, .caps = exynos_dwmmc_caps,
.init = dw_mci_exynos_priv_init, .init = dw_mci_exynos_priv_init,
.setup_clock = dw_mci_exynos_setup_clock, .setup_clock = dw_mci_exynos_setup_clock,
.prepare_command = dw_mci_exynos_prepare_command, .prepare_command = dw_mci_exynos_prepare_command,
.set_ios = dw_mci_exynos_set_ios, .set_ios = dw_mci_exynos_set_ios,
.parse_dt = dw_mci_exynos_parse_dt, .parse_dt = dw_mci_exynos_parse_dt,
.setup_bus = dw_mci_exynos_setup_bus,
}; };
static const struct of_device_id dw_mci_exynos_match[] = { static const struct of_device_id dw_mci_exynos_match[] = {
{ .compatible = "samsung,exynos4412-dw-mshc",
.data = &exynos_drv_data, },
{ .compatible = "samsung,exynos5250-dw-mshc", { .compatible = "samsung,exynos5250-dw-mshc",
.data = &exynos5250_drv_data, }, .data = &exynos_drv_data, },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, dw_mci_exynos_match); MODULE_DEVICE_TABLE(of, dw_mci_exynos_match);
int dw_mci_exynos_probe(struct platform_device *pdev) static int dw_mci_exynos_probe(struct platform_device *pdev)
{ {
const struct dw_mci_drv_data *drv_data; const struct dw_mci_drv_data *drv_data;
const struct of_device_id *match; const struct of_device_id *match;
...@@ -230,7 +194,7 @@ static struct platform_driver dw_mci_exynos_pltfm_driver = { ...@@ -230,7 +194,7 @@ static struct platform_driver dw_mci_exynos_pltfm_driver = {
.remove = __exit_p(dw_mci_pltfm_remove), .remove = __exit_p(dw_mci_pltfm_remove),
.driver = { .driver = {
.name = "dwmmc_exynos", .name = "dwmmc_exynos",
.of_match_table = of_match_ptr(dw_mci_exynos_match), .of_match_table = dw_mci_exynos_match,
.pm = &dw_mci_pltfm_pmops, .pm = &dw_mci_pltfm_pmops,
}, },
}; };
......
This diff is collapsed.
...@@ -190,7 +190,6 @@ extern int dw_mci_resume(struct dw_mci *host); ...@@ -190,7 +190,6 @@ extern int dw_mci_resume(struct dw_mci *host);
* @prepare_command: handle CMD register extensions. * @prepare_command: handle CMD register extensions.
* @set_ios: handle bus specific extensions. * @set_ios: handle bus specific extensions.
* @parse_dt: parse implementation specific device tree properties. * @parse_dt: parse implementation specific device tree properties.
* @setup_bus: initialize io-interface
* *
* Provide controller implementation specific extensions. The usage of this * Provide controller implementation specific extensions. The usage of this
* data structure is fully optional and usage of each member in this structure * data structure is fully optional and usage of each member in this structure
...@@ -203,7 +202,5 @@ struct dw_mci_drv_data { ...@@ -203,7 +202,5 @@ struct dw_mci_drv_data {
void (*prepare_command)(struct dw_mci *host, u32 *cmdr); void (*prepare_command)(struct dw_mci *host, u32 *cmdr);
void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
int (*parse_dt)(struct dw_mci *host); int (*parse_dt)(struct dw_mci *host);
int (*setup_bus)(struct dw_mci *host,
struct device_node *slot_np, u8 bus_width);
}; };
#endif /* _DW_MMC_H_ */ #endif /* _DW_MMC_H_ */
...@@ -119,9 +119,7 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data) ...@@ -119,9 +119,7 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data)
host->pio_size = data->blocks * data->blksz; host->pio_size = data->blocks * data->blksz;
host->pio_ptr = sg_virt(data->sg); host->pio_ptr = sg_virt(data->sg);
if (!nodma) if (!nodma)
pr_debug("%s: fallback to PIO for data " dev_dbg(host->dev, "fallback to PIO for data at 0x%p size %d\n",
"at 0x%p size %d\n",
mmc_hostname(host->mmc),
host->pio_ptr, host->pio_size); host->pio_ptr, host->pio_size);
return 1; return 1;
} else { } else {
...@@ -473,8 +471,8 @@ static irqreturn_t mvsd_irq(int irq, void *dev) ...@@ -473,8 +471,8 @@ static irqreturn_t mvsd_irq(int irq, void *dev)
if (mrq->data) if (mrq->data)
err_status = mvsd_finish_data(host, mrq->data, err_status); err_status = mvsd_finish_data(host, mrq->data, err_status);
if (err_status) { if (err_status) {
pr_err("%s: unhandled error status %#04x\n", dev_err(host->dev, "unhandled error status %#04x\n",
mmc_hostname(host->mmc), err_status); err_status);
cmd->error = -ENOMSG; cmd->error = -ENOMSG;
} }
...@@ -491,9 +489,8 @@ static irqreturn_t mvsd_irq(int irq, void *dev) ...@@ -491,9 +489,8 @@ static irqreturn_t mvsd_irq(int irq, void *dev)
if (irq_handled) if (irq_handled)
return IRQ_HANDLED; return IRQ_HANDLED;
pr_err("%s: unhandled interrupt status=0x%04x en=0x%04x " dev_err(host->dev, "unhandled interrupt status=0x%04x en=0x%04x pio=%d\n",
"pio=%d\n", mmc_hostname(host->mmc), intr_status, intr_status, host->intr_en, host->pio_size);
host->intr_en, host->pio_size);
return IRQ_NONE; return IRQ_NONE;
} }
...@@ -507,10 +504,8 @@ static void mvsd_timeout_timer(unsigned long data) ...@@ -507,10 +504,8 @@ static void mvsd_timeout_timer(unsigned long data)
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
mrq = host->mrq; mrq = host->mrq;
if (mrq) { if (mrq) {
pr_err("%s: Timeout waiting for hardware interrupt.\n", dev_err(host->dev, "Timeout waiting for hardware interrupt.\n");
mmc_hostname(host->mmc)); dev_err(host->dev, "hw_state=0x%04x, intr_status=0x%04x intr_en=0x%04x\n",
pr_err("%s: hw_state=0x%04x, intr_status=0x%04x "
"intr_en=0x%04x\n", mmc_hostname(host->mmc),
mvsd_read(MVSD_HW_STATE), mvsd_read(MVSD_HW_STATE),
mvsd_read(MVSD_NOR_INTR_STATUS), mvsd_read(MVSD_NOR_INTR_STATUS),
mvsd_read(MVSD_NOR_INTR_EN)); mvsd_read(MVSD_NOR_INTR_EN));
...@@ -741,8 +736,8 @@ static int __init mvsd_probe(struct platform_device *pdev) ...@@ -741,8 +736,8 @@ static int __init mvsd_probe(struct platform_device *pdev)
goto out; goto out;
} }
host->base_clock = mvsd_data->clock / 2; host->base_clock = mvsd_data->clock / 2;
gpio_card_detect = mvsd_data->gpio_card_detect; gpio_card_detect = mvsd_data->gpio_card_detect ? : -EINVAL;
gpio_write_protect = mvsd_data->gpio_write_protect; gpio_write_protect = mvsd_data->gpio_write_protect ? : -EINVAL;
} }
mmc->ops = &mvsd_ops; mmc->ops = &mvsd_ops;
...@@ -778,7 +773,7 @@ static int __init mvsd_probe(struct platform_device *pdev) ...@@ -778,7 +773,7 @@ static int __init mvsd_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, irq, mvsd_irq, 0, DRIVER_NAME, host); ret = devm_request_irq(&pdev->dev, irq, mvsd_irq, 0, DRIVER_NAME, host);
if (ret) { if (ret) {
pr_err("%s: cannot assign irq %d\n", DRIVER_NAME, irq); dev_err(&pdev->dev, "cannot assign irq %d\n", irq);
goto out; goto out;
} }
...@@ -797,13 +792,11 @@ static int __init mvsd_probe(struct platform_device *pdev) ...@@ -797,13 +792,11 @@ static int __init mvsd_probe(struct platform_device *pdev)
if (ret) if (ret)
goto out; goto out;
pr_notice("%s: %s driver initialized, ",
mmc_hostname(mmc), DRIVER_NAME);
if (!(mmc->caps & MMC_CAP_NEEDS_POLL)) if (!(mmc->caps & MMC_CAP_NEEDS_POLL))
printk("using GPIO %d for card detection\n", dev_notice(&pdev->dev, "using GPIO %d for card detection\n",
gpio_card_detect); gpio_card_detect);
else else
printk("lacking card detect (fall back to polling)\n"); dev_notice(&pdev->dev, "lacking card detect (fall back to polling)\n");
return 0; return 0;
out: out:
...@@ -881,18 +874,7 @@ static struct platform_driver mvsd_driver = { ...@@ -881,18 +874,7 @@ static struct platform_driver mvsd_driver = {
}, },
}; };
static int __init mvsd_init(void) module_platform_driver_probe(mvsd_driver, mvsd_probe);
{
return platform_driver_probe(&mvsd_driver, mvsd_probe);
}
static void __exit mvsd_exit(void)
{
platform_driver_unregister(&mvsd_driver);
}
module_init(mvsd_init);
module_exit(mvsd_exit);
/* maximum card clock frequency (default 50MHz) */ /* maximum card clock frequency (default 50MHz) */
module_param(maxfreq, int, 0); module_param(maxfreq, int, 0);
......
This diff is collapsed.
...@@ -72,6 +72,9 @@ struct mxs_mmc_host { ...@@ -72,6 +72,9 @@ struct mxs_mmc_host {
int sdio_irq_en; int sdio_irq_en;
int wp_gpio; int wp_gpio;
bool wp_inverted; bool wp_inverted;
bool cd_inverted;
bool broken_cd;
bool non_removable;
}; };
static int mxs_mmc_get_ro(struct mmc_host *mmc) static int mxs_mmc_get_ro(struct mmc_host *mmc)
...@@ -95,8 +98,9 @@ static int mxs_mmc_get_cd(struct mmc_host *mmc) ...@@ -95,8 +98,9 @@ static int mxs_mmc_get_cd(struct mmc_host *mmc)
struct mxs_mmc_host *host = mmc_priv(mmc); struct mxs_mmc_host *host = mmc_priv(mmc);
struct mxs_ssp *ssp = &host->ssp; struct mxs_ssp *ssp = &host->ssp;
return !(readl(ssp->base + HW_SSP_STATUS(ssp)) & return host->non_removable || host->broken_cd ||
BM_SSP_STATUS_CARD_DETECT); !(readl(ssp->base + HW_SSP_STATUS(ssp)) &
BM_SSP_STATUS_CARD_DETECT) ^ host->cd_inverted;
} }
static void mxs_mmc_reset(struct mxs_mmc_host *host) static void mxs_mmc_reset(struct mxs_mmc_host *host)
...@@ -686,11 +690,16 @@ static int mxs_mmc_probe(struct platform_device *pdev) ...@@ -686,11 +690,16 @@ static int mxs_mmc_probe(struct platform_device *pdev)
mmc->caps |= MMC_CAP_4_BIT_DATA; mmc->caps |= MMC_CAP_4_BIT_DATA;
else if (bus_width == 8) else if (bus_width == 8)
mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
host->broken_cd = of_property_read_bool(np, "broken-cd");
host->non_removable = of_property_read_bool(np, "non-removable");
if (host->non_removable)
mmc->caps |= MMC_CAP_NONREMOVABLE;
host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags); host->wp_gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags);
if (flags & OF_GPIO_ACTIVE_LOW) if (flags & OF_GPIO_ACTIVE_LOW)
host->wp_inverted = 1; host->wp_inverted = 1;
host->cd_inverted = of_property_read_bool(np, "cd-inverted");
mmc->f_min = 400000; mmc->f_min = 400000;
mmc->f_max = 288000000; mmc->f_max = 288000000;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
......
...@@ -1717,6 +1717,12 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev) ...@@ -1717,6 +1717,12 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
struct omap_mmc_platform_data *pdata; struct omap_mmc_platform_data *pdata;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
u32 bus_width, max_freq; u32 bus_width, max_freq;
int cd_gpio, wp_gpio;
cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
if (cd_gpio == -EPROBE_DEFER || wp_gpio == -EPROBE_DEFER)
return ERR_PTR(-EPROBE_DEFER);
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) if (!pdata)
...@@ -1727,8 +1733,8 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev) ...@@ -1727,8 +1733,8 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
/* This driver only supports 1 slot */ /* This driver only supports 1 slot */
pdata->nr_slots = 1; pdata->nr_slots = 1;
pdata->slots[0].switch_pin = of_get_named_gpio(np, "cd-gpios", 0); pdata->slots[0].switch_pin = cd_gpio;
pdata->slots[0].gpio_wp = of_get_named_gpio(np, "wp-gpios", 0); pdata->slots[0].gpio_wp = wp_gpio;
if (of_find_property(np, "ti,non-removable", NULL)) { if (of_find_property(np, "ti,non-removable", NULL)) {
pdata->slots[0].nonremovable = true; pdata->slots[0].nonremovable = true;
...@@ -1774,6 +1780,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev) ...@@ -1774,6 +1780,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev); match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
if (match) { if (match) {
pdata = of_get_hsmmc_pdata(&pdev->dev); pdata = of_get_hsmmc_pdata(&pdev->dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
if (match->data) { if (match->data) {
const u16 *offsetp = match->data; const u16 *offsetp = match->data;
pdata->reg_offset = *offsetp; pdata->reg_offset = *offsetp;
......
...@@ -57,6 +57,9 @@ struct realtek_pci_sdmmc { ...@@ -57,6 +57,9 @@ struct realtek_pci_sdmmc {
bool eject; bool eject;
bool initial_mode; bool initial_mode;
bool ddr_mode; bool ddr_mode;
int power_state;
#define SDMMC_POWER_ON 1
#define SDMMC_POWER_OFF 0
}; };
static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host) static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host)
...@@ -765,6 +768,9 @@ static int sd_power_on(struct realtek_pci_sdmmc *host) ...@@ -765,6 +768,9 @@ static int sd_power_on(struct realtek_pci_sdmmc *host)
struct rtsx_pcr *pcr = host->pcr; struct rtsx_pcr *pcr = host->pcr;
int err; int err;
if (host->power_state == SDMMC_POWER_ON)
return 0;
rtsx_pci_init_cmd(pcr); rtsx_pci_init_cmd(pcr);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SELECT, 0x07, SD_MOD_SEL); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SELECT, 0x07, SD_MOD_SEL);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SHARE_MODE, rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_SHARE_MODE,
...@@ -787,6 +793,7 @@ static int sd_power_on(struct realtek_pci_sdmmc *host) ...@@ -787,6 +793,7 @@ static int sd_power_on(struct realtek_pci_sdmmc *host)
if (err < 0) if (err < 0)
return err; return err;
host->power_state = SDMMC_POWER_ON;
return 0; return 0;
} }
...@@ -795,6 +802,8 @@ static int sd_power_off(struct realtek_pci_sdmmc *host) ...@@ -795,6 +802,8 @@ static int sd_power_off(struct realtek_pci_sdmmc *host)
struct rtsx_pcr *pcr = host->pcr; struct rtsx_pcr *pcr = host->pcr;
int err; int err;
host->power_state = SDMMC_POWER_OFF;
rtsx_pci_init_cmd(pcr); rtsx_pci_init_cmd(pcr);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, SD_CLK_EN, 0); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, SD_CLK_EN, 0);
...@@ -1260,6 +1269,7 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev) ...@@ -1260,6 +1269,7 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
host->pcr = pcr; host->pcr = pcr;
host->mmc = mmc; host->mmc = mmc;
host->pdev = pdev; host->pdev = pdev;
host->power_state = SDMMC_POWER_OFF;
platform_set_drvdata(pdev, host); platform_set_drvdata(pdev, host);
pcr->slots[RTSX_SD_CARD].p_dev = pdev; pcr->slots[RTSX_SD_CARD].p_dev = pdev;
pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event; pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event;
......
...@@ -195,6 +195,8 @@ static int sdhci_acpi_probe(struct platform_device *pdev) ...@@ -195,6 +195,8 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
host->mmc->pm_caps |= c->slot->pm_caps; host->mmc->pm_caps |= c->slot->pm_caps;
} }
host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP;
err = sdhci_add_host(host); err = sdhci_add_host(host);
if (err) if (err)
goto err_free; goto err_free;
......
...@@ -124,7 +124,7 @@ unsigned int bcm2835_sdhci_get_min_clock(struct sdhci_host *host) ...@@ -124,7 +124,7 @@ unsigned int bcm2835_sdhci_get_min_clock(struct sdhci_host *host)
return MIN_FREQ; return MIN_FREQ;
} }
static struct sdhci_ops bcm2835_sdhci_ops = { static const struct sdhci_ops bcm2835_sdhci_ops = {
.write_l = bcm2835_sdhci_writel, .write_l = bcm2835_sdhci_writel,
.write_w = bcm2835_sdhci_writew, .write_w = bcm2835_sdhci_writew,
.write_b = bcm2835_sdhci_writeb, .write_b = bcm2835_sdhci_writeb,
...@@ -135,7 +135,7 @@ static struct sdhci_ops bcm2835_sdhci_ops = { ...@@ -135,7 +135,7 @@ static struct sdhci_ops bcm2835_sdhci_ops = {
.get_min_clock = bcm2835_sdhci_get_min_clock, .get_min_clock = bcm2835_sdhci_get_min_clock,
}; };
static struct sdhci_pltfm_data bcm2835_sdhci_pdata = { static const struct sdhci_pltfm_data bcm2835_sdhci_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION | .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK, SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
.ops = &bcm2835_sdhci_ops, .ops = &bcm2835_sdhci_ops,
......
...@@ -79,12 +79,12 @@ static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -79,12 +79,12 @@ static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock)
host->clock = clock; host->clock = clock;
} }
static struct sdhci_ops sdhci_cns3xxx_ops = { static const struct sdhci_ops sdhci_cns3xxx_ops = {
.get_max_clock = sdhci_cns3xxx_get_max_clk, .get_max_clock = sdhci_cns3xxx_get_max_clk,
.set_clock = sdhci_cns3xxx_set_clock, .set_clock = sdhci_cns3xxx_set_clock,
}; };
static struct sdhci_pltfm_data sdhci_cns3xxx_pdata = { static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
.ops = &sdhci_cns3xxx_ops, .ops = &sdhci_cns3xxx_ops,
.quirks = SDHCI_QUIRK_BROKEN_DMA | .quirks = SDHCI_QUIRK_BROKEN_DMA |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
......
...@@ -83,12 +83,12 @@ static u32 sdhci_dove_readl(struct sdhci_host *host, int reg) ...@@ -83,12 +83,12 @@ static u32 sdhci_dove_readl(struct sdhci_host *host, int reg)
return ret; return ret;
} }
static struct sdhci_ops sdhci_dove_ops = { static const struct sdhci_ops sdhci_dove_ops = {
.read_w = sdhci_dove_readw, .read_w = sdhci_dove_readw,
.read_l = sdhci_dove_readl, .read_l = sdhci_dove_readl,
}; };
static struct sdhci_pltfm_data sdhci_dove_pdata = { static const struct sdhci_pltfm_data sdhci_dove_pdata = {
.ops = &sdhci_dove_ops, .ops = &sdhci_dove_ops,
.quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER | .quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
SDHCI_QUIRK_NO_BUSY_IRQ | SDHCI_QUIRK_NO_BUSY_IRQ |
......
...@@ -399,7 +399,7 @@ static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width) ...@@ -399,7 +399,7 @@ static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
return 0; return 0;
} }
static struct sdhci_ops sdhci_esdhc_ops = { static const struct sdhci_ops sdhci_esdhc_ops = {
.read_l = esdhc_readl_le, .read_l = esdhc_readl_le,
.read_w = esdhc_readw_le, .read_w = esdhc_readw_le,
.write_l = esdhc_writel_le, .write_l = esdhc_writel_le,
...@@ -412,7 +412,7 @@ static struct sdhci_ops sdhci_esdhc_ops = { ...@@ -412,7 +412,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.platform_bus_width = esdhc_pltfm_bus_width, .platform_bus_width = esdhc_pltfm_bus_width,
}; };
static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_HISPD_BIT .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_HISPD_BIT
| SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
| SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC
......
...@@ -230,7 +230,7 @@ static void esdhc_of_platform_init(struct sdhci_host *host) ...@@ -230,7 +230,7 @@ static void esdhc_of_platform_init(struct sdhci_host *host)
host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
} }
static struct sdhci_ops sdhci_esdhc_ops = { static const 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,
...@@ -249,7 +249,7 @@ static struct sdhci_ops sdhci_esdhc_ops = { ...@@ -249,7 +249,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.adma_workaround = esdhci_of_adma_workaround, .adma_workaround = esdhci_of_adma_workaround,
}; };
static struct sdhci_pltfm_data sdhci_esdhc_pdata = { static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {
/* /*
* card detection could be handled via GPIO * card detection could be handled via GPIO
* eSDHC cannot support End Attribute in NOP ADMA descriptor * eSDHC cannot support End Attribute in NOP ADMA descriptor
......
...@@ -51,7 +51,7 @@ static void sdhci_hlwd_writeb(struct sdhci_host *host, u8 val, int reg) ...@@ -51,7 +51,7 @@ static void sdhci_hlwd_writeb(struct sdhci_host *host, u8 val, int reg)
udelay(SDHCI_HLWD_WRITE_DELAY); udelay(SDHCI_HLWD_WRITE_DELAY);
} }
static struct sdhci_ops sdhci_hlwd_ops = { static const struct sdhci_ops sdhci_hlwd_ops = {
.read_l = sdhci_be32bs_readl, .read_l = sdhci_be32bs_readl,
.read_w = sdhci_be32bs_readw, .read_w = sdhci_be32bs_readw,
.read_b = sdhci_be32bs_readb, .read_b = sdhci_be32bs_readb,
...@@ -60,7 +60,7 @@ static struct sdhci_ops sdhci_hlwd_ops = { ...@@ -60,7 +60,7 @@ static struct sdhci_ops sdhci_hlwd_ops = {
.write_b = sdhci_hlwd_writeb, .write_b = sdhci_hlwd_writeb,
}; };
static struct sdhci_pltfm_data sdhci_hlwd_pdata = { static const struct sdhci_pltfm_data sdhci_hlwd_pdata = {
.quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | .quirks = SDHCI_QUIRK_32BIT_DMA_ADDR |
SDHCI_QUIRK_32BIT_DMA_SIZE, SDHCI_QUIRK_32BIT_DMA_SIZE,
.ops = &sdhci_hlwd_ops, .ops = &sdhci_hlwd_ops,
......
...@@ -975,7 +975,7 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host) ...@@ -975,7 +975,7 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host)
usleep_range(300, 1000); usleep_range(300, 1000);
} }
static struct sdhci_ops sdhci_pci_ops = { static const struct sdhci_ops sdhci_pci_ops = {
.enable_dma = sdhci_pci_enable_dma, .enable_dma = sdhci_pci_enable_dma,
.platform_bus_width = sdhci_pci_bus_width, .platform_bus_width = sdhci_pci_bus_width,
.hw_reset = sdhci_pci_hw_reset, .hw_reset = sdhci_pci_hw_reset,
...@@ -1279,6 +1279,8 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( ...@@ -1279,6 +1279,8 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot(
} }
host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ; host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
host->mmc->slotno = slotno;
host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP;
ret = sdhci_add_host(host); ret = sdhci_add_host(host);
if (ret) if (ret)
......
...@@ -44,7 +44,7 @@ unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host) ...@@ -44,7 +44,7 @@ unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host)
} }
EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_max_clock); EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_max_clock);
static struct sdhci_ops sdhci_pltfm_ops = { static const struct sdhci_ops sdhci_pltfm_ops = {
}; };
#ifdef CONFIG_OF #ifdef CONFIG_OF
...@@ -94,6 +94,7 @@ void sdhci_get_of_property(struct platform_device *pdev) ...@@ -94,6 +94,7 @@ void sdhci_get_of_property(struct platform_device *pdev)
if (of_device_is_compatible(np, "fsl,p2020-esdhc") || if (of_device_is_compatible(np, "fsl,p2020-esdhc") ||
of_device_is_compatible(np, "fsl,p1010-esdhc") || of_device_is_compatible(np, "fsl,p1010-esdhc") ||
of_device_is_compatible(np, "fsl,t4240-esdhc") ||
of_device_is_compatible(np, "fsl,mpc8536-esdhc")) of_device_is_compatible(np, "fsl,mpc8536-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
...@@ -114,7 +115,7 @@ void sdhci_get_of_property(struct platform_device *pdev) {} ...@@ -114,7 +115,7 @@ void sdhci_get_of_property(struct platform_device *pdev) {}
EXPORT_SYMBOL_GPL(sdhci_get_of_property); EXPORT_SYMBOL_GPL(sdhci_get_of_property);
struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
struct sdhci_pltfm_data *pdata) const struct sdhci_pltfm_data *pdata)
{ {
struct sdhci_host *host; struct sdhci_host *host;
struct sdhci_pltfm_host *pltfm_host; struct sdhci_pltfm_host *pltfm_host;
...@@ -201,7 +202,7 @@ void sdhci_pltfm_free(struct platform_device *pdev) ...@@ -201,7 +202,7 @@ void sdhci_pltfm_free(struct platform_device *pdev)
EXPORT_SYMBOL_GPL(sdhci_pltfm_free); EXPORT_SYMBOL_GPL(sdhci_pltfm_free);
int sdhci_pltfm_register(struct platform_device *pdev, int sdhci_pltfm_register(struct platform_device *pdev,
struct sdhci_pltfm_data *pdata) const struct sdhci_pltfm_data *pdata)
{ {
struct sdhci_host *host; struct sdhci_host *host;
int ret = 0; int ret = 0;
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
#include "sdhci.h" #include "sdhci.h"
struct sdhci_pltfm_data { struct sdhci_pltfm_data {
struct sdhci_ops *ops; const struct sdhci_ops *ops;
unsigned int quirks; unsigned int quirks;
}; };
...@@ -91,11 +91,11 @@ static inline void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg) ...@@ -91,11 +91,11 @@ static inline void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
extern void sdhci_get_of_property(struct platform_device *pdev); extern void sdhci_get_of_property(struct platform_device *pdev);
extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
struct sdhci_pltfm_data *pdata); const struct sdhci_pltfm_data *pdata);
extern void sdhci_pltfm_free(struct platform_device *pdev); extern void sdhci_pltfm_free(struct platform_device *pdev);
extern int sdhci_pltfm_register(struct platform_device *pdev, extern int sdhci_pltfm_register(struct platform_device *pdev,
struct sdhci_pltfm_data *pdata); const struct sdhci_pltfm_data *pdata);
extern int sdhci_pltfm_unregister(struct platform_device *pdev); extern int sdhci_pltfm_unregister(struct platform_device *pdev);
extern unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host); extern unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host);
......
...@@ -111,7 +111,7 @@ static int pxav2_mmc_set_width(struct sdhci_host *host, int width) ...@@ -111,7 +111,7 @@ static int pxav2_mmc_set_width(struct sdhci_host *host, int width)
return 0; return 0;
} }
static struct sdhci_ops pxav2_sdhci_ops = { static const struct sdhci_ops pxav2_sdhci_ops = {
.get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock,
.platform_reset_exit = pxav2_set_private_registers, .platform_reset_exit = pxav2_set_private_registers,
.platform_bus_width = pxav2_mmc_set_width, .platform_bus_width = pxav2_mmc_set_width,
......
...@@ -167,13 +167,21 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) ...@@ -167,13 +167,21 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
return 0; return 0;
} }
static struct sdhci_ops pxav3_sdhci_ops = { static const 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 = sdhci_pltfm_clk_get_max_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock,
}; };
static struct sdhci_pltfm_data sdhci_pxav3_pdata = {
.quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
| SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
| SDHCI_QUIRK_32BIT_ADMA_SIZE
| SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
.ops = &pxav3_sdhci_ops,
};
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id sdhci_pxav3_of_match[] = { static const struct of_device_id sdhci_pxav3_of_match[] = {
{ {
...@@ -187,29 +195,16 @@ static struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev) ...@@ -187,29 +195,16 @@ static struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev)
{ {
struct sdhci_pxa_platdata *pdata; struct sdhci_pxa_platdata *pdata;
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
u32 bus_width;
u32 clk_delay_cycles; u32 clk_delay_cycles;
enum of_gpio_flags gpio_flags;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) if (!pdata)
return NULL; return NULL;
if (of_find_property(np, "non-removable", NULL))
pdata->flags |= PXA_FLAG_CARD_PERMANENT;
of_property_read_u32(np, "bus-width", &bus_width);
if (bus_width == 8)
pdata->flags |= PXA_FLAG_SD_8_BIT_CAPABLE_SLOT;
of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles); of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles);
if (clk_delay_cycles > 0) if (clk_delay_cycles > 0)
pdata->clk_delay_cycles = clk_delay_cycles; pdata->clk_delay_cycles = clk_delay_cycles;
pdata->ext_cd_gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, &gpio_flags);
if (gpio_flags != OF_GPIO_ACTIVE_LOW)
pdata->host_caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
return pdata; return pdata;
} }
#else #else
...@@ -235,7 +230,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) ...@@ -235,7 +230,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
if (!pxa) if (!pxa)
return -ENOMEM; return -ENOMEM;
host = sdhci_pltfm_init(pdev, NULL); host = sdhci_pltfm_init(pdev, &sdhci_pxav3_pdata);
if (IS_ERR(host)) { if (IS_ERR(host)) {
kfree(pxa); kfree(pxa);
return PTR_ERR(host); return PTR_ERR(host);
...@@ -252,24 +247,18 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) ...@@ -252,24 +247,18 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
pltfm_host->clk = clk; pltfm_host->clk = clk;
clk_prepare_enable(clk); clk_prepare_enable(clk);
host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
| SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
| 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;
match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev); match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev);
if (match) if (match) {
mmc_of_parse(host->mmc);
sdhci_get_of_property(pdev);
pdata = pxav3_get_mmc_pdata(dev); pdata = pxav3_get_mmc_pdata(dev);
} else if (pdata) {
if (pdata) {
if (pdata->flags & PXA_FLAG_CARD_PERMANENT) {
/* on-chip device */ /* on-chip device */
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; if (pdata->flags & PXA_FLAG_CARD_PERMANENT)
host->mmc->caps |= MMC_CAP_NONREMOVABLE; host->mmc->caps |= MMC_CAP_NONREMOVABLE;
}
/* If slot design supports 8 bit data, indicate this to MMC. */ /* If slot design supports 8 bit data, indicate this to MMC. */
if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT) if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT)
...@@ -296,10 +285,6 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) ...@@ -296,10 +285,6 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
} }
} }
host->ops = &pxav3_sdhci_ops;
sdhci_get_of_property(pdev);
pm_runtime_set_active(&pdev->dev); pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, PXAV3_RPM_DELAY_MS); pm_runtime_set_autosuspend_delay(&pdev->dev, PXAV3_RPM_DELAY_MS);
...@@ -317,7 +302,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev) ...@@ -317,7 +302,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, host); platform_set_drvdata(pdev, host);
if (pdata->pm_caps & MMC_PM_KEEP_POWER) { if (host->mmc->pm_caps & MMC_PM_KEEP_POWER) {
device_init_wakeup(&pdev->dev, 1); device_init_wakeup(&pdev->dev, 1);
host->mmc->pm_flags |= MMC_PM_WAKE_SDIO_IRQ; host->mmc->pm_flags |= MMC_PM_WAKE_SDIO_IRQ;
} else { } else {
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#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>
...@@ -44,7 +43,6 @@ ...@@ -44,7 +43,6 @@
* @ioarea: The resource created when we claimed the IO area. * @ioarea: The resource created when we claimed the IO area.
* @pdata: The platform data for this controller. * @pdata: The platform data for this controller.
* @cur_clk: The index of the current bus clock. * @cur_clk: The index of the current bus clock.
* @gpios: List of gpio numbers parsed from device tree.
* @clk_io: The clock for the internal bus interface. * @clk_io: The clock for the internal bus interface.
* @clk_bus: The clocks that are available for the SD/MMC bus clock. * @clk_bus: The clocks that are available for the SD/MMC bus clock.
*/ */
...@@ -56,8 +54,6 @@ struct sdhci_s3c { ...@@ -56,8 +54,6 @@ struct sdhci_s3c {
unsigned int cur_clk; unsigned int cur_clk;
int ext_cd_irq; int ext_cd_irq;
int ext_cd_gpio; int ext_cd_gpio;
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];
...@@ -446,88 +442,39 @@ static int sdhci_s3c_parse_dt(struct device *dev, ...@@ -446,88 +442,39 @@ static int sdhci_s3c_parse_dt(struct device *dev,
struct device_node *node = dev->of_node; struct device_node *node = dev->of_node;
struct sdhci_s3c *ourhost = to_s3c(host); struct sdhci_s3c *ourhost = to_s3c(host);
u32 max_width; u32 max_width;
int gpio, cnt, ret; int gpio;
/* if the bus-width property is not specified, assume width as 1 */ /* if the bus-width property is not specified, assume width as 1 */
if (of_property_read_u32(node, "bus-width", &max_width)) if (of_property_read_u32(node, "bus-width", &max_width))
max_width = 1; max_width = 1;
pdata->max_width = max_width; pdata->max_width = max_width;
ourhost->gpios = devm_kzalloc(dev, NUM_GPIOS(pdata->max_width) *
sizeof(int), GFP_KERNEL);
if (!ourhost->gpios)
return -ENOMEM;
/* get the card detection method */ /* get the card detection method */
if (of_get_property(node, "broken-cd", NULL)) { 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; return 0;
} }
if (of_get_property(node, "non-removable", NULL)) { 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; return 0;
} }
gpio = of_get_named_gpio(node, "cd-gpios", 0); gpio = of_get_named_gpio(node, "cd-gpios", 0);
if (gpio_is_valid(gpio)) { if (gpio_is_valid(gpio)) {
pdata->cd_type = S3C_SDHCI_CD_GPIO; pdata->cd_type = S3C_SDHCI_CD_GPIO;
goto found_cd;
} else if (gpio != -ENOENT) {
dev_err(dev, "invalid card detect gpio specified\n");
return -EINVAL;
}
gpio = of_get_named_gpio(node, "samsung,cd-pinmux-gpio", 0);
if (gpio_is_valid(gpio)) {
pdata->cd_type = S3C_SDHCI_CD_INTERNAL;
goto found_cd;
} else if (gpio != -ENOENT) {
dev_err(dev, "invalid card detect gpio specified\n");
return -EINVAL;
}
/* assuming internal card detect that will be configured by pinctrl */
pdata->cd_type = S3C_SDHCI_CD_INTERNAL;
goto setup_bus;
found_cd:
if (pdata->cd_type == S3C_SDHCI_CD_GPIO) {
pdata->ext_cd_gpio = gpio; pdata->ext_cd_gpio = gpio;
ourhost->ext_cd_gpio = -1; ourhost->ext_cd_gpio = -1;
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) {
ret = devm_gpio_request(dev, gpio, "sdhci-cd");
if (ret) {
dev_err(dev, "card detect gpio request failed\n");
return -EINVAL;
}
ourhost->ext_cd_gpio = gpio;
}
setup_bus:
if (!IS_ERR(ourhost->pctrl))
return 0; return 0;
} else if (gpio != -ENOENT) {
/* get the gpios for command, clock and data lines */ dev_err(dev, "invalid card detect gpio specified\n");
for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) {
gpio = of_get_gpio(node, cnt);
if (!gpio_is_valid(gpio)) {
dev_err(dev, "invalid gpio[%d]\n", cnt);
return -EINVAL;
}
ourhost->gpios[cnt] = gpio;
}
for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) {
ret = devm_gpio_request(dev, ourhost->gpios[cnt], "sdhci-gpio");
if (ret) {
dev_err(dev, "gpio[%d] request failed\n", cnt);
return -EINVAL; return -EINVAL;
} }
}
/* assuming internal card detect that will be configured by pinctrl */
pdata->cd_type = S3C_SDHCI_CD_INTERNAL;
return 0; return 0;
} }
#else #else
...@@ -588,8 +535,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev) ...@@ -588,8 +535,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
goto err_pdata_io_clk; 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)
...@@ -607,7 +552,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev) ...@@ -607,7 +552,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, host); platform_set_drvdata(pdev, host);
sc->clk_io = clk_get(dev, "hsmmc"); sc->clk_io = devm_clk_get(dev, "hsmmc");
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);
...@@ -622,7 +567,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev) ...@@ -622,7 +567,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
char name[14]; char name[14];
snprintf(name, 14, "mmc_busclk.%d", ptr); snprintf(name, 14, "mmc_busclk.%d", ptr);
clk = clk_get(dev, name); clk = devm_clk_get(dev, name);
if (IS_ERR(clk)) if (IS_ERR(clk))
continue; continue;
...@@ -763,15 +708,9 @@ static int sdhci_s3c_probe(struct platform_device *pdev) ...@@ -763,15 +708,9 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
#ifndef CONFIG_PM_RUNTIME #ifndef CONFIG_PM_RUNTIME
clk_disable_unprepare(sc->clk_bus[sc->cur_clk]); clk_disable_unprepare(sc->clk_bus[sc->cur_clk]);
#endif #endif
for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
if (sc->clk_bus[ptr]) {
clk_put(sc->clk_bus[ptr]);
}
}
err_no_busclks: err_no_busclks:
clk_disable_unprepare(sc->clk_io); clk_disable_unprepare(sc->clk_io);
clk_put(sc->clk_io);
err_pdata_io_clk: err_pdata_io_clk:
sdhci_free_host(host); sdhci_free_host(host);
...@@ -784,7 +723,6 @@ static int sdhci_s3c_remove(struct platform_device *pdev) ...@@ -784,7 +723,6 @@ static int sdhci_s3c_remove(struct platform_device *pdev)
struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_s3c *sc = sdhci_priv(host); struct sdhci_s3c *sc = sdhci_priv(host);
struct s3c_sdhci_platdata *pdata = sc->pdata; struct s3c_sdhci_platdata *pdata = sc->pdata;
int ptr;
if (pdata->cd_type == S3C_SDHCI_CD_EXTERNAL && pdata->ext_cd_cleanup) if (pdata->cd_type == S3C_SDHCI_CD_EXTERNAL && pdata->ext_cd_cleanup)
pdata->ext_cd_cleanup(&sdhci_s3c_notify_change); pdata->ext_cd_cleanup(&sdhci_s3c_notify_change);
...@@ -804,13 +742,7 @@ static int sdhci_s3c_remove(struct platform_device *pdev) ...@@ -804,13 +742,7 @@ static int sdhci_s3c_remove(struct platform_device *pdev)
#ifndef CONFIG_PM_RUNTIME #ifndef CONFIG_PM_RUNTIME
clk_disable_unprepare(sc->clk_bus[sc->cur_clk]); clk_disable_unprepare(sc->clk_bus[sc->cur_clk]);
#endif #endif
for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
if (sc->clk_bus[ptr]) {
clk_put(sc->clk_bus[ptr]);
}
}
clk_disable_unprepare(sc->clk_io); clk_disable_unprepare(sc->clk_io);
clk_put(sc->clk_io);
sdhci_free_host(host); sdhci_free_host(host);
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
......
/*
* SDHCI support for SiRF primaII and marco SoCs
*
* Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
*
* Licensed under GPLv2 or later.
*/
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/mmc/host.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/pinctrl/consumer.h>
#include "sdhci-pltfm.h"
struct sdhci_sirf_priv {
struct clk *clk;
int gpio_cd;
};
static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_sirf_priv *priv = pltfm_host->priv;
return clk_get_rate(priv->clk);
}
static struct sdhci_ops sdhci_sirf_ops = {
.get_max_clock = sdhci_sirf_get_max_clk,
};
static struct sdhci_pltfm_data sdhci_sirf_pdata = {
.ops = &sdhci_sirf_ops,
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
SDHCI_QUIRK_DELAY_AFTER_POWER,
};
static int sdhci_sirf_probe(struct platform_device *pdev)
{
struct sdhci_host *host;
struct sdhci_pltfm_host *pltfm_host;
struct sdhci_sirf_priv *priv;
struct pinctrl *pinctrl;
int ret;
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (IS_ERR(pinctrl)) {
dev_err(&pdev->dev, "unable to get pinmux");
return PTR_ERR(pinctrl);
}
priv = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_sirf_priv),
GFP_KERNEL);
if (!priv) {
dev_err(&pdev->dev, "unable to allocate private data");
return -ENOMEM;
}
priv->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(&pdev->dev, "unable to get clock");
return PTR_ERR(priv->clk);
}
if (pdev->dev.of_node) {
priv->gpio_cd = of_get_named_gpio(pdev->dev.of_node,
"cd-gpios", 0);
} else {
priv->gpio_cd = -EINVAL;
}
host = sdhci_pltfm_init(pdev, &sdhci_sirf_pdata);
if (IS_ERR(host)) {
ret = PTR_ERR(host);
goto err_sdhci_pltfm_init;
}
pltfm_host = sdhci_priv(host);
pltfm_host->priv = priv;
sdhci_get_of_property(pdev);
clk_prepare_enable(priv->clk);
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 = mmc_gpio_request_cd(host->mmc, priv->gpio_cd);
if (ret) {
dev_err(&pdev->dev, "card detect irq request failed: %d\n",
ret);
goto err_request_cd;
}
}
return 0;
err_request_cd:
sdhci_remove_host(host, 0);
err_sdhci_add:
clk_disable_unprepare(priv->clk);
sdhci_pltfm_free(pdev);
err_sdhci_pltfm_init:
return ret;
}
static int sdhci_sirf_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_sirf_priv *priv = pltfm_host->priv;
sdhci_pltfm_unregister(pdev);
if (gpio_is_valid(priv->gpio_cd))
mmc_gpio_free_cd(host->mmc);
clk_disable_unprepare(priv->clk);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int sdhci_sirf_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_sirf_priv *priv = pltfm_host->priv;
int ret;
ret = sdhci_suspend_host(host);
if (ret)
return ret;
clk_disable(priv->clk);
return 0;
}
static int sdhci_sirf_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_sirf_priv *priv = pltfm_host->priv;
int ret;
ret = clk_enable(priv->clk);
if (ret) {
dev_dbg(dev, "Resume: Error enabling clock\n");
return ret;
}
return sdhci_resume_host(host);
}
static SIMPLE_DEV_PM_OPS(sdhci_sirf_pm_ops, sdhci_sirf_suspend, sdhci_sirf_resume);
#endif
static const struct of_device_id sdhci_sirf_of_match[] = {
{ .compatible = "sirf,prima2-sdhc" },
{ }
};
MODULE_DEVICE_TABLE(of, sdhci_sirf_of_match);
static struct platform_driver sdhci_sirf_driver = {
.driver = {
.name = "sdhci-sirf",
.owner = THIS_MODULE,
.of_match_table = sdhci_sirf_of_match,
#ifdef CONFIG_PM_SLEEP
.pm = &sdhci_sirf_pm_ops,
#endif
},
.probe = sdhci_sirf_probe,
.remove = sdhci_sirf_remove,
};
module_platform_driver(sdhci_sirf_driver);
MODULE_DESCRIPTION("SDHCI driver for SiRFprimaII/SiRFmarco");
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
MODULE_LICENSE("GPL v2");
...@@ -36,7 +36,7 @@ struct spear_sdhci { ...@@ -36,7 +36,7 @@ struct spear_sdhci {
}; };
/* sdhci ops */ /* sdhci ops */
static struct sdhci_ops sdhci_pltfm_ops = { static const struct sdhci_ops sdhci_pltfm_ops = {
/* Nothing to do for now. */ /* Nothing to do for now. */
}; };
...@@ -291,7 +291,7 @@ static int sdhci_remove(struct platform_device *pdev) ...@@ -291,7 +291,7 @@ static int sdhci_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
static int sdhci_suspend(struct device *dev) static int sdhci_suspend(struct device *dev)
{ {
struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_host *host = dev_get_drvdata(dev);
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/mmc/card.h> #include <linux/mmc/card.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/slot-gpio.h>
#include <asm/gpio.h> #include <asm/gpio.h>
...@@ -38,16 +39,13 @@ ...@@ -38,16 +39,13 @@
#define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2) #define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2)
struct sdhci_tegra_soc_data { struct sdhci_tegra_soc_data {
struct sdhci_pltfm_data *pdata; const struct sdhci_pltfm_data *pdata;
u32 nvquirks; u32 nvquirks;
}; };
struct sdhci_tegra { struct sdhci_tegra {
const struct sdhci_tegra_soc_data *soc_data; const struct sdhci_tegra_soc_data *soc_data;
int cd_gpio;
int wp_gpio;
int power_gpio; int power_gpio;
int is_8bit;
}; };
static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg) static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg)
...@@ -107,23 +105,9 @@ static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg) ...@@ -107,23 +105,9 @@ static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host) static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); return mmc_gpio_get_ro(host->mmc);
struct sdhci_tegra *tegra_host = pltfm_host->priv;
if (!gpio_is_valid(tegra_host->wp_gpio))
return -1;
return gpio_get_value(tegra_host->wp_gpio);
} }
static irqreturn_t carddetect_irq(int irq, void *data)
{
struct sdhci_host *sdhost = (struct sdhci_host *)data;
tasklet_schedule(&sdhost->card_tasklet);
return IRQ_HANDLED;
};
static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask) static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
...@@ -145,12 +129,11 @@ static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask) ...@@ -145,12 +129,11 @@ static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask)
static int tegra_sdhci_buswidth(struct sdhci_host *host, int bus_width) static int tegra_sdhci_buswidth(struct sdhci_host *host, int bus_width)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_tegra *tegra_host = pltfm_host->priv;
u32 ctrl; u32 ctrl;
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
if (tegra_host->is_8bit && bus_width == MMC_BUS_WIDTH_8) { if ((host->mmc->caps & MMC_CAP_8_BIT_DATA) &&
(bus_width == MMC_BUS_WIDTH_8)) {
ctrl &= ~SDHCI_CTRL_4BITBUS; ctrl &= ~SDHCI_CTRL_4BITBUS;
ctrl |= SDHCI_CTRL_8BITBUS; ctrl |= SDHCI_CTRL_8BITBUS;
} else { } else {
...@@ -164,7 +147,7 @@ static int tegra_sdhci_buswidth(struct sdhci_host *host, int bus_width) ...@@ -164,7 +147,7 @@ static int tegra_sdhci_buswidth(struct sdhci_host *host, int bus_width)
return 0; return 0;
} }
static struct sdhci_ops tegra_sdhci_ops = { static const struct sdhci_ops tegra_sdhci_ops = {
.get_ro = tegra_sdhci_get_ro, .get_ro = tegra_sdhci_get_ro,
.read_l = tegra_sdhci_readl, .read_l = tegra_sdhci_readl,
.read_w = tegra_sdhci_readw, .read_w = tegra_sdhci_readw,
...@@ -173,8 +156,7 @@ static struct sdhci_ops tegra_sdhci_ops = { ...@@ -173,8 +156,7 @@ static struct sdhci_ops tegra_sdhci_ops = {
.platform_reset_exit = tegra_sdhci_reset_exit, .platform_reset_exit = tegra_sdhci_reset_exit,
}; };
#ifdef CONFIG_ARCH_TEGRA_2x_SOC static const struct sdhci_pltfm_data sdhci_tegra20_pdata = {
static struct sdhci_pltfm_data sdhci_tegra20_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_SINGLE_POWER_WRITE | SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_NO_HISPD_BIT |
...@@ -187,10 +169,8 @@ static struct sdhci_tegra_soc_data soc_data_tegra20 = { ...@@ -187,10 +169,8 @@ static struct sdhci_tegra_soc_data soc_data_tegra20 = {
.nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 | .nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 |
NVQUIRK_ENABLE_BLOCK_GAP_DET, NVQUIRK_ENABLE_BLOCK_GAP_DET,
}; };
#endif
#ifdef CONFIG_ARCH_TEGRA_3x_SOC static const struct sdhci_pltfm_data sdhci_tegra30_pdata = {
static struct sdhci_pltfm_data sdhci_tegra30_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_SINGLE_POWER_WRITE | SDHCI_QUIRK_SINGLE_POWER_WRITE |
...@@ -203,32 +183,37 @@ static struct sdhci_tegra_soc_data soc_data_tegra30 = { ...@@ -203,32 +183,37 @@ static struct sdhci_tegra_soc_data soc_data_tegra30 = {
.pdata = &sdhci_tegra30_pdata, .pdata = &sdhci_tegra30_pdata,
.nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300, .nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300,
}; };
#endif
static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC,
.ops = &tegra_sdhci_ops,
};
static struct sdhci_tegra_soc_data soc_data_tegra114 = {
.pdata = &sdhci_tegra114_pdata,
};
static const struct of_device_id sdhci_tegra_dt_match[] = { static const struct of_device_id sdhci_tegra_dt_match[] = {
#ifdef CONFIG_ARCH_TEGRA_3x_SOC { .compatible = "nvidia,tegra114-sdhci", .data = &soc_data_tegra114 },
{ .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 }, { .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 },
#endif
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
{ .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 }, { .compatible = "nvidia,tegra20-sdhci", .data = &soc_data_tegra20 },
#endif
{} {}
}; };
MODULE_DEVICE_TABLE(of, sdhci_dt_ids); MODULE_DEVICE_TABLE(of, sdhci_tegra_dt_match);
static void sdhci_tegra_parse_dt(struct device *dev, static void sdhci_tegra_parse_dt(struct device *dev)
struct sdhci_tegra *tegra_host)
{ {
struct device_node *np = dev->of_node; struct device_node *np = dev->of_node;
u32 bus_width; struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_tegra *tegra_host = pltfm_host->priv;
tegra_host->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
tegra_host->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
tegra_host->power_gpio = of_get_named_gpio(np, "power-gpios", 0); tegra_host->power_gpio = of_get_named_gpio(np, "power-gpios", 0);
mmc_of_parse(host->mmc);
if (of_property_read_u32(np, "bus-width", &bus_width) == 0 &&
bus_width == 8)
tegra_host->is_8bit = 1;
} }
static int sdhci_tegra_probe(struct platform_device *pdev) static int sdhci_tegra_probe(struct platform_device *pdev)
...@@ -260,7 +245,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev) ...@@ -260,7 +245,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
tegra_host->soc_data = soc_data; tegra_host->soc_data = soc_data;
pltfm_host->priv = tegra_host; pltfm_host->priv = tegra_host;
sdhci_tegra_parse_dt(&pdev->dev, tegra_host); sdhci_tegra_parse_dt(&pdev->dev);
if (gpio_is_valid(tegra_host->power_gpio)) { if (gpio_is_valid(tegra_host->power_gpio)) {
rc = gpio_request(tegra_host->power_gpio, "sdhci_power"); rc = gpio_request(tegra_host->power_gpio, "sdhci_power");
...@@ -272,37 +257,6 @@ static int sdhci_tegra_probe(struct platform_device *pdev) ...@@ -272,37 +257,6 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
gpio_direction_output(tegra_host->power_gpio, 1); gpio_direction_output(tegra_host->power_gpio, 1);
} }
if (gpio_is_valid(tegra_host->cd_gpio)) {
rc = gpio_request(tegra_host->cd_gpio, "sdhci_cd");
if (rc) {
dev_err(mmc_dev(host->mmc),
"failed to allocate cd gpio\n");
goto err_cd_req;
}
gpio_direction_input(tegra_host->cd_gpio);
rc = request_irq(gpio_to_irq(tegra_host->cd_gpio),
carddetect_irq,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
mmc_hostname(host->mmc), host);
if (rc) {
dev_err(mmc_dev(host->mmc), "request irq error\n");
goto err_cd_irq_req;
}
}
if (gpio_is_valid(tegra_host->wp_gpio)) {
rc = gpio_request(tegra_host->wp_gpio, "sdhci_wp");
if (rc) {
dev_err(mmc_dev(host->mmc),
"failed to allocate wp gpio\n");
goto err_wp_req;
}
gpio_direction_input(tegra_host->wp_gpio);
}
clk = clk_get(mmc_dev(host->mmc), NULL); clk = clk_get(mmc_dev(host->mmc), NULL);
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
dev_err(mmc_dev(host->mmc), "clk err\n"); dev_err(mmc_dev(host->mmc), "clk err\n");
...@@ -312,9 +266,6 @@ static int sdhci_tegra_probe(struct platform_device *pdev) ...@@ -312,9 +266,6 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
clk_prepare_enable(clk); clk_prepare_enable(clk);
pltfm_host->clk = clk; pltfm_host->clk = clk;
if (tegra_host->is_8bit)
host->mmc->caps |= MMC_CAP_8_BIT_DATA;
rc = sdhci_add_host(host); rc = sdhci_add_host(host);
if (rc) if (rc)
goto err_add_host; goto err_add_host;
...@@ -325,15 +276,6 @@ static int sdhci_tegra_probe(struct platform_device *pdev) ...@@ -325,15 +276,6 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
clk_disable_unprepare(pltfm_host->clk); clk_disable_unprepare(pltfm_host->clk);
clk_put(pltfm_host->clk); clk_put(pltfm_host->clk);
err_clk_get: err_clk_get:
if (gpio_is_valid(tegra_host->wp_gpio))
gpio_free(tegra_host->wp_gpio);
err_wp_req:
if (gpio_is_valid(tegra_host->cd_gpio))
free_irq(gpio_to_irq(tegra_host->cd_gpio), host);
err_cd_irq_req:
if (gpio_is_valid(tegra_host->cd_gpio))
gpio_free(tegra_host->cd_gpio);
err_cd_req:
if (gpio_is_valid(tegra_host->power_gpio)) if (gpio_is_valid(tegra_host->power_gpio))
gpio_free(tegra_host->power_gpio); gpio_free(tegra_host->power_gpio);
err_power_req: err_power_req:
...@@ -351,14 +293,6 @@ static int sdhci_tegra_remove(struct platform_device *pdev) ...@@ -351,14 +293,6 @@ static int sdhci_tegra_remove(struct platform_device *pdev)
sdhci_remove_host(host, dead); sdhci_remove_host(host, dead);
if (gpio_is_valid(tegra_host->wp_gpio))
gpio_free(tegra_host->wp_gpio);
if (gpio_is_valid(tegra_host->cd_gpio)) {
free_irq(gpio_to_irq(tegra_host->cd_gpio), host);
gpio_free(tegra_host->cd_gpio);
}
if (gpio_is_valid(tegra_host->power_gpio)) if (gpio_is_valid(tegra_host->power_gpio))
gpio_free(tegra_host->power_gpio); gpio_free(tegra_host->power_gpio);
......
...@@ -1581,6 +1581,37 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -1581,6 +1581,37 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
sdhci_runtime_pm_put(host); sdhci_runtime_pm_put(host);
} }
static int sdhci_do_get_cd(struct sdhci_host *host)
{
int gpio_cd = mmc_gpio_get_cd(host->mmc);
if (host->flags & SDHCI_DEVICE_DEAD)
return 0;
/* If polling/nonremovable, assume that the card is always present. */
if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) ||
(host->mmc->caps & MMC_CAP_NONREMOVABLE))
return 1;
/* Try slot gpio detect */
if (!IS_ERR_VALUE(gpio_cd))
return !!gpio_cd;
/* Host native card detect */
return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
}
static int sdhci_get_cd(struct mmc_host *mmc)
{
struct sdhci_host *host = mmc_priv(mmc);
int ret;
sdhci_runtime_pm_get(host);
ret = sdhci_do_get_cd(host);
sdhci_runtime_pm_put(host);
return ret;
}
static int sdhci_check_ro(struct sdhci_host *host) static int sdhci_check_ro(struct sdhci_host *host)
{ {
unsigned long flags; unsigned long flags;
...@@ -2038,6 +2069,7 @@ static void sdhci_card_event(struct mmc_host *mmc) ...@@ -2038,6 +2069,7 @@ static void sdhci_card_event(struct mmc_host *mmc)
static const struct mmc_host_ops sdhci_ops = { static const struct mmc_host_ops sdhci_ops = {
.request = sdhci_request, .request = sdhci_request,
.set_ios = sdhci_set_ios, .set_ios = sdhci_set_ios,
.get_cd = sdhci_get_cd,
.get_ro = sdhci_get_ro, .get_ro = sdhci_get_ro,
.hw_reset = sdhci_hw_reset, .hw_reset = sdhci_hw_reset,
.enable_sdio_irq = sdhci_enable_sdio_irq, .enable_sdio_irq = sdhci_enable_sdio_irq,
...@@ -2907,12 +2939,17 @@ int sdhci_add_host(struct sdhci_host *host) ...@@ -2907,12 +2939,17 @@ int sdhci_add_host(struct sdhci_host *host)
host->vqmmc = NULL; host->vqmmc = NULL;
} }
} else { } else {
regulator_enable(host->vqmmc); ret = regulator_enable(host->vqmmc);
if (!regulator_is_supported_voltage(host->vqmmc, 1700000, if (!regulator_is_supported_voltage(host->vqmmc, 1700000,
1950000)) 1950000))
caps[1] &= ~(SDHCI_SUPPORT_SDR104 | caps[1] &= ~(SDHCI_SUPPORT_SDR104 |
SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR50 |
SDHCI_SUPPORT_DDR50); SDHCI_SUPPORT_DDR50);
if (ret) {
pr_warn("%s: Failed to enable vqmmc regulator: %d\n",
mmc_hostname(mmc), ret);
host->vqmmc = NULL;
}
} }
if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V) if (host->quirks2 & SDHCI_QUIRK2_NO_1_8_V)
......
...@@ -348,13 +348,11 @@ static void wmt_complete_data_request(struct wmt_mci_priv *priv) ...@@ -348,13 +348,11 @@ static void wmt_complete_data_request(struct wmt_mci_priv *priv)
static irqreturn_t wmt_mci_dma_isr(int irq_num, void *data) static irqreturn_t wmt_mci_dma_isr(int irq_num, void *data)
{ {
struct mmc_host *mmc;
struct wmt_mci_priv *priv; struct wmt_mci_priv *priv;
int status; int status;
priv = (struct wmt_mci_priv *)data; priv = (struct wmt_mci_priv *)data;
mmc = priv->mmc;
status = readl(priv->sdmmc_base + SDDMA_CCR) & 0x0F; status = readl(priv->sdmmc_base + SDDMA_CCR) & 0x0F;
...@@ -925,7 +923,7 @@ static int wmt_mci_remove(struct platform_device *pdev) ...@@ -925,7 +923,7 @@ static int wmt_mci_remove(struct platform_device *pdev)
clk_put(priv->clk_sdmmc); clk_put(priv->clk_sdmmc);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, res->end - res->start + 1); release_mem_region(res->start, resource_size(res));
mmc_free_host(mmc); mmc_free_host(mmc);
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
struct mmc_cid { struct mmc_cid {
unsigned int manfid; unsigned int manfid;
char prod_name[8]; char prod_name[8];
unsigned char prv;
unsigned int serial; unsigned int serial;
unsigned short oemid; unsigned short oemid;
unsigned short year; unsigned short year;
......
...@@ -280,6 +280,7 @@ struct mmc_host { ...@@ -280,6 +280,7 @@ struct mmc_host {
#define MMC_CAP2_PACKED_WR (1 << 13) /* Allow packed write */ #define MMC_CAP2_PACKED_WR (1 << 13) /* Allow packed write */
#define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \ #define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \
MMC_CAP2_PACKED_WR) MMC_CAP2_PACKED_WR)
#define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */
mmc_pm_flag_t pm_caps; /* supported pm features */ mmc_pm_flag_t pm_caps; /* supported pm features */
...@@ -361,6 +362,8 @@ struct mmc_host { ...@@ -361,6 +362,8 @@ struct mmc_host {
unsigned int actual_clock; /* Actual HC clock rate */ unsigned int actual_clock; /* Actual HC clock rate */
unsigned int slotno; /* used for sdio acpi binding */
unsigned long private[0] ____cacheline_aligned; unsigned long private[0] ____cacheline_aligned;
}; };
......
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