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().
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.13 (GNU/Linux)
 
 iQIcBAABAgAGBQJRfr+qAAoJEHNBYZ7TNxYMG90QALW6ArdTxkfNKNybCx/s3ttm
 hyP2BB9eXF/FbZ9bGHGuv9NXV/4YZ4yr4c3yV4paOMW3s0z/+IhqajLfCgPFPCGK
 MOk5GAStN/+znBjLy+5V/17EJuVpE+WVwUqDg3RafB8NGQtaClymwPg6R+SMWwL9
 uiRcCVgmgzlk9l+4Z1p9wHUeQlhZQ/Okzj4CjkOpWfgsUpo0PcWQRosd+CHHirWz
 iWnhFBM1cP4Nj59ashYSedu797s29pKGd31JcuWWQE228iykGfcCJWzMr9YMiU6x
 LwESeuTST8b9HblI7WYnFvpVvD9qTuBkkKMIKMNb4E34xBf8+H2zUh1hK7iEnDXt
 W0F1xy3WsxpJ1yF0BY9SqqnNeLpJBOenHlTZfGlf5r+kHWYUUQvvqw/ZdmWStRgv
 mSoqXSmz/oM3rn1KjMritJ9oyr0EH8kHDMAsoiCF0EuGipmenFTdJJiwbh0JZJxK
 bjqPUROtSK8TdPvTw1BPRX5YtJLzsG4HdsI3C8W05BTbCL9iIE1NaWP27nikPVfq
 glt9EilzgR252Wc649OrB7JAHBZjlVFIndNzjziGdxNzH6m1AK05qxTL5hBvba99
 plccrsVMDGWLSmsGVwz7Eo+TLflRCdtrE+7O4NrlydZzp2t24HZrMc9rN8GDWQQE
 dP91YUdpDYrTsUBKiKGQ
 =Pr7P
 -----END PGP SIGNATURE-----

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
  ...
This commit is contained in:
Linus Torvalds 2013-05-04 13:45:17 -07:00
commit 173192958d
49 changed files with 822 additions and 545 deletions

View File

@ -0,0 +1,24 @@
* 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";
};

View File

@ -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
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:
- compatible: should be one of the following
- "samsung,s3c6410-sdhci": For controllers compatible with s3c6410 sdhci
@ -20,38 +13,18 @@ Required SoC Specific Properties:
controller.
Required Board Specific Properties:
- Samsung GPIO variant (will be completely replaced by pinctrl):
- gpios: Should specify the gpios used for clock, command and data lines. The
gpio specifier format depends on the gpio controller.
- Pinctrl variant (preferred if available):
- pinctrl-0: Should specify pin control groups used for this controller.
- pinctrl-names: Should contain only one value - "default".
Optional Board Specific Properties:
- samsung,cd-pinmux-gpio: Specifies the card detect line that is routed
through a pinmux to the card-detect pin of the card slot. This property
should be used only if none of the mmc core card-detect properties are
used. Only for Samsung GPIO variant.
Example:
sdhci@12530000 {
compatible = "samsung,exynos4210-sdhci";
reg = <0x12530000 0x100>;
interrupts = <0 75 0>;
bus-width = <4>;
cd-gpios = <&gpk2 2 2 3 3>;
/* Samsung GPIO variant */
gpios = <&gpk2 0 2 0 3>, /* clock line */
<&gpk2 1 2 0 3>, /* command line */
<&gpk2 3 2 3 3>, /* data line 0 */
<&gpk2 4 2 3 3>, /* data line 1 */
<&gpk2 5 2 3 3>, /* data line 2 */
<&gpk2 6 2 3 3>; /* data line 3 */
/* Pinctrl variant */
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4>;
cd-gpios = <&gpk2 2 0>;
pinctrl-names = "default";
pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4>;
};
Note: This example shows both SoC specific and board specific properties

View File

@ -0,0 +1,18 @@
* 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>;
};

View File

@ -22,6 +22,7 @@ All attributes are read-only.
manfid Manufacturer ID (from CID Register)
name Product Name (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)
erase_size Erase group size
preferred_erase_size Preferred erase size

View File

@ -801,6 +801,7 @@ S: Maintained
F: arch/arm/mach-prima2/
F: drivers/dma/sirf-dma.c
F: drivers/i2c/busses/i2c-sirf.c
F: drivers/mmc/host/sdhci-sirf.c
F: drivers/pinctrl/pinctrl-sirf.c
F: drivers/spi/spi-sirf.c

View File

@ -173,7 +173,6 @@ CONFIG_MMC=y
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_SDIO_UART=m
CONFIG_MMC_ATMELMCI=y
CONFIG_MMC_ATMELMCI_DMA=y
CONFIG_LEDS_ATMEL_PWM=y
CONFIG_LEDS_GPIO=y
CONFIG_LEDS_TRIGGER_TIMER=y

View File

@ -122,7 +122,6 @@ CONFIG_USB_G_SERIAL=m
CONFIG_USB_CDC_COMPOSITE=m
CONFIG_MMC=y
CONFIG_MMC_ATMELMCI=y
CONFIG_MMC_ATMELMCI_DMA=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_ATMEL_PWM=m

View File

@ -102,7 +102,6 @@ CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_LOGO=y
CONFIG_MMC=y
CONFIG_MMC_ATMELMCI=y
CONFIG_MMC_ATMELMCI_DMA=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_ATMEL_PWM=y

View File

@ -152,6 +152,8 @@
compatible = "fsl,mpc5121-sdhc";
reg = <0x1500 0x100>;
interrupts = <8 0x8>;
dmas = <&dma0 30>;
dma-names = "rx-tx";
};
i2c@1700 {

View File

@ -1932,8 +1932,14 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
}
out:
if (!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST))
/* release host only when there are no more requests */
if ((!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) ||
(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);
return ret;
}

View File

@ -22,9 +22,6 @@
#define MMC_QUEUE_BOUNCESZ 65536
#define MMC_REQ_SPECIAL_MASK (REQ_DISCARD | REQ_FLUSH)
/*
* Prepare a MMC request. This just filters out odd stuff.
*/

View File

@ -1,6 +1,8 @@
#ifndef MMC_QUEUE_H
#define MMC_QUEUE_H
#define MMC_REQ_SPECIAL_MASK (REQ_DISCARD | REQ_FLUSH)
struct request;
struct task_struct;

View File

@ -2289,6 +2289,19 @@ int _mmc_detect_card_removed(struct mmc_host *host)
return 1;
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) {
mmc_card_set_removed(host->card);
pr_debug("%s: card remove detected\n", mmc_hostname(host));
@ -2403,6 +2416,9 @@ void mmc_start_host(struct mmc_host *host)
{
host->f_init = max(freqs[0], host->f_min);
host->rescan_disable = 0;
if (host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)
mmc_power_off(host);
else
mmc_power_up(host);
mmc_detect_change(host, 0);
}

View File

@ -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[4] = UNSTUFF_BITS(resp, 64, 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.month = UNSTUFF_BITS(resp, 12, 4);
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)
ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
card->ext_csd.raw_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) {
/*
* Enhanced area feature support -- check whether the eMMC
* card has the Enhanced area enabled. If so, export enhanced
* 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) &&
(ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) {
hc_erase_grp_sz =
@ -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(name, "%s\n", card->cid.prod_name);
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(enhanced_area_offset, "%llu\n",
card->ext_csd.enhanced_area_offset);
@ -645,6 +647,7 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_manfid.attr,
&dev_attr_name.attr,
&dev_attr_oemid.attr,
&dev_attr_prv.attr,
&dev_attr_serial.attr,
&dev_attr_enhanced_area_offset.attr,
&dev_attr_enhanced_area_size.attr,

View File

@ -861,9 +861,11 @@ static void mmc_sdio_detect(struct mmc_host *host)
/* Make sure card is powered before detecting it */
if (host->caps & MMC_CAP_POWER_OFF_CARD) {
err = pm_runtime_get_sync(&host->card->dev);
if (err < 0)
if (err < 0) {
pm_runtime_put_noidle(&host->card->dev);
goto out;
}
}
mmc_claim_host(host);

View File

@ -16,6 +16,7 @@
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/acpi.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@ -137,7 +138,7 @@ static int sdio_bus_probe(struct device *dev)
if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) {
ret = pm_runtime_get_sync(dev);
if (ret < 0)
goto out;
goto disable_runtimepm;
}
/* 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)
disable_runtimepm:
if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
pm_runtime_put_noidle(dev);
out:
return ret;
}
@ -299,6 +299,19 @@ struct sdio_func *sdio_alloc_func(struct mmc_card *card)
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.
*/
@ -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);
sdio_acpi_set_handle(func);
ret = device_add(&func->dev);
if (ret == 0)
if (ret == 0) {
sdio_func_set_present(func);
acpi_dev_pm_attach(&func->dev, false);
}
return ret;
}
@ -326,6 +342,7 @@ void sdio_remove_func(struct sdio_func *func)
if (!sdio_func_present(func))
return;
acpi_dev_pm_detach(&func->dev, false);
device_del(&func->dev);
put_device(&func->dev);
}

View File

@ -190,6 +190,17 @@ config MMC_SDHCI_S3C
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
tristate "Marvell MMP2 SD Host Controller support (PXAV3)"
depends on CLKDEV_LOOKUP
@ -300,16 +311,6 @@ config MMC_ATMELMCI
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
tristate "Qualcomm SDCC Controller Support"
depends on MMC && ARCH_MSM
@ -319,12 +320,12 @@ config MMC_MSM
support for SDIO devices.
config MMC_MXC
tristate "Freescale i.MX21/27/31 Multimedia Card Interface support"
depends on ARCH_MXC
tristate "Freescale i.MX21/27/31 or MPC512x Multimedia Card support"
depends on ARCH_MXC || PPC_MPC512x
help
This selects the Freescale i.MX21, i.MX27 and i.MX31 Multimedia card
Interface. If you have a i.MX platform with a Multimedia Card slot,
say Y or M here.
This selects the Freescale i.MX21, i.MX27, i.MX31 or MPC512x
Multimedia Card Interface. If you have an i.MX or MPC512x platform
with a Multimedia Card slot, say Y or M here.
If unsure, say N.

View File

@ -13,6 +13,7 @@ obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o
obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o
obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.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_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o

View File

@ -476,7 +476,7 @@ static int goldfish_mmc_probe(struct platform_device *pdev)
host->mmc = mmc;
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) {
ret = -ENOMEM;
goto ioremap_failed;

View File

@ -178,6 +178,7 @@ struct atmel_mci {
void __iomem *regs;
struct scatterlist *sg;
unsigned int sg_len;
unsigned int pio_offset;
unsigned int *buffer;
unsigned int buf_size;
@ -892,6 +893,7 @@ static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data)
data->error = -EINPROGRESS;
host->sg = data->sg;
host->sg_len = data->sg_len;
host->data = data;
host->data_chan = NULL;
@ -1826,7 +1828,8 @@ static void atmci_read_data_pio(struct atmel_mci *host)
if (offset == sg->length) {
flush_dcache_page(sg_page(sg));
host->sg = sg = sg_next(sg);
if (!sg)
host->sg_len--;
if (!sg || !host->sg_len)
goto done;
offset = 0;
@ -1839,7 +1842,8 @@ static void atmci_read_data_pio(struct atmel_mci *host)
flush_dcache_page(sg_page(sg));
host->sg = sg = sg_next(sg);
if (!sg)
host->sg_len--;
if (!sg || !host->sg_len)
goto done;
offset = 4 - remaining;
@ -1890,7 +1894,8 @@ static void atmci_write_data_pio(struct atmel_mci *host)
nbytes += 4;
if (offset == sg->length) {
host->sg = sg = sg_next(sg);
if (!sg)
host->sg_len--;
if (!sg || !host->sg_len)
goto done;
offset = 0;
@ -1904,7 +1909,8 @@ static void atmci_write_data_pio(struct atmel_mci *host)
nbytes += remaining;
host->sg = sg = sg_next(sg);
if (!sg) {
host->sg_len--;
if (!sg || !host->sg_len) {
atmci_writel(host, ATMCI_TDR, value);
goto done;
}
@ -2487,10 +2493,8 @@ static int __exit atmci_remove(struct platform_device *pdev)
atmci_readl(host, ATMCI_SR);
clk_disable(host->mck);
#ifdef CONFIG_MMC_ATMELMCI_DMA
if (host->dma.chan)
dma_release_channel(host->dma.chan);
#endif
free_irq(platform_get_irq(pdev, 0), host);
iounmap(host->regs);

View File

@ -1264,12 +1264,14 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!r)
goto out;
dev_warn(&pdev->dev, "RX DMA resource not specified\n");
else
host->rxdma = r->start;
r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!r)
goto out;
dev_warn(&pdev->dev, "TX DMA resource not specified\n");
else
host->txdma = r->start;
host->mem_res = mem;
@ -1488,18 +1490,7 @@ static struct platform_driver davinci_mmcsd_driver = {
.id_table = davinci_mmc_devtype,
};
static int __init davinci_mmcsd_init(void)
{
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_platform_driver_probe(davinci_mmcsd_driver, davinci_mmcsd_probe);
MODULE_AUTHOR("Texas Instruments India");
MODULE_LICENSE("GPL");

View File

@ -152,45 +152,8 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
return 0;
}
static int dw_mci_exynos_setup_bus(struct dw_mci *host,
struct device_node *slot_np, u8 bus_width)
{
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] = {
/* Common capabilities of Exynos4/Exynos5 SoC */
static unsigned long exynos_dwmmc_caps[4] = {
MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
MMC_CAP_CMD23,
@ -198,24 +161,25 @@ static unsigned long exynos5250_dwmmc_caps[4] = {
MMC_CAP_CMD23,
};
static const struct dw_mci_drv_data exynos5250_drv_data = {
.caps = exynos5250_dwmmc_caps,
static const struct dw_mci_drv_data exynos_drv_data = {
.caps = exynos_dwmmc_caps,
.init = dw_mci_exynos_priv_init,
.setup_clock = dw_mci_exynos_setup_clock,
.prepare_command = dw_mci_exynos_prepare_command,
.set_ios = dw_mci_exynos_set_ios,
.parse_dt = dw_mci_exynos_parse_dt,
.setup_bus = dw_mci_exynos_setup_bus,
};
static const struct of_device_id dw_mci_exynos_match[] = {
{ .compatible = "samsung,exynos4412-dw-mshc",
.data = &exynos_drv_data, },
{ .compatible = "samsung,exynos5250-dw-mshc",
.data = &exynos5250_drv_data, },
.data = &exynos_drv_data, },
{},
};
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 of_device_id *match;
@ -230,7 +194,7 @@ static struct platform_driver dw_mci_exynos_pltfm_driver = {
.remove = __exit_p(dw_mci_pltfm_remove),
.driver = {
.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,
},
};

View File

@ -795,9 +795,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
/* DDR mode set */
if (ios->timing == MMC_TIMING_UHS_DDR50)
regs |= (0x1 << slot->id) << 16;
regs |= ((0x1 << slot->id) << 16);
else
regs &= ~(0x1 << slot->id) << 16;
regs &= ~((0x1 << slot->id) << 16);
mci_writel(slot->host, UHS_REG, regs);
@ -818,6 +818,20 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
switch (ios->power_mode) {
case MMC_POWER_UP:
set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
/* Power up slot */
if (slot->host->pdata->setpower)
slot->host->pdata->setpower(slot->id, mmc->ocr_avail);
regs = mci_readl(slot->host, PWREN);
regs |= (1 << slot->id);
mci_writel(slot->host, PWREN, regs);
break;
case MMC_POWER_OFF:
/* Power down slot */
if (slot->host->pdata->setpower)
slot->host->pdata->setpower(slot->id, 0);
regs = mci_readl(slot->host, PWREN);
regs &= ~(1 << slot->id);
mci_writel(slot->host, PWREN, regs);
break;
default:
break;
@ -1191,12 +1205,15 @@ static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt)
static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
{
struct mmc_data *data = host->data;
int init_cnt = cnt;
/* try and push anything in the part_buf */
if (unlikely(host->part_buf_count)) {
int len = dw_mci_push_part_bytes(host, buf, cnt);
buf += len;
cnt -= len;
if (!sg_next(host->sg) || host->part_buf_count == 2) {
if (host->part_buf_count == 2) {
mci_writew(host, DATA(host->data_offset),
host->part_buf16);
host->part_buf_count = 0;
@ -1229,7 +1246,9 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
/* put anything remaining in the part_buf */
if (cnt) {
dw_mci_set_part_bytes(host, buf, cnt);
if (!sg_next(host->sg))
/* Push data if we have reached the expected data length */
if ((data->bytes_xfered + init_cnt) ==
(data->blksz * data->blocks))
mci_writew(host, DATA(host->data_offset),
host->part_buf16);
}
@ -1269,12 +1288,15 @@ static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt)
static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
{
struct mmc_data *data = host->data;
int init_cnt = cnt;
/* try and push anything in the part_buf */
if (unlikely(host->part_buf_count)) {
int len = dw_mci_push_part_bytes(host, buf, cnt);
buf += len;
cnt -= len;
if (!sg_next(host->sg) || host->part_buf_count == 4) {
if (host->part_buf_count == 4) {
mci_writel(host, DATA(host->data_offset),
host->part_buf32);
host->part_buf_count = 0;
@ -1307,7 +1329,9 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
/* put anything remaining in the part_buf */
if (cnt) {
dw_mci_set_part_bytes(host, buf, cnt);
if (!sg_next(host->sg))
/* Push data if we have reached the expected data length */
if ((data->bytes_xfered + init_cnt) ==
(data->blksz * data->blocks))
mci_writel(host, DATA(host->data_offset),
host->part_buf32);
}
@ -1347,13 +1371,17 @@ static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt)
static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
{
struct mmc_data *data = host->data;
int init_cnt = cnt;
/* try and push anything in the part_buf */
if (unlikely(host->part_buf_count)) {
int len = dw_mci_push_part_bytes(host, buf, cnt);
buf += len;
cnt -= len;
if (!sg_next(host->sg) || host->part_buf_count == 8) {
mci_writew(host, DATA(host->data_offset),
if (host->part_buf_count == 8) {
mci_writeq(host, DATA(host->data_offset),
host->part_buf);
host->part_buf_count = 0;
}
@ -1385,7 +1413,9 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
/* put anything remaining in the part_buf */
if (cnt) {
dw_mci_set_part_bytes(host, buf, cnt);
if (!sg_next(host->sg))
/* Push data if we have reached the expected data length */
if ((data->bytes_xfered + init_cnt) ==
(data->blksz * data->blocks))
mci_writeq(host, DATA(host->data_offset),
host->part_buf);
}
@ -1438,7 +1468,7 @@ static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt)
host->pull_data(host, buf, cnt);
}
static void dw_mci_read_data_pio(struct dw_mci *host)
static void dw_mci_read_data_pio(struct dw_mci *host, bool dto)
{
struct sg_mapping_iter *sg_miter = &host->sg_miter;
void *buf;
@ -1446,7 +1476,7 @@ static void dw_mci_read_data_pio(struct dw_mci *host)
struct mmc_data *data = host->data;
int shift = host->data_shift;
u32 status;
unsigned int nbytes = 0, len;
unsigned int len;
unsigned int remain, fcnt;
do {
@ -1465,16 +1495,17 @@ static void dw_mci_read_data_pio(struct dw_mci *host)
if (!len)
break;
dw_mci_pull_data(host, (void *)(buf + offset), len);
data->bytes_xfered += len;
offset += len;
nbytes += len;
remain -= len;
} while (remain);
sg_miter->consumed = offset;
status = mci_readl(host, MINTSTS);
mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
} while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/
data->bytes_xfered += nbytes;
/* if the RXDR is ready read again */
} while ((status & SDMMC_INT_RXDR) ||
(dto && SDMMC_GET_FCNT(mci_readl(host, STATUS))));
if (!remain) {
if (!sg_miter_next(sg_miter))
@ -1485,7 +1516,6 @@ static void dw_mci_read_data_pio(struct dw_mci *host)
return;
done:
data->bytes_xfered += nbytes;
sg_miter_stop(sg_miter);
host->sg = NULL;
smp_wmb();
@ -1500,7 +1530,7 @@ static void dw_mci_write_data_pio(struct dw_mci *host)
struct mmc_data *data = host->data;
int shift = host->data_shift;
u32 status;
unsigned int nbytes = 0, len;
unsigned int len;
unsigned int fifo_depth = host->fifo_depth;
unsigned int remain, fcnt;
@ -1521,8 +1551,8 @@ static void dw_mci_write_data_pio(struct dw_mci *host)
if (!len)
break;
host->push_data(host, (void *)(buf + offset), len);
data->bytes_xfered += len;
offset += len;
nbytes += len;
remain -= len;
} while (remain);
@ -1530,7 +1560,6 @@ static void dw_mci_write_data_pio(struct dw_mci *host)
status = mci_readl(host, MINTSTS);
mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
} while (status & SDMMC_INT_TXDR); /* if TXDR write again */
data->bytes_xfered += nbytes;
if (!remain) {
if (!sg_miter_next(sg_miter))
@ -1541,7 +1570,6 @@ static void dw_mci_write_data_pio(struct dw_mci *host)
return;
done:
data->bytes_xfered += nbytes;
sg_miter_stop(sg_miter);
host->sg = NULL;
smp_wmb();
@ -1563,12 +1591,12 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
{
struct dw_mci *host = dev_id;
u32 pending;
unsigned int pass_count = 0;
int i;
do {
pending = mci_readl(host, MINTSTS); /* read-only mask reg */
if (pending) {
/*
* DTO fix - version 2.10a and below, and only if internal DMA
* is configured.
@ -1579,9 +1607,6 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
pending |= SDMMC_INT_DATA_OVER;
}
if (!pending)
break;
if (pending & DW_MCI_CMD_ERROR_FLAGS) {
mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
host->cmd_status = pending;
@ -1605,7 +1630,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
smp_wmb();
if (host->dir_status == DW_MCI_RECV_STATUS) {
if (host->sg != NULL)
dw_mci_read_data_pio(host);
dw_mci_read_data_pio(host, true);
}
set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
tasklet_schedule(&host->tasklet);
@ -1614,7 +1639,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
if (pending & SDMMC_INT_RXDR) {
mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
if (host->dir_status == DW_MCI_RECV_STATUS && host->sg)
dw_mci_read_data_pio(host);
dw_mci_read_data_pio(host, false);
}
if (pending & SDMMC_INT_TXDR) {
@ -1642,7 +1667,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
}
}
} while (pass_count++ < 5);
}
#ifdef CONFIG_MMC_DW_IDMAC
/* Handle DMA interrupts */
@ -1674,10 +1699,6 @@ static void dw_mci_work_routine_card(struct work_struct *work)
dev_dbg(&slot->mmc->class_dev, "card %s\n",
present ? "inserted" : "removed");
/* Power up slot (before spin_lock, may sleep) */
if (present != 0 && host->pdata->setpower)
host->pdata->setpower(slot->id, mmc->ocr_avail);
spin_lock_bh(&host->lock);
/* Card change detected */
@ -1760,10 +1781,6 @@ static void dw_mci_work_routine_card(struct work_struct *work)
spin_unlock_bh(&host->lock);
/* Power down slot (after spin_unlock, may sleep) */
if (present == 0 && host->pdata->setpower)
host->pdata->setpower(slot->id, 0);
present = dw_mci_get_cd(mmc);
}
@ -1935,14 +1952,6 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
else
bus_width = 1;
if (drv_data && drv_data->setup_bus) {
struct device_node *slot_np;
slot_np = dw_mci_of_find_slot_node(host->dev, slot->id);
ret = drv_data->setup_bus(host, slot_np, bus_width);
if (ret)
goto err_setup_bus;
}
switch (bus_width) {
case 8:
mmc->caps |= MMC_CAP_8_BIT_DATA;
@ -1980,8 +1989,14 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
if (IS_ERR(host->vmmc)) {
pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
host->vmmc = NULL;
} else
regulator_enable(host->vmmc);
} else {
ret = regulator_enable(host->vmmc);
if (ret) {
dev_err(host->dev,
"failed to enable regulator: %d\n", ret);
goto err_setup_bus;
}
}
if (dw_mci_get_cd(mmc))
set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
@ -1990,7 +2005,9 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id);
mmc_add_host(mmc);
ret = mmc_add_host(mmc);
if (ret)
goto err_setup_bus;
#if defined(CONFIG_DEBUG_FS)
dw_mci_init_debugfs(slot);
@ -2289,6 +2306,18 @@ int dw_mci_probe(struct dw_mci *host)
mci_writel(host, CLKENA, 0);
mci_writel(host, CLKSRC, 0);
/*
* In 2.40a spec, Data offset is changed.
* Need to check the version-id and set data-offset for DATA register.
*/
host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
dev_info(host->dev, "Version ID is %04x\n", host->verid);
if (host->verid < DW_MMC_240A)
host->data_offset = DATA_OFFSET;
else
host->data_offset = DATA_240A_OFFSET;
tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
host->card_workqueue = alloc_workqueue("dw-mci-card",
WQ_MEM_RECLAIM | WQ_NON_REENTRANT, 1);
@ -2337,18 +2366,6 @@ int dw_mci_probe(struct dw_mci *host)
goto err_workqueue;
}
/*
* In 2.40a spec, Data offset is changed.
* Need to check the version-id and set data-offset for DATA register.
*/
host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
dev_info(host->dev, "Version ID is %04x\n", host->verid);
if (host->verid < DW_MMC_240A)
host->data_offset = DATA_OFFSET;
else
host->data_offset = DATA_240A_OFFSET;
if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");
@ -2445,8 +2462,14 @@ int dw_mci_resume(struct dw_mci *host)
{
int i, ret;
if (host->vmmc)
regulator_enable(host->vmmc);
if (host->vmmc) {
ret = regulator_enable(host->vmmc);
if (ret) {
dev_err(host->dev,
"failed to enable regulator: %d\n", ret);
return ret;
}
}
if (!mci_wait_reset(host->dev, host)) {
ret = -ENODEV;
@ -2485,7 +2508,7 @@ EXPORT_SYMBOL(dw_mci_resume);
static int __init dw_mci_init(void)
{
printk(KERN_INFO "Synopsys Designware Multimedia Card Interface Driver");
pr_info("Synopsys Designware Multimedia Card Interface Driver\n");
return 0;
}

View File

@ -190,7 +190,6 @@ extern int dw_mci_resume(struct dw_mci *host);
* @prepare_command: handle CMD register extensions.
* @set_ios: handle bus specific extensions.
* @parse_dt: parse implementation specific device tree properties.
* @setup_bus: initialize io-interface
*
* Provide controller implementation specific extensions. The usage of this
* data structure is fully optional and usage of each member in this structure
@ -203,7 +202,5 @@ struct dw_mci_drv_data {
void (*prepare_command)(struct dw_mci *host, u32 *cmdr);
void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
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_ */

View File

@ -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_ptr = sg_virt(data->sg);
if (!nodma)
pr_debug("%s: fallback to PIO for data "
"at 0x%p size %d\n",
mmc_hostname(host->mmc),
dev_dbg(host->dev, "fallback to PIO for data at 0x%p size %d\n",
host->pio_ptr, host->pio_size);
return 1;
} else {
@ -473,8 +471,8 @@ static irqreturn_t mvsd_irq(int irq, void *dev)
if (mrq->data)
err_status = mvsd_finish_data(host, mrq->data, err_status);
if (err_status) {
pr_err("%s: unhandled error status %#04x\n",
mmc_hostname(host->mmc), err_status);
dev_err(host->dev, "unhandled error status %#04x\n",
err_status);
cmd->error = -ENOMSG;
}
@ -491,9 +489,8 @@ static irqreturn_t mvsd_irq(int irq, void *dev)
if (irq_handled)
return IRQ_HANDLED;
pr_err("%s: unhandled interrupt status=0x%04x en=0x%04x "
"pio=%d\n", mmc_hostname(host->mmc), intr_status,
host->intr_en, host->pio_size);
dev_err(host->dev, "unhandled interrupt status=0x%04x en=0x%04x pio=%d\n",
intr_status, host->intr_en, host->pio_size);
return IRQ_NONE;
}
@ -507,10 +504,8 @@ static void mvsd_timeout_timer(unsigned long data)
spin_lock_irqsave(&host->lock, flags);
mrq = host->mrq;
if (mrq) {
pr_err("%s: Timeout waiting for hardware interrupt.\n",
mmc_hostname(host->mmc));
pr_err("%s: hw_state=0x%04x, intr_status=0x%04x "
"intr_en=0x%04x\n", mmc_hostname(host->mmc),
dev_err(host->dev, "Timeout waiting for hardware interrupt.\n");
dev_err(host->dev, "hw_state=0x%04x, intr_status=0x%04x intr_en=0x%04x\n",
mvsd_read(MVSD_HW_STATE),
mvsd_read(MVSD_NOR_INTR_STATUS),
mvsd_read(MVSD_NOR_INTR_EN));
@ -741,8 +736,8 @@ static int __init mvsd_probe(struct platform_device *pdev)
goto out;
}
host->base_clock = mvsd_data->clock / 2;
gpio_card_detect = mvsd_data->gpio_card_detect;
gpio_write_protect = mvsd_data->gpio_write_protect;
gpio_card_detect = mvsd_data->gpio_card_detect ? : -EINVAL;
gpio_write_protect = mvsd_data->gpio_write_protect ? : -EINVAL;
}
mmc->ops = &mvsd_ops;
@ -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);
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;
}
@ -797,13 +792,11 @@ static int __init mvsd_probe(struct platform_device *pdev)
if (ret)
goto out;
pr_notice("%s: %s driver initialized, ",
mmc_hostname(mmc), DRIVER_NAME);
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);
else
printk("lacking card detect (fall back to polling)\n");
dev_notice(&pdev->dev, "lacking card detect (fall back to polling)\n");
return 0;
out:
@ -881,18 +874,7 @@ static struct platform_driver mvsd_driver = {
},
};
static int __init mvsd_init(void)
{
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);
module_platform_driver_probe(mvsd_driver, mvsd_probe);
/* maximum card clock frequency (default 50MHz) */
module_param(maxfreq, int, 0);

View File

@ -34,10 +34,14 @@
#include <linux/regulator/consumer.h>
#include <linux/dmaengine.h>
#include <linux/types.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_dma.h>
#include <linux/of_gpio.h>
#include <linux/mmc/slot-gpio.h>
#include <asm/dma.h>
#include <asm/irq.h>
#include <asm/sizes.h>
#include <linux/platform_data/mmc-mxcmmc.h>
#include <linux/platform_data/dma-imx.h>
@ -115,6 +119,7 @@
enum mxcmci_type {
IMX21_MMC,
IMX31_MMC,
MPC512X_MMC,
};
struct mxcmci_host {
@ -160,24 +165,80 @@ struct mxcmci_host {
enum mxcmci_type devtype;
};
static struct platform_device_id mxcmci_devtype[] = {
static const struct platform_device_id mxcmci_devtype[] = {
{
.name = "imx21-mmc",
.driver_data = IMX21_MMC,
}, {
.name = "imx31-mmc",
.driver_data = IMX31_MMC,
}, {
.name = "mpc512x-sdhc",
.driver_data = MPC512X_MMC,
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(platform, mxcmci_devtype);
static const struct of_device_id mxcmci_of_match[] = {
{
.compatible = "fsl,imx21-mmc",
.data = &mxcmci_devtype[IMX21_MMC],
}, {
.compatible = "fsl,imx31-mmc",
.data = &mxcmci_devtype[IMX31_MMC],
}, {
.compatible = "fsl,mpc5121-sdhc",
.data = &mxcmci_devtype[MPC512X_MMC],
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(of, mxcmci_of_match);
static inline int is_imx31_mmc(struct mxcmci_host *host)
{
return host->devtype == IMX31_MMC;
}
static inline int is_mpc512x_mmc(struct mxcmci_host *host)
{
return host->devtype == MPC512X_MMC;
}
static inline u32 mxcmci_readl(struct mxcmci_host *host, int reg)
{
if (IS_ENABLED(CONFIG_PPC_MPC512x))
return ioread32be(host->base + reg);
else
return readl(host->base + reg);
}
static inline void mxcmci_writel(struct mxcmci_host *host, u32 val, int reg)
{
if (IS_ENABLED(CONFIG_PPC_MPC512x))
iowrite32be(val, host->base + reg);
else
writel(val, host->base + reg);
}
static inline u16 mxcmci_readw(struct mxcmci_host *host, int reg)
{
if (IS_ENABLED(CONFIG_PPC_MPC512x))
return ioread32be(host->base + reg);
else
return readw(host->base + reg);
}
static inline void mxcmci_writew(struct mxcmci_host *host, u16 val, int reg)
{
if (IS_ENABLED(CONFIG_PPC_MPC512x))
iowrite32be(val, host->base + reg);
else
writew(val, host->base + reg);
}
static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios);
static inline void mxcmci_init_ocr(struct mxcmci_host *host)
@ -229,17 +290,40 @@ static void mxcmci_softreset(struct mxcmci_host *host)
dev_dbg(mmc_dev(host->mmc), "mxcmci_softreset\n");
/* reset sequence */
writew(STR_STP_CLK_RESET, host->base + MMC_REG_STR_STP_CLK);
writew(STR_STP_CLK_RESET | STR_STP_CLK_START_CLK,
host->base + MMC_REG_STR_STP_CLK);
mxcmci_writew(host, STR_STP_CLK_RESET, MMC_REG_STR_STP_CLK);
mxcmci_writew(host, STR_STP_CLK_RESET | STR_STP_CLK_START_CLK,
MMC_REG_STR_STP_CLK);
for (i = 0; i < 8; i++)
writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK);
mxcmci_writew(host, STR_STP_CLK_START_CLK, MMC_REG_STR_STP_CLK);
writew(0xff, host->base + MMC_REG_RES_TO);
mxcmci_writew(host, 0xff, MMC_REG_RES_TO);
}
static int mxcmci_setup_dma(struct mmc_host *mmc);
#if IS_ENABLED(CONFIG_PPC_MPC512x)
static inline void buffer_swap32(u32 *buf, int len)
{
int i;
for (i = 0; i < ((len + 3) / 4); i++) {
st_le32(buf, *buf);
buf++;
}
}
static void mxcmci_swap_buffers(struct mmc_data *data)
{
struct scatterlist *sg;
int i;
for_each_sg(data->sg, sg, data->sg_len, i)
buffer_swap32(sg_virt(sg), sg->length);
}
#else
static inline void mxcmci_swap_buffers(struct mmc_data *data) {}
#endif
static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
{
unsigned int nob = data->blocks;
@ -255,8 +339,8 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
host->data = data;
data->bytes_xfered = 0;
writew(nob, host->base + MMC_REG_NOB);
writew(blksz, host->base + MMC_REG_BLK_LEN);
mxcmci_writew(host, nob, MMC_REG_NOB);
mxcmci_writew(host, blksz, MMC_REG_BLK_LEN);
host->datasize = datasize;
if (!mxcmci_use_dma(host))
@ -275,6 +359,8 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
} else {
host->dma_dir = DMA_TO_DEVICE;
slave_dirn = DMA_MEM_TO_DEV;
mxcmci_swap_buffers(data);
}
nents = dma_map_sg(host->dma->device->dev, data->sg,
@ -312,13 +398,13 @@ static void mxcmci_dma_callback(void *data)
del_timer(&host->watchdog);
stat = readl(host->base + MMC_REG_STATUS);
writel(stat & ~STATUS_DATA_TRANS_DONE, host->base + MMC_REG_STATUS);
stat = mxcmci_readl(host, MMC_REG_STATUS);
mxcmci_writel(host, stat & ~STATUS_DATA_TRANS_DONE, MMC_REG_STATUS);
dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat);
if (stat & STATUS_READ_OP_DONE)
writel(STATUS_READ_OP_DONE, host->base + MMC_REG_STATUS);
mxcmci_writel(host, STATUS_READ_OP_DONE, MMC_REG_STATUS);
mxcmci_data_done(host, stat);
}
@ -366,12 +452,12 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
spin_lock_irqsave(&host->lock, flags);
if (host->use_sdio)
int_cntr |= INT_SDIO_IRQ_EN;
writel(int_cntr, host->base + MMC_REG_INT_CNTR);
mxcmci_writel(host, int_cntr, MMC_REG_INT_CNTR);
spin_unlock_irqrestore(&host->lock, flags);
writew(cmd->opcode, host->base + MMC_REG_CMD);
writel(cmd->arg, host->base + MMC_REG_ARG);
writew(cmdat, host->base + MMC_REG_CMD_DAT_CONT);
mxcmci_writew(host, cmd->opcode, MMC_REG_CMD);
mxcmci_writel(host, cmd->arg, MMC_REG_ARG);
mxcmci_writew(host, cmdat, MMC_REG_CMD_DAT_CONT);
return 0;
}
@ -385,7 +471,7 @@ static void mxcmci_finish_request(struct mxcmci_host *host,
spin_lock_irqsave(&host->lock, flags);
if (host->use_sdio)
int_cntr |= INT_SDIO_IRQ_EN;
writel(int_cntr, host->base + MMC_REG_INT_CNTR);
mxcmci_writel(host, int_cntr, MMC_REG_INT_CNTR);
spin_unlock_irqrestore(&host->lock, flags);
host->req = NULL;
@ -400,9 +486,11 @@ static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat)
struct mmc_data *data = host->data;
int data_error;
if (mxcmci_use_dma(host))
if (mxcmci_use_dma(host)) {
dma_unmap_sg(host->dma->device->dev, data->sg, data->sg_len,
host->dma_dir);
mxcmci_swap_buffers(data);
}
if (stat & STATUS_ERR_MASK) {
dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",
@ -460,14 +548,14 @@ static void mxcmci_read_response(struct mxcmci_host *host, unsigned int stat)
if (cmd->flags & MMC_RSP_PRESENT) {
if (cmd->flags & MMC_RSP_136) {
for (i = 0; i < 4; i++) {
a = readw(host->base + MMC_REG_RES_FIFO);
b = readw(host->base + MMC_REG_RES_FIFO);
a = mxcmci_readw(host, MMC_REG_RES_FIFO);
b = mxcmci_readw(host, MMC_REG_RES_FIFO);
cmd->resp[i] = a << 16 | b;
}
} else {
a = readw(host->base + MMC_REG_RES_FIFO);
b = readw(host->base + MMC_REG_RES_FIFO);
c = readw(host->base + MMC_REG_RES_FIFO);
a = mxcmci_readw(host, MMC_REG_RES_FIFO);
b = mxcmci_readw(host, MMC_REG_RES_FIFO);
c = mxcmci_readw(host, MMC_REG_RES_FIFO);
cmd->resp[0] = a << 24 | b << 8 | c >> 8;
}
}
@ -479,7 +567,7 @@ static int mxcmci_poll_status(struct mxcmci_host *host, u32 mask)
unsigned long timeout = jiffies + HZ;
do {
stat = readl(host->base + MMC_REG_STATUS);
stat = mxcmci_readl(host, MMC_REG_STATUS);
if (stat & STATUS_ERR_MASK)
return stat;
if (time_after(jiffies, timeout)) {
@ -503,7 +591,7 @@ static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes)
STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE);
if (stat)
return stat;
*buf++ = readl(host->base + MMC_REG_BUFFER_ACCESS);
*buf++ = cpu_to_le32(mxcmci_readl(host, MMC_REG_BUFFER_ACCESS));
bytes -= 4;
}
@ -515,7 +603,7 @@ static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes)
STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE);
if (stat)
return stat;
tmp = readl(host->base + MMC_REG_BUFFER_ACCESS);
tmp = cpu_to_le32(mxcmci_readl(host, MMC_REG_BUFFER_ACCESS));
memcpy(b, &tmp, bytes);
}
@ -531,7 +619,7 @@ static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes)
stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
if (stat)
return stat;
writel(*buf++, host->base + MMC_REG_BUFFER_ACCESS);
mxcmci_writel(host, cpu_to_le32(*buf++), MMC_REG_BUFFER_ACCESS);
bytes -= 4;
}
@ -544,7 +632,7 @@ static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes)
return stat;
memcpy(&tmp, b, bytes);
writel(tmp, host->base + MMC_REG_BUFFER_ACCESS);
mxcmci_writel(host, cpu_to_le32(tmp), MMC_REG_BUFFER_ACCESS);
}
stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
@ -590,8 +678,8 @@ static void mxcmci_datawork(struct work_struct *work)
datawork);
int datastat = mxcmci_transfer_data(host);
writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
host->base + MMC_REG_STATUS);
mxcmci_writel(host, STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
MMC_REG_STATUS);
mxcmci_finish_data(host, datastat);
if (host->req->stop) {
@ -606,24 +694,40 @@ static void mxcmci_datawork(struct work_struct *work)
static void mxcmci_data_done(struct mxcmci_host *host, unsigned int stat)
{
struct mmc_data *data = host->data;
struct mmc_request *req;
int data_error;
unsigned long flags;
if (!data)
spin_lock_irqsave(&host->lock, flags);
if (!host->data) {
spin_unlock_irqrestore(&host->lock, flags);
return;
}
if (!host->req) {
spin_unlock_irqrestore(&host->lock, flags);
return;
}
req = host->req;
if (!req->stop)
host->req = NULL; /* we will handle finish req below */
data_error = mxcmci_finish_data(host, stat);
spin_unlock_irqrestore(&host->lock, flags);
mxcmci_read_response(host, stat);
host->cmd = NULL;
if (host->req->stop) {
if (mxcmci_start_cmd(host, host->req->stop, 0)) {
mxcmci_finish_request(host, host->req);
if (req->stop) {
if (mxcmci_start_cmd(host, req->stop, 0)) {
mxcmci_finish_request(host, req);
return;
}
} else {
mxcmci_finish_request(host, host->req);
mxcmci_finish_request(host, req);
}
}
@ -653,9 +757,11 @@ static irqreturn_t mxcmci_irq(int irq, void *devid)
bool sdio_irq;
u32 stat;
stat = readl(host->base + MMC_REG_STATUS);
writel(stat & ~(STATUS_SDIO_INT_ACTIVE | STATUS_DATA_TRANS_DONE |
STATUS_WRITE_OP_DONE), host->base + MMC_REG_STATUS);
stat = mxcmci_readl(host, MMC_REG_STATUS);
mxcmci_writel(host,
stat & ~(STATUS_SDIO_INT_ACTIVE | STATUS_DATA_TRANS_DONE |
STATUS_WRITE_OP_DONE),
MMC_REG_STATUS);
dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat);
@ -665,11 +771,11 @@ static irqreturn_t mxcmci_irq(int irq, void *devid)
if (mxcmci_use_dma(host) &&
(stat & (STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE)))
writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
host->base + MMC_REG_STATUS);
mxcmci_writel(host, STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
MMC_REG_STATUS);
if (sdio_irq) {
writel(STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS);
mxcmci_writel(host, STATUS_SDIO_INT_ACTIVE, MMC_REG_STATUS);
mmc_signal_sdio_irq(host->mmc);
}
@ -751,7 +857,7 @@ static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios)
prescaler <<= 1;
}
writew((prescaler << 4) | divider, host->base + MMC_REG_CLK_RATE);
mxcmci_writew(host, (prescaler << 4) | divider, MMC_REG_CLK_RATE);
dev_dbg(mmc_dev(host->mmc), "scaler: %d divider: %d in: %d out: %d\n",
prescaler, divider, clk_in, clk_ios);
@ -814,9 +920,9 @@ static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (ios->clock) {
mxcmci_set_clk_rate(host, ios->clock);
writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK);
mxcmci_writew(host, STR_STP_CLK_START_CLK, MMC_REG_STR_STP_CLK);
} else {
writew(STR_STP_CLK_STOP_CLK, host->base + MMC_REG_STR_STP_CLK);
mxcmci_writew(host, STR_STP_CLK_STOP_CLK, MMC_REG_STR_STP_CLK);
}
host->clock = ios->clock;
@ -839,10 +945,11 @@ static int mxcmci_get_ro(struct mmc_host *mmc)
if (host->pdata && host->pdata->get_ro)
return !!host->pdata->get_ro(mmc_dev(mmc));
/*
* Board doesn't support read only detection; let the mmc core
* decide what to do.
* If board doesn't support read only detection (no mmc_gpio
* context or gpio is invalid), then let the mmc core decide
* what to do.
*/
return -ENOSYS;
return mmc_gpio_get_ro(mmc);
}
static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
@ -853,14 +960,14 @@ static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
spin_lock_irqsave(&host->lock, flags);
host->use_sdio = enable;
int_cntr = readl(host->base + MMC_REG_INT_CNTR);
int_cntr = mxcmci_readl(host, MMC_REG_INT_CNTR);
if (enable)
int_cntr |= INT_SDIO_IRQ_EN;
else
int_cntr &= ~INT_SDIO_IRQ_EN;
writel(int_cntr, host->base + MMC_REG_INT_CNTR);
mxcmci_writel(host, int_cntr, MMC_REG_INT_CNTR);
spin_unlock_irqrestore(&host->lock, flags);
}
@ -898,7 +1005,7 @@ static void mxcmci_watchdog(unsigned long data)
struct mmc_host *mmc = (struct mmc_host *)data;
struct mxcmci_host *host = mmc_priv(mmc);
struct mmc_request *req = host->req;
unsigned int stat = readl(host->base + MMC_REG_STATUS);
unsigned int stat = mxcmci_readl(host, MMC_REG_STATUS);
if (host->dma_dir == DMA_FROM_DEVICE) {
dmaengine_terminate_all(host->dma);
@ -914,6 +1021,7 @@ static void mxcmci_watchdog(unsigned long data)
/* Mark transfer as erroneus and inform the upper layers */
if (host->data)
host->data->error = -ETIMEDOUT;
host->req = NULL;
host->cmd = NULL;
@ -935,9 +1043,14 @@ static int mxcmci_probe(struct platform_device *pdev)
struct mxcmci_host *host = NULL;
struct resource *iores, *r;
int ret = 0, irq;
bool dat3_card_detect = false;
dma_cap_mask_t mask;
const struct of_device_id *of_id;
struct imxmmc_platform_data *pdata = pdev->dev.platform_data;
pr_info("i.MX SDHC driver\n");
pr_info("i.MX/MPC512x SDHC driver\n");
of_id = of_match_device(mxcmci_of_match, &pdev->dev);
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
@ -954,11 +1067,16 @@ static int mxcmci_probe(struct platform_device *pdev)
goto out_release_mem;
}
mmc_of_parse(mmc);
mmc->ops = &mxcmci_ops;
/* For devicetree parsing, the bus width is read from devicetree */
if (pdata)
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
else
mmc->caps |= MMC_CAP_SDIO_IRQ;
/* MMC core transfer sizes tunable parameters */
mmc->max_segs = 64;
mmc->max_blk_size = 2048;
mmc->max_blk_count = 65535;
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
@ -971,14 +1089,30 @@ static int mxcmci_probe(struct platform_device *pdev)
goto out_free;
}
host->mmc = mmc;
host->pdata = pdev->dev.platform_data;
if (of_id) {
const struct platform_device_id *id_entry = of_id->data;
host->devtype = id_entry->driver_data;
} else {
host->devtype = pdev->id_entry->driver_data;
}
/* adjust max_segs after devtype detection */
if (!is_mpc512x_mmc(host))
mmc->max_segs = 64;
host->mmc = mmc;
host->pdata = pdata;
spin_lock_init(&host->lock);
if (pdata)
dat3_card_detect = pdata->dat3_card_detect;
else if (!(mmc->caps & MMC_CAP_NONREMOVABLE)
&& !of_property_read_bool(pdev->dev.of_node, "cd-gpios"))
dat3_card_detect = true;
mxcmci_init_ocr(host);
if (host->pdata && host->pdata->dat3_card_detect)
if (dat3_card_detect)
host->default_irq_mask =
INT_CARD_INSERTION_EN | INT_CARD_REMOVAL_EN;
else
@ -1004,7 +1138,7 @@ static int mxcmci_probe(struct platform_device *pdev)
mxcmci_softreset(host);
host->rev_no = readw(host->base + MMC_REG_REV_NO);
host->rev_no = mxcmci_readw(host, MMC_REG_REV_NO);
if (host->rev_no != 0x400) {
ret = -ENODEV;
dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n",
@ -1016,10 +1150,13 @@ static int mxcmci_probe(struct platform_device *pdev)
mmc->f_max = clk_get_rate(host->clk_per) >> 1;
/* recommended in data sheet */
writew(0x2db4, host->base + MMC_REG_READ_TO);
mxcmci_writew(host, 0x2db4, MMC_REG_READ_TO);
writel(host->default_irq_mask, host->base + MMC_REG_INT_CNTR);
mxcmci_writel(host, host->default_irq_mask, MMC_REG_INT_CNTR);
if (!host->pdata) {
host->dma = dma_request_slave_channel(&pdev->dev, "rx-tx");
} else {
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (r) {
host->dmareq = r->start;
@ -1029,12 +1166,12 @@ static int mxcmci_probe(struct platform_device *pdev)
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
host->dma = dma_request_channel(mask, filter, host);
}
}
if (host->dma)
mmc->max_seg_size = dma_get_max_seg_size(
host->dma->device->dev);
}
if (!host->dma)
else
dev_info(mmc_dev(host->mmc), "dma not available. Using PIO\n");
INIT_WORK(&host->datawork, mxcmci_datawork);
@ -1052,12 +1189,12 @@ static int mxcmci_probe(struct platform_device *pdev)
goto out_free_irq;
}
mmc_add_host(mmc);
init_timer(&host->watchdog);
host->watchdog.function = &mxcmci_watchdog;
host->watchdog.data = (unsigned long)mmc;
mmc_add_host(mmc);
return 0;
out_free_irq:
@ -1153,6 +1290,7 @@ static struct platform_driver mxcmci_driver = {
#ifdef CONFIG_PM
.pm = &mxcmci_pm_ops,
#endif
.of_match_table = mxcmci_of_match,
}
};

View File

@ -72,6 +72,9 @@ struct mxs_mmc_host {
int sdio_irq_en;
int wp_gpio;
bool wp_inverted;
bool cd_inverted;
bool broken_cd;
bool non_removable;
};
static int mxs_mmc_get_ro(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_ssp *ssp = &host->ssp;
return !(readl(ssp->base + HW_SSP_STATUS(ssp)) &
BM_SSP_STATUS_CARD_DETECT);
return host->non_removable || host->broken_cd ||
!(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)
@ -686,11 +690,16 @@ static int mxs_mmc_probe(struct platform_device *pdev)
mmc->caps |= MMC_CAP_4_BIT_DATA;
else if (bus_width == 8)
mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
host->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);
if (flags & OF_GPIO_ACTIVE_LOW)
host->wp_inverted = 1;
host->cd_inverted = of_property_read_bool(np, "cd-inverted");
mmc->f_min = 400000;
mmc->f_max = 288000000;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;

View File

@ -1717,6 +1717,12 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
struct omap_mmc_platform_data *pdata;
struct device_node *np = dev->of_node;
u32 bus_width, 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);
if (!pdata)
@ -1727,8 +1733,8 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
/* This driver only supports 1 slot */
pdata->nr_slots = 1;
pdata->slots[0].switch_pin = of_get_named_gpio(np, "cd-gpios", 0);
pdata->slots[0].gpio_wp = of_get_named_gpio(np, "wp-gpios", 0);
pdata->slots[0].switch_pin = cd_gpio;
pdata->slots[0].gpio_wp = wp_gpio;
if (of_find_property(np, "ti,non-removable", NULL)) {
pdata->slots[0].nonremovable = true;
@ -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);
if (match) {
pdata = of_get_hsmmc_pdata(&pdev->dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
if (match->data) {
const u16 *offsetp = match->data;
pdata->reg_offset = *offsetp;

View File

@ -57,6 +57,9 @@ struct realtek_pci_sdmmc {
bool eject;
bool initial_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)
@ -765,6 +768,9 @@ static int sd_power_on(struct realtek_pci_sdmmc *host)
struct rtsx_pcr *pcr = host->pcr;
int err;
if (host->power_state == SDMMC_POWER_ON)
return 0;
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_SHARE_MODE,
@ -787,6 +793,7 @@ static int sd_power_on(struct realtek_pci_sdmmc *host)
if (err < 0)
return err;
host->power_state = SDMMC_POWER_ON;
return 0;
}
@ -795,6 +802,8 @@ static int sd_power_off(struct realtek_pci_sdmmc *host)
struct rtsx_pcr *pcr = host->pcr;
int err;
host->power_state = SDMMC_POWER_OFF;
rtsx_pci_init_cmd(pcr);
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)
host->pcr = pcr;
host->mmc = mmc;
host->pdev = pdev;
host->power_state = SDMMC_POWER_OFF;
platform_set_drvdata(pdev, host);
pcr->slots[RTSX_SD_CARD].p_dev = pdev;
pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event;

View File

@ -195,6 +195,8 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
host->mmc->pm_caps |= c->slot->pm_caps;
}
host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP;
err = sdhci_add_host(host);
if (err)
goto err_free;

View File

@ -124,7 +124,7 @@ unsigned int bcm2835_sdhci_get_min_clock(struct sdhci_host *host)
return MIN_FREQ;
}
static struct sdhci_ops bcm2835_sdhci_ops = {
static const struct sdhci_ops bcm2835_sdhci_ops = {
.write_l = bcm2835_sdhci_writel,
.write_w = bcm2835_sdhci_writew,
.write_b = bcm2835_sdhci_writeb,
@ -135,7 +135,7 @@ static struct sdhci_ops bcm2835_sdhci_ops = {
.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 |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
.ops = &bcm2835_sdhci_ops,

View File

@ -79,12 +79,12 @@ out:
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,
.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,
.quirks = SDHCI_QUIRK_BROKEN_DMA |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |

View File

@ -83,12 +83,12 @@ static u32 sdhci_dove_readl(struct sdhci_host *host, int reg)
return ret;
}
static struct sdhci_ops sdhci_dove_ops = {
static const struct sdhci_ops sdhci_dove_ops = {
.read_w = sdhci_dove_readw,
.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,
.quirks = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
SDHCI_QUIRK_NO_BUSY_IRQ |

View File

@ -399,7 +399,7 @@ static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
return 0;
}
static struct sdhci_ops sdhci_esdhc_ops = {
static const struct sdhci_ops sdhci_esdhc_ops = {
.read_l = esdhc_readl_le,
.read_w = esdhc_readw_le,
.write_l = esdhc_writel_le,
@ -412,7 +412,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.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
| SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
| SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC

View File

@ -230,7 +230,7 @@ static void esdhc_of_platform_init(struct sdhci_host *host)
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_w = esdhc_readw,
.read_b = esdhc_readb,
@ -249,7 +249,7 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.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
* eSDHC cannot support End Attribute in NOP ADMA descriptor

View File

@ -51,7 +51,7 @@ static void sdhci_hlwd_writeb(struct sdhci_host *host, u8 val, int reg)
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_w = sdhci_be32bs_readw,
.read_b = sdhci_be32bs_readb,
@ -60,7 +60,7 @@ static struct sdhci_ops sdhci_hlwd_ops = {
.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 |
SDHCI_QUIRK_32BIT_DMA_SIZE,
.ops = &sdhci_hlwd_ops,

View File

@ -975,7 +975,7 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host)
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,
.platform_bus_width = sdhci_pci_bus_width,
.hw_reset = sdhci_pci_hw_reset,
@ -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->slotno = slotno;
host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP;
ret = sdhci_add_host(host);
if (ret)

View File

@ -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);
static struct sdhci_ops sdhci_pltfm_ops = {
static const struct sdhci_ops sdhci_pltfm_ops = {
};
#ifdef CONFIG_OF
@ -94,6 +94,7 @@ void sdhci_get_of_property(struct platform_device *pdev)
if (of_device_is_compatible(np, "fsl,p2020-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"))
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
@ -114,7 +115,7 @@ void sdhci_get_of_property(struct platform_device *pdev) {}
EXPORT_SYMBOL_GPL(sdhci_get_of_property);
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_pltfm_host *pltfm_host;
@ -201,7 +202,7 @@ void sdhci_pltfm_free(struct platform_device *pdev)
EXPORT_SYMBOL_GPL(sdhci_pltfm_free);
int sdhci_pltfm_register(struct platform_device *pdev,
struct sdhci_pltfm_data *pdata)
const struct sdhci_pltfm_data *pdata)
{
struct sdhci_host *host;
int ret = 0;

View File

@ -16,7 +16,7 @@
#include "sdhci.h"
struct sdhci_pltfm_data {
struct sdhci_ops *ops;
const struct sdhci_ops *ops;
unsigned int quirks;
};
@ -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 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 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 unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host);

View File

@ -111,7 +111,7 @@ static int pxav2_mmc_set_width(struct sdhci_host *host, int width)
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,
.platform_reset_exit = pxav2_set_private_registers,
.platform_bus_width = pxav2_mmc_set_width,

View File

@ -167,13 +167,21 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
return 0;
}
static struct sdhci_ops pxav3_sdhci_ops = {
static const struct sdhci_ops pxav3_sdhci_ops = {
.platform_reset_exit = pxav3_set_private_registers,
.set_uhs_signaling = pxav3_set_uhs_signaling,
.platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
.get_max_clock = 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
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)
{
struct sdhci_pxa_platdata *pdata;
struct device_node *np = dev->of_node;
u32 bus_width;
u32 clk_delay_cycles;
enum of_gpio_flags gpio_flags;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
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);
if (clk_delay_cycles > 0)
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;
}
#else
@ -235,7 +230,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
if (!pxa)
return -ENOMEM;
host = sdhci_pltfm_init(pdev, NULL);
host = sdhci_pltfm_init(pdev, &sdhci_pxav3_pdata);
if (IS_ERR(host)) {
kfree(pxa);
return PTR_ERR(host);
@ -252,24 +247,18 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
pltfm_host->clk = 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 */
host->mmc->caps |= MMC_CAP_1_8V_DDR;
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);
if (pdata) {
if (pdata->flags & PXA_FLAG_CARD_PERMANENT) {
} else if (pdata) {
/* on-chip device */
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
if (pdata->flags & PXA_FLAG_CARD_PERMANENT)
host->mmc->caps |= MMC_CAP_NONREMOVABLE;
}
/* If slot design supports 8 bit data, indicate this to MMC. */
if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT)
@ -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_enable(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, PXAV3_RPM_DELAY_MS);
@ -317,7 +302,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
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);
host->mmc->pm_flags |= MMC_PM_WAKE_SDIO_IRQ;
} else {

View File

@ -25,7 +25,6 @@
#include <linux/of_gpio.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/pinctrl/consumer.h>
#include <linux/mmc/host.h>
@ -44,7 +43,6 @@
* @ioarea: The resource created when we claimed the IO area.
* @pdata: The platform data for this controller.
* @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_bus: The clocks that are available for the SD/MMC bus clock.
*/
@ -56,8 +54,6 @@ struct sdhci_s3c {
unsigned int cur_clk;
int ext_cd_irq;
int ext_cd_gpio;
int *gpios;
struct pinctrl *pctrl;
struct clk *clk_io;
struct clk *clk_bus[MAX_BUS_CLK];
@ -446,42 +442,32 @@ static int sdhci_s3c_parse_dt(struct device *dev,
struct device_node *node = dev->of_node;
struct sdhci_s3c *ourhost = to_s3c(host);
u32 max_width;
int gpio, cnt, ret;
int gpio;
/* if the bus-width property is not specified, assume width as 1 */
if (of_property_read_u32(node, "bus-width", &max_width))
max_width = 1;
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 */
if (of_get_property(node, "broken-cd", NULL)) {
pdata->cd_type = S3C_SDHCI_CD_NONE;
goto setup_bus;
return 0;
}
if (of_get_property(node, "non-removable", NULL)) {
pdata->cd_type = S3C_SDHCI_CD_PERMANENT;
goto setup_bus;
return 0;
}
gpio = of_get_named_gpio(node, "cd-gpios", 0);
if (gpio_is_valid(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;
pdata->ext_cd_gpio = gpio;
ourhost->ext_cd_gpio = -1;
if (of_get_property(node, "cd-inverted", NULL))
pdata->ext_cd_gpio_invert = 1;
return 0;
} else if (gpio != -ENOENT) {
dev_err(dev, "invalid card detect gpio specified\n");
return -EINVAL;
@ -489,45 +475,6 @@ static int sdhci_s3c_parse_dt(struct device *dev,
/* 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;
ourhost->ext_cd_gpio = -1;
if (of_get_property(node, "cd-inverted", NULL))
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;
/* get the gpios for command, clock and data lines */
for (cnt = 0; cnt < NUM_GPIOS(pdata->max_width); cnt++) {
gpio = of_get_gpio(node, cnt);
if (!gpio_is_valid(gpio)) {
dev_err(dev, "invalid gpio[%d]\n", cnt);
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 0;
}
#else
@ -588,8 +535,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
goto err_pdata_io_clk;
}
sc->pctrl = devm_pinctrl_get_select_default(&pdev->dev);
if (pdev->dev.of_node) {
ret = sdhci_s3c_parse_dt(&pdev->dev, host, pdata);
if (ret)
@ -607,7 +552,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
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)) {
dev_err(dev, "failed to get io clock\n");
ret = PTR_ERR(sc->clk_io);
@ -622,7 +567,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
char name[14];
snprintf(name, 14, "mmc_busclk.%d", ptr);
clk = clk_get(dev, name);
clk = devm_clk_get(dev, name);
if (IS_ERR(clk))
continue;
@ -763,15 +708,9 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
#ifndef CONFIG_PM_RUNTIME
clk_disable_unprepare(sc->clk_bus[sc->cur_clk]);
#endif
for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
if (sc->clk_bus[ptr]) {
clk_put(sc->clk_bus[ptr]);
}
}
err_no_busclks:
clk_disable_unprepare(sc->clk_io);
clk_put(sc->clk_io);
err_pdata_io_clk:
sdhci_free_host(host);
@ -784,7 +723,6 @@ static int sdhci_s3c_remove(struct platform_device *pdev)
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_s3c *sc = sdhci_priv(host);
struct s3c_sdhci_platdata *pdata = sc->pdata;
int ptr;
if (pdata->cd_type == S3C_SDHCI_CD_EXTERNAL && pdata->ext_cd_cleanup)
pdata->ext_cd_cleanup(&sdhci_s3c_notify_change);
@ -804,13 +742,7 @@ static int sdhci_s3c_remove(struct platform_device *pdev)
#ifndef CONFIG_PM_RUNTIME
clk_disable_unprepare(sc->clk_bus[sc->cur_clk]);
#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_put(sc->clk_io);
sdhci_free_host(host);
platform_set_drvdata(pdev, NULL);

View File

@ -0,0 +1,193 @@
/*
* 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");

View File

@ -36,7 +36,7 @@ struct spear_sdhci {
};
/* sdhci ops */
static struct sdhci_ops sdhci_pltfm_ops = {
static const struct sdhci_ops sdhci_pltfm_ops = {
/* Nothing to do for now. */
};
@ -291,7 +291,7 @@ static int sdhci_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int sdhci_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);

View File

@ -24,6 +24,7 @@
#include <linux/gpio.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/slot-gpio.h>
#include <asm/gpio.h>
@ -38,16 +39,13 @@
#define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2)
struct sdhci_tegra_soc_data {
struct sdhci_pltfm_data *pdata;
const struct sdhci_pltfm_data *pdata;
u32 nvquirks;
};
struct sdhci_tegra {
const struct sdhci_tegra_soc_data *soc_data;
int cd_gpio;
int wp_gpio;
int power_gpio;
int is_8bit;
};
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)
static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
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);
return mmc_gpio_get_ro(host->mmc);
}
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)
{
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)
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;
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_8BITBUS;
} else {
@ -164,7 +147,7 @@ static int tegra_sdhci_buswidth(struct sdhci_host *host, int bus_width)
return 0;
}
static struct sdhci_ops tegra_sdhci_ops = {
static const struct sdhci_ops tegra_sdhci_ops = {
.get_ro = tegra_sdhci_get_ro,
.read_l = tegra_sdhci_readl,
.read_w = tegra_sdhci_readw,
@ -173,8 +156,7 @@ static struct sdhci_ops tegra_sdhci_ops = {
.platform_reset_exit = tegra_sdhci_reset_exit,
};
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
static struct sdhci_pltfm_data sdhci_tegra20_pdata = {
static const struct sdhci_pltfm_data sdhci_tegra20_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT |
@ -187,10 +169,8 @@ static struct sdhci_tegra_soc_data soc_data_tegra20 = {
.nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 |
NVQUIRK_ENABLE_BLOCK_GAP_DET,
};
#endif
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
static struct sdhci_pltfm_data sdhci_tegra30_pdata = {
static const struct sdhci_pltfm_data sdhci_tegra30_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_SINGLE_POWER_WRITE |
@ -203,32 +183,37 @@ static struct sdhci_tegra_soc_data soc_data_tegra30 = {
.pdata = &sdhci_tegra30_pdata,
.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[] = {
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
{ .compatible = "nvidia,tegra114-sdhci", .data = &soc_data_tegra114 },
{ .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 },
#endif
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
{ .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,
struct sdhci_tegra *tegra_host)
static void sdhci_tegra_parse_dt(struct device *dev)
{
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);
if (of_property_read_u32(np, "bus-width", &bus_width) == 0 &&
bus_width == 8)
tegra_host->is_8bit = 1;
mmc_of_parse(host->mmc);
}
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;
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)) {
rc = gpio_request(tegra_host->power_gpio, "sdhci_power");
@ -272,37 +257,6 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
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);
if (IS_ERR(clk)) {
dev_err(mmc_dev(host->mmc), "clk err\n");
@ -312,9 +266,6 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
clk_prepare_enable(clk);
pltfm_host->clk = clk;
if (tegra_host->is_8bit)
host->mmc->caps |= MMC_CAP_8_BIT_DATA;
rc = sdhci_add_host(host);
if (rc)
goto err_add_host;
@ -325,15 +276,6 @@ err_add_host:
clk_disable_unprepare(pltfm_host->clk);
clk_put(pltfm_host->clk);
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))
gpio_free(tegra_host->power_gpio);
err_power_req:
@ -351,14 +293,6 @@ static int sdhci_tegra_remove(struct platform_device *pdev)
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))
gpio_free(tegra_host->power_gpio);

View File

@ -1581,6 +1581,37 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
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)
{
unsigned long flags;
@ -2038,6 +2069,7 @@ static void sdhci_card_event(struct mmc_host *mmc)
static const struct mmc_host_ops sdhci_ops = {
.request = sdhci_request,
.set_ios = sdhci_set_ios,
.get_cd = sdhci_get_cd,
.get_ro = sdhci_get_ro,
.hw_reset = sdhci_hw_reset,
.enable_sdio_irq = sdhci_enable_sdio_irq,
@ -2907,12 +2939,17 @@ int sdhci_add_host(struct sdhci_host *host)
host->vqmmc = NULL;
}
} else {
regulator_enable(host->vqmmc);
ret = regulator_enable(host->vqmmc);
if (!regulator_is_supported_voltage(host->vqmmc, 1700000,
1950000))
caps[1] &= ~(SDHCI_SUPPORT_SDR104 |
SDHCI_SUPPORT_SDR50 |
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)

View File

@ -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)
{
struct mmc_host *mmc;
struct wmt_mci_priv *priv;
int status;
priv = (struct wmt_mci_priv *)data;
mmc = priv->mmc;
status = readl(priv->sdmmc_base + SDDMA_CCR) & 0x0F;
@ -925,7 +923,7 @@ static int wmt_mci_remove(struct platform_device *pdev)
clk_put(priv->clk_sdmmc);
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);

View File

@ -17,6 +17,7 @@
struct mmc_cid {
unsigned int manfid;
char prod_name[8];
unsigned char prv;
unsigned int serial;
unsigned short oemid;
unsigned short year;

View File

@ -280,6 +280,7 @@ struct mmc_host {
#define MMC_CAP2_PACKED_WR (1 << 13) /* Allow packed write */
#define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \
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 */
@ -361,6 +362,8 @@ struct mmc_host {
unsigned int actual_clock; /* Actual HC clock rate */
unsigned int slotno; /* used for sdio acpi binding */
unsigned long private[0] ____cacheline_aligned;
};