Commit bbd60bff authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'mmc-v4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc

Pull MMC updates from Ulf Hansson:
 "Updates for MMC for v4.19.

  MMC core:
   - Add some fine-grained hooks to further support HS400 tuning
   - Improve error path for bus width setting for HS400es
   - Use a common method when checking R1 status

  MMC host:
   - renesas_sdhi: Add r8a77990 support
   - renesas_sdhi: Add eMMC HS400 mode support
   - tmio/renesas_sdhi: Improve tuning/clock management
   - tmio: Add eMMC HS400 mode support
   - sunxi: Add support for 3.3V eMMC DDR mode
   - mmci: Initial support to manage variant specific callbacks
   - sdhci: Don't try 3.3V I/O voltage if not supported
   - sdhci-pci-dwc-mshc: Add driver to support Synopsys dwc mshc SDHCI PCI
   - sdhci-of-dwcmshc: Add driver to support Synopsys DWC MSHC SDHCI
   - sdhci-msm: Add support for new version sdcc V5
   - sdhci-pci-o2micro: Add support for O2 eMMC HS200 mode
   - sdhci-pci-o2micro: Add support for O2 hardware tuning
   - sdhci-pci-o2micro: Add MSI interrupt support for O2 SD host
   - sdhci-pci: Add support for Intel ICP
   - sdhci-tegra: Prevent ACMD23 and HS200 mode on Tegra 3
   - sdhci-tegra: Fix eMMC DDR52 mode
   - sdhci-tegra: Improve clock management
   - dw_mmc-rockchip: Document compatible string for px30
   - sdhci-esdhc-imx: Add support for 3.3V eMMC DDR mode
   - sdhci-of-esdhc: Set proper DMA mask for ls104x chips
   - sdhci-of-esdhc: Improve clock management
   - sdhci-of-arasan: Add a quirk to manage unstable clocks
   - dw_mmc-exynos: Address potential external abort during system resume
   - pxamci: Add support for common MMC DT bindings
   - pxamci: Several cleanups and improvements
   - pxamci: Merge immutable branch for pxa to switch to DMA slave maps"

* tag 'mmc-v4.19' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (56 commits)
  mmc: core: improve reasonableness of bus width setting for HS400es
  mmc: tmio: remove unneeded variable in tmio_mmc_start_command()
  mmc: renesas_sdhi: Fix sampling clock position selecting
  mmc: tmio: Fix tuning flow
  mmc: sunxi: remove output of virtual base address
  dt-bindings: mmc: rockchip-dw-mshc: add description for px30
  mmc: renesas_sdhi: Add r8a77990 support
  mmc: sunxi: allow 3.3V DDR when DDR is available
  mmc: mmci: Add and implement a ->dma_setup() callback for qcom dml
  mmc: mmci: Initial support to manage variant specific callbacks
  mmc: tegra: Force correct divider calculation on DDR50/52
  mmc: sdhci: Add MSI interrupt support for O2 SD host
  mmc: sdhci: Add support for O2 hardware tuning
  mmc: sdhci: Export sdhci tuning function symbol
  mmc: sdhci: Change O2 Host HS200 mode clock frequency to 200MHz
  mmc: sdhci: Add support for O2 eMMC HS200 mode
  mmc: tegra: Add and use tegra_sdhci_get_max_clock()
  mmc: sdhci-esdhc-imx: fix indent
  mmc: sdhci-esdhc-imx: disable clocks before changing frequency
  mmc: tegra: prevent ACMD23 on Tegra 3
  ...
parents 30779715 7f38abf2
...@@ -37,6 +37,8 @@ Optional Properties: ...@@ -37,6 +37,8 @@ Optional Properties:
- xlnx,fails-without-test-cd: when present, the controller doesn't work when - xlnx,fails-without-test-cd: when present, the controller doesn't work when
the CD line is not connected properly, and the line is not connected the CD line is not connected properly, and the line is not connected
properly. Test mode can be used to force the controller to function. properly. Test mode can be used to force the controller to function.
- xlnx,int-clock-stable-broken: when present, the controller always reports
that the internal clock is stable even when it is not.
Example: Example:
sdhci@e0100000 { sdhci@e0100000 {
......
...@@ -8,10 +8,9 @@ Required properties: ...@@ -8,10 +8,9 @@ Required properties:
Optional properties: Optional properties:
- marvell,detect-delay-ms: sets the detection delay timeout in ms. - marvell,detect-delay-ms: sets the detection delay timeout in ms.
- marvell,gpio-power: GPIO spec for the card power enable pin
This file documents differences between the core properties in mmc.txt In addition to the properties described in this docuent, the details
and the properties used by the pxa-mmc driver. described in mmc.txt are supported.
Examples: Examples:
...@@ -19,6 +18,7 @@ mmc0: mmc@41100000 { ...@@ -19,6 +18,7 @@ mmc0: mmc@41100000 {
compatible = "marvell,pxa-mmc"; compatible = "marvell,pxa-mmc";
reg = <0x41100000 0x1000>; reg = <0x41100000 0x1000>;
interrupts = <23>; interrupts = <23>;
vmmc-supply = <&mmc_regulator>;
cd-gpios = <&gpio 23 0>; cd-gpios = <&gpio 23 0>;
wp-gpios = <&gpio 24 0>; wp-gpios = <&gpio 24 0>;
}; };
......
...@@ -14,6 +14,7 @@ Required Properties: ...@@ -14,6 +14,7 @@ Required Properties:
before RK3288 before RK3288
- "rockchip,rk3288-dw-mshc": for Rockchip RK3288 - "rockchip,rk3288-dw-mshc": for Rockchip RK3288
- "rockchip,rv1108-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RV1108 - "rockchip,rv1108-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RV1108
- "rockchip,px30-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip PX30
- "rockchip,rk3036-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3036 - "rockchip,rk3036-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3036
- "rockchip,rk3228-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK322x - "rockchip,rk3228-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK322x
- "rockchip,rk3328-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3328 - "rockchip,rk3328-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3328
......
...@@ -4,7 +4,12 @@ This file documents differences between the core properties in mmc.txt ...@@ -4,7 +4,12 @@ This file documents differences between the core properties in mmc.txt
and the properties used by the sdhci-msm driver. and the properties used by the sdhci-msm driver.
Required properties: Required properties:
- compatible: Should contain "qcom,sdhci-msm-v4". - compatible: Should contain:
"qcom,sdhci-msm-v4" for sdcc versions less than 5.0
"qcom,sdhci-msm-v5" for sdcc versions >= 5.0
For SDCC version 5.0.0, MCI registers are removed from SDCC
interface and some registers are moved to HC. New compatible
string is added to support this change - "qcom,sdhci-msm-v5".
- reg: Base address and length of the register in the following order: - reg: Base address and length of the register in the following order:
- Host controller register map (required) - Host controller register map (required)
- SD Core register map (required) - SD Core register map (required)
......
* Synopsys DesignWare Cores Mobile Storage Host Controller
Required properties:
- compatible: should be one of the following:
"snps,dwcmshc-sdhci"
- reg: offset and length of the register set for the device.
- interrupts: a single interrupt specifier.
- clocks: Array of clocks required for SDHCI; requires at least one for
core clock.
- clock-names: Array of names corresponding to clocks property; shall be
"core" for core clock and "bus" for optional bus clock.
Example:
sdhci2: sdhci@aa0000 {
compatible = "snps,dwcmshc-sdhci";
reg = <0xaa0000 0x1000>;
interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&emmcclk>;
bus-width = <8>;
}
...@@ -28,6 +28,7 @@ Required properties: ...@@ -28,6 +28,7 @@ Required properties:
"renesas,sdhi-r8a7796" - SDHI IP on R8A7796 SoC "renesas,sdhi-r8a7796" - SDHI IP on R8A7796 SoC
"renesas,sdhi-r8a77965" - SDHI IP on R8A77965 SoC "renesas,sdhi-r8a77965" - SDHI IP on R8A77965 SoC
"renesas,sdhi-r8a77980" - SDHI IP on R8A77980 SoC "renesas,sdhi-r8a77980" - SDHI IP on R8A77980 SoC
"renesas,sdhi-r8a77990" - SDHI IP on R8A77990 SoC
"renesas,sdhi-r8a77995" - SDHI IP on R8A77995 SoC "renesas,sdhi-r8a77995" - SDHI IP on R8A77995 SoC
"renesas,sdhi-shmobile" - a generic sh-mobile SDHI controller "renesas,sdhi-shmobile" - a generic sh-mobile SDHI controller
"renesas,rcar-gen1-sdhi" - a generic R-Car Gen1 SDHI controller "renesas,rcar-gen1-sdhi" - a generic R-Car Gen1 SDHI controller
......
...@@ -12916,6 +12916,13 @@ S: Maintained ...@@ -12916,6 +12916,13 @@ S: Maintained
F: drivers/mmc/host/sdhci* F: drivers/mmc/host/sdhci*
F: include/linux/mmc/sdhci* F: include/linux/mmc/sdhci*
SYNOPSYS SDHCI COMPLIANT DWC MSHC DRIVER
M: Prabu Thangamuthu <prabu.t@synopsys.com>
M: Manjunath M B <manjumb@synopsys.com>
L: linux-mmc@vger.kernel.org
S: Maintained
F: drivers/mmc/host/sdhci-pci-dwc-mshc.c
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) SAMSUNG DRIVER SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) SAMSUNG DRIVER
M: Ben Dooks <ben-linux@fluff.org> M: Ben Dooks <ben-linux@fluff.org>
M: Jaehoon Chung <jh80.chung@samsung.com> M: Jaehoon Chung <jh80.chung@samsung.com>
......
...@@ -2078,7 +2078,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from, ...@@ -2078,7 +2078,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
/* Do not retry else we can't see errors */ /* Do not retry else we can't see errors */
err = mmc_wait_for_cmd(card->host, &cmd, 0); err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err || (cmd.resp[0] & 0xFDF92000)) { if (err || R1_STATUS(cmd.resp[0])) {
pr_err("error %d requesting status %#x\n", pr_err("error %d requesting status %#x\n",
err, cmd.resp[0]); err, cmd.resp[0]);
err = -EIO; err = -EIO;
...@@ -2716,52 +2716,6 @@ void mmc_stop_host(struct mmc_host *host) ...@@ -2716,52 +2716,6 @@ void mmc_stop_host(struct mmc_host *host)
mmc_release_host(host); mmc_release_host(host);
} }
int mmc_power_save_host(struct mmc_host *host)
{
int ret = 0;
pr_debug("%s: %s: powering down\n", mmc_hostname(host), __func__);
mmc_bus_get(host);
if (!host->bus_ops || host->bus_dead) {
mmc_bus_put(host);
return -EINVAL;
}
if (host->bus_ops->power_save)
ret = host->bus_ops->power_save(host);
mmc_bus_put(host);
mmc_power_off(host);
return ret;
}
EXPORT_SYMBOL(mmc_power_save_host);
int mmc_power_restore_host(struct mmc_host *host)
{
int ret;
pr_debug("%s: %s: powering up\n", mmc_hostname(host), __func__);
mmc_bus_get(host);
if (!host->bus_ops || host->bus_dead) {
mmc_bus_put(host);
return -EINVAL;
}
mmc_power_up(host, host->card->ocr);
ret = host->bus_ops->power_restore(host);
mmc_bus_put(host);
return ret;
}
EXPORT_SYMBOL(mmc_power_restore_host);
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
/* Do the card removal on suspend if card is assumed removeable /* Do the card removal on suspend if card is assumed removeable
* Do that in pm notifier while userspace isn't yet frozen, so we will be able * Do that in pm notifier while userspace isn't yet frozen, so we will be able
......
...@@ -28,8 +28,6 @@ struct mmc_bus_ops { ...@@ -28,8 +28,6 @@ struct mmc_bus_ops {
int (*resume)(struct mmc_host *); int (*resume)(struct mmc_host *);
int (*runtime_suspend)(struct mmc_host *); int (*runtime_suspend)(struct mmc_host *);
int (*runtime_resume)(struct mmc_host *); int (*runtime_resume)(struct mmc_host *);
int (*power_save)(struct mmc_host *);
int (*power_restore)(struct mmc_host *);
int (*alive)(struct mmc_host *); int (*alive)(struct mmc_host *);
int (*shutdown)(struct mmc_host *); int (*shutdown)(struct mmc_host *);
int (*hw_reset)(struct mmc_host *); int (*hw_reset)(struct mmc_host *);
......
...@@ -1169,6 +1169,10 @@ static int mmc_select_hs400(struct mmc_card *card) ...@@ -1169,6 +1169,10 @@ static int mmc_select_hs400(struct mmc_card *card)
/* Set host controller to HS timing */ /* Set host controller to HS timing */
mmc_set_timing(card->host, MMC_TIMING_MMC_HS); mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
/* Prepare host to downgrade to HS timing */
if (host->ops->hs400_downgrade)
host->ops->hs400_downgrade(host);
/* Reduce frequency to HS frequency */ /* Reduce frequency to HS frequency */
max_dtr = card->ext_csd.hs_max_dtr; max_dtr = card->ext_csd.hs_max_dtr;
mmc_set_clock(host, max_dtr); mmc_set_clock(host, max_dtr);
...@@ -1209,6 +1213,9 @@ static int mmc_select_hs400(struct mmc_card *card) ...@@ -1209,6 +1213,9 @@ static int mmc_select_hs400(struct mmc_card *card)
if (err) if (err)
goto out_err; goto out_err;
if (host->ops->hs400_complete)
host->ops->hs400_complete(host);
return 0; return 0;
out_err: out_err:
...@@ -1256,6 +1263,9 @@ int mmc_hs400_to_hs200(struct mmc_card *card) ...@@ -1256,6 +1263,9 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
mmc_set_timing(host, MMC_TIMING_MMC_HS); mmc_set_timing(host, MMC_TIMING_MMC_HS);
if (host->ops->hs400_downgrade)
host->ops->hs400_downgrade(host);
err = mmc_switch_status(card); err = mmc_switch_status(card);
if (err) if (err)
goto out_err; goto out_err;
...@@ -1338,8 +1348,12 @@ static int mmc_select_hs400es(struct mmc_card *card) ...@@ -1338,8 +1348,12 @@ static int mmc_select_hs400es(struct mmc_card *card)
goto out_err; goto out_err;
err = mmc_select_bus_width(card); err = mmc_select_bus_width(card);
if (err < 0) if (err != MMC_BUS_WIDTH_8) {
pr_err("%s: switch to 8bit bus width failed, err:%d\n",
mmc_hostname(host), err);
err = err < 0 ? err : -ENOTSUPP;
goto out_err; goto out_err;
}
/* Switch card to HS mode */ /* Switch card to HS mode */
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
......
...@@ -417,7 +417,7 @@ static int mmc_switch_status_error(struct mmc_host *host, u32 status) ...@@ -417,7 +417,7 @@ static int mmc_switch_status_error(struct mmc_host *host, u32 status)
if (status & R1_SPI_ILLEGAL_COMMAND) if (status & R1_SPI_ILLEGAL_COMMAND)
return -EBADMSG; return -EBADMSG;
} else { } else {
if (status & 0xFDFFA000) if (R1_STATUS(status))
pr_warn("%s: unexpected status %#x after switch\n", pr_warn("%s: unexpected status %#x after switch\n",
mmc_hostname(host), status); mmc_hostname(host), status);
if (status & R1_SWITCH_ERROR) if (status & R1_SWITCH_ERROR)
......
...@@ -1076,7 +1076,6 @@ static const struct mmc_bus_ops mmc_sdio_ops = { ...@@ -1076,7 +1076,6 @@ static const struct mmc_bus_ops mmc_sdio_ops = {
.resume = mmc_sdio_resume, .resume = mmc_sdio_resume,
.runtime_suspend = mmc_sdio_runtime_suspend, .runtime_suspend = mmc_sdio_runtime_suspend,
.runtime_resume = mmc_sdio_runtime_resume, .runtime_resume = mmc_sdio_runtime_resume,
.power_restore = mmc_sdio_power_restore,
.alive = mmc_sdio_alive, .alive = mmc_sdio_alive,
.hw_reset = mmc_sdio_hw_reset, .hw_reset = mmc_sdio_hw_reset,
.sw_reset = mmc_sdio_sw_reset, .sw_reset = mmc_sdio_sw_reset,
......
...@@ -176,6 +176,17 @@ config MMC_SDHCI_OF_HLWD ...@@ -176,6 +176,17 @@ config MMC_SDHCI_OF_HLWD
If unsure, say N. If unsure, say N.
config MMC_SDHCI_OF_DWCMSHC
tristate "SDHCI OF support for the Synopsys DWC MSHC"
depends on MMC_SDHCI_PLTFM
depends on OF
depends on COMMON_CLK
help
This selects Synopsys DesignWare Cores Mobile Storage Controller
support.
If you have a controller with this interface, say Y or M here.
If unsure, say N.
config MMC_SDHCI_CADENCE config MMC_SDHCI_CADENCE
tristate "SDHCI support for the Cadence SD/SDIO/eMMC controller" tristate "SDHCI support for the Cadence SD/SDIO/eMMC controller"
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
......
...@@ -11,7 +11,8 @@ obj-$(CONFIG_MMC_MXC) += mxcmmc.o ...@@ -11,7 +11,8 @@ obj-$(CONFIG_MMC_MXC) += mxcmmc.o
obj-$(CONFIG_MMC_MXS) += mxs-mmc.o obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
obj-$(CONFIG_MMC_SDHCI) += sdhci.o obj-$(CONFIG_MMC_SDHCI) += sdhci.o
obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o
sdhci-pci-y += sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o sdhci-pci-y += sdhci-pci-core.o sdhci-pci-o2micro.o sdhci-pci-arasan.o \
sdhci-pci-dwc-mshc.o
obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o obj-$(subst m,y,$(CONFIG_MMC_SDHCI_PCI)) += sdhci-pci-data.o
obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o
obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o
...@@ -82,6 +83,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_ARASAN) += sdhci-of-arasan.o ...@@ -82,6 +83,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_ARASAN) += sdhci-of-arasan.o
obj-$(CONFIG_MMC_SDHCI_OF_AT91) += sdhci-of-at91.o obj-$(CONFIG_MMC_SDHCI_OF_AT91) += sdhci-of-at91.o
obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
obj-$(CONFIG_MMC_SDHCI_OF_DWCMSHC) += sdhci-of-dwcmshc.o
obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o
obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o
obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o
......
...@@ -175,6 +175,20 @@ static int dw_mci_exynos_runtime_resume(struct device *dev) ...@@ -175,6 +175,20 @@ static int dw_mci_exynos_runtime_resume(struct device *dev)
return ret; return ret;
} }
#endif /* CONFIG_PM */
#ifdef CONFIG_PM_SLEEP
/**
* dw_mci_exynos_suspend_noirq - Exynos-specific suspend code
*
* This ensures that device will be in runtime active state in
* dw_mci_exynos_resume_noirq after calling pm_runtime_force_resume()
*/
static int dw_mci_exynos_suspend_noirq(struct device *dev)
{
pm_runtime_get_noresume(dev);
return pm_runtime_force_suspend(dev);
}
/** /**
* dw_mci_exynos_resume_noirq - Exynos-specific resume code * dw_mci_exynos_resume_noirq - Exynos-specific resume code
...@@ -186,12 +200,16 @@ static int dw_mci_exynos_runtime_resume(struct device *dev) ...@@ -186,12 +200,16 @@ static int dw_mci_exynos_runtime_resume(struct device *dev)
* *
* We run this code on all exynos variants because it doesn't hurt. * We run this code on all exynos variants because it doesn't hurt.
*/ */
static int dw_mci_exynos_resume_noirq(struct device *dev) static int dw_mci_exynos_resume_noirq(struct device *dev)
{ {
struct dw_mci *host = dev_get_drvdata(dev); struct dw_mci *host = dev_get_drvdata(dev);
struct dw_mci_exynos_priv_data *priv = host->priv; struct dw_mci_exynos_priv_data *priv = host->priv;
u32 clksel; u32 clksel;
int ret;
ret = pm_runtime_force_resume(dev);
if (ret)
return ret;
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
...@@ -207,11 +225,11 @@ static int dw_mci_exynos_resume_noirq(struct device *dev) ...@@ -207,11 +225,11 @@ static int dw_mci_exynos_resume_noirq(struct device *dev)
mci_writel(host, CLKSEL, clksel); mci_writel(host, CLKSEL, clksel);
} }
pm_runtime_put(dev);
return 0; return 0;
} }
#else #endif /* CONFIG_PM_SLEEP */
#define dw_mci_exynos_resume_noirq NULL
#endif /* CONFIG_PM */
static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing) static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
{ {
...@@ -553,14 +571,11 @@ static int dw_mci_exynos_remove(struct platform_device *pdev) ...@@ -553,14 +571,11 @@ static int dw_mci_exynos_remove(struct platform_device *pdev)
} }
static const struct dev_pm_ops dw_mci_exynos_pmops = { static const struct dev_pm_ops dw_mci_exynos_pmops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend_noirq,
pm_runtime_force_resume) dw_mci_exynos_resume_noirq)
SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend, SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
dw_mci_exynos_runtime_resume, dw_mci_exynos_runtime_resume,
NULL) NULL)
.resume_noirq = dw_mci_exynos_resume_noirq,
.thaw_noirq = dw_mci_exynos_resume_noirq,
.restore_noirq = dw_mci_exynos_resume_noirq,
}; };
static struct platform_driver dw_mci_exynos_pltfm_driver = { static struct platform_driver dw_mci_exynos_pltfm_driver = {
......
...@@ -48,78 +48,6 @@ ...@@ -48,78 +48,6 @@
static unsigned int fmax = 515633; static unsigned int fmax = 515633;
/**
* struct variant_data - MMCI variant-specific quirks
* @clkreg: default value for MCICLOCK register
* @clkreg_enable: enable value for MMCICLOCK register
* @clkreg_8bit_bus_enable: enable value for 8 bit bus
* @clkreg_neg_edge_enable: enable value for inverted data/cmd output
* @datalength_bits: number of bits in the MMCIDATALENGTH register
* @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
* is asserted (likewise for RX)
* @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
* is asserted (likewise for RX)
* @data_cmd_enable: enable value for data commands.
* @st_sdio: enable ST specific SDIO logic
* @st_clkdiv: true if using a ST-specific clock divider algorithm
* @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
* @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
* @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl
* register
* @datactrl_mask_sdio: SDIO enable mask in datactrl register
* @pwrreg_powerup: power up value for MMCIPOWER register
* @f_max: maximum clk frequency supported by the controller.
* @signal_direction: input/out direction of bus signals can be indicated
* @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
* @busy_detect: true if the variant supports busy detection on DAT0.
* @busy_dpsm_flag: bitmask enabling busy detection in the DPSM
* @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register
* indicating that the card is busy
* @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for
* getting busy end detection interrupts
* @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
* @explicit_mclk_control: enable explicit mclk control in driver.
* @qcom_fifo: enables qcom specific fifo pio read logic.
* @qcom_dml: enables qcom specific dma glue for dma transfers.
* @reversed_irq_handling: handle data irq before cmd irq.
* @mmcimask1: true if variant have a MMCIMASK1 register.
* @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS
* register.
* @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
*/
struct variant_data {
unsigned int clkreg;
unsigned int clkreg_enable;
unsigned int clkreg_8bit_bus_enable;
unsigned int clkreg_neg_edge_enable;
unsigned int datalength_bits;
unsigned int fifosize;
unsigned int fifohalfsize;
unsigned int data_cmd_enable;
unsigned int datactrl_mask_ddrmode;
unsigned int datactrl_mask_sdio;
bool st_sdio;
bool st_clkdiv;
bool blksz_datactrl16;
bool blksz_datactrl4;
u32 pwrreg_powerup;
u32 f_max;
bool signal_direction;
bool pwrreg_clkgate;
bool busy_detect;
u32 busy_dpsm_flag;
u32 busy_detect_flag;
u32 busy_detect_mask;
bool pwrreg_nopower;
bool explicit_mclk_control;
bool qcom_fifo;
bool qcom_dml;
bool reversed_irq_handling;
bool mmcimask1;
u32 start_err;
u32 opendrain;
};
static struct variant_data variant_arm = { static struct variant_data variant_arm = {
.fifosize = 16 * 4, .fifosize = 16 * 4,
.fifohalfsize = 8 * 4, .fifohalfsize = 8 * 4,
...@@ -280,6 +208,7 @@ static struct variant_data variant_qcom = { ...@@ -280,6 +208,7 @@ static struct variant_data variant_qcom = {
.mmcimask1 = true, .mmcimask1 = true,
.start_err = MCI_STARTBITERR, .start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD, .opendrain = MCI_ROD,
.init = qcom_variant_init,
}; };
/* Busy detection for the ST Micro variant */ /* Busy detection for the ST Micro variant */
...@@ -489,7 +418,6 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) ...@@ -489,7 +418,6 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
static void mmci_dma_setup(struct mmci_host *host) static void mmci_dma_setup(struct mmci_host *host)
{ {
const char *rxname, *txname; const char *rxname, *txname;
struct variant_data *variant = host->variant;
host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx"); host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx");
host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx"); host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx");
...@@ -537,9 +465,8 @@ static void mmci_dma_setup(struct mmci_host *host) ...@@ -537,9 +465,8 @@ static void mmci_dma_setup(struct mmci_host *host)
host->mmc->max_seg_size = max_seg_size; host->mmc->max_seg_size = max_seg_size;
} }
if (variant->qcom_dml && host->dma_rx_channel && host->dma_tx_channel) if (host->ops && host->ops->dma_setup)
if (dml_hw_init(host, host->mmc->parent->of_node)) host->ops->dma_setup(host);
variant->qcom_dml = false;
} }
/* /*
...@@ -1706,6 +1633,9 @@ static int mmci_probe(struct amba_device *dev, ...@@ -1706,6 +1633,9 @@ static int mmci_probe(struct amba_device *dev,
goto clk_disable; goto clk_disable;
} }
if (variant->init)
variant->init(host);
/* /*
* The ARM and ST versions of the block have slightly different * The ARM and ST versions of the block have slightly different
* clock divider equations which means that the minimum divider * clock divider equations which means that the minimum divider
......
...@@ -195,8 +195,86 @@ ...@@ -195,8 +195,86 @@
#define MMCI_PINCTRL_STATE_OPENDRAIN "opendrain" #define MMCI_PINCTRL_STATE_OPENDRAIN "opendrain"
struct clk; struct clk;
struct variant_data;
struct dma_chan; struct dma_chan;
struct mmci_host;
/**
* struct variant_data - MMCI variant-specific quirks
* @clkreg: default value for MCICLOCK register
* @clkreg_enable: enable value for MMCICLOCK register
* @clkreg_8bit_bus_enable: enable value for 8 bit bus
* @clkreg_neg_edge_enable: enable value for inverted data/cmd output
* @datalength_bits: number of bits in the MMCIDATALENGTH register
* @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
* is asserted (likewise for RX)
* @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
* is asserted (likewise for RX)
* @data_cmd_enable: enable value for data commands.
* @st_sdio: enable ST specific SDIO logic
* @st_clkdiv: true if using a ST-specific clock divider algorithm
* @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
* @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
* @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl
* register
* @datactrl_mask_sdio: SDIO enable mask in datactrl register
* @pwrreg_powerup: power up value for MMCIPOWER register
* @f_max: maximum clk frequency supported by the controller.
* @signal_direction: input/out direction of bus signals can be indicated
* @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
* @busy_detect: true if the variant supports busy detection on DAT0.
* @busy_dpsm_flag: bitmask enabling busy detection in the DPSM
* @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register
* indicating that the card is busy
* @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for
* getting busy end detection interrupts
* @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
* @explicit_mclk_control: enable explicit mclk control in driver.
* @qcom_fifo: enables qcom specific fifo pio read logic.
* @qcom_dml: enables qcom specific dma glue for dma transfers.
* @reversed_irq_handling: handle data irq before cmd irq.
* @mmcimask1: true if variant have a MMCIMASK1 register.
* @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS
* register.
* @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
*/
struct variant_data {
unsigned int clkreg;
unsigned int clkreg_enable;
unsigned int clkreg_8bit_bus_enable;
unsigned int clkreg_neg_edge_enable;
unsigned int datalength_bits;
unsigned int fifosize;
unsigned int fifohalfsize;
unsigned int data_cmd_enable;
unsigned int datactrl_mask_ddrmode;
unsigned int datactrl_mask_sdio;
bool st_sdio;
bool st_clkdiv;
bool blksz_datactrl16;
bool blksz_datactrl4;
u32 pwrreg_powerup;
u32 f_max;
bool signal_direction;
bool pwrreg_clkgate;
bool busy_detect;
u32 busy_dpsm_flag;
u32 busy_detect_flag;
u32 busy_detect_mask;
bool pwrreg_nopower;
bool explicit_mclk_control;
bool qcom_fifo;
bool qcom_dml;
bool reversed_irq_handling;
bool mmcimask1;
u32 start_err;
u32 opendrain;
void (*init)(struct mmci_host *host);
};
/* mmci variant callbacks */
struct mmci_host_ops {
void (*dma_setup)(struct mmci_host *host);
};
struct mmci_host_next { struct mmci_host_next {
struct dma_async_tx_descriptor *dma_desc; struct dma_async_tx_descriptor *dma_desc;
...@@ -228,6 +306,7 @@ struct mmci_host { ...@@ -228,6 +306,7 @@ struct mmci_host {
u32 mask1_reg; u32 mask1_reg;
bool vqmmc_enabled; bool vqmmc_enabled;
struct mmci_platform_data *plat; struct mmci_platform_data *plat;
struct mmci_host_ops *ops;
struct variant_data *variant; struct variant_data *variant;
struct pinctrl *pinctrl; struct pinctrl *pinctrl;
struct pinctrl_state *pins_default; struct pinctrl_state *pins_default;
......
...@@ -119,17 +119,20 @@ static int of_get_dml_pipe_index(struct device_node *np, const char *name) ...@@ -119,17 +119,20 @@ static int of_get_dml_pipe_index(struct device_node *np, const char *name)
} }
/* Initialize the dml hardware connected to SD Card controller */ /* Initialize the dml hardware connected to SD Card controller */
int dml_hw_init(struct mmci_host *host, struct device_node *np) static void qcom_dma_setup(struct mmci_host *host)
{ {
u32 config; u32 config;
void __iomem *base; void __iomem *base;
int consumer_id, producer_id; int consumer_id, producer_id;
struct device_node *np = host->mmc->parent->of_node;
consumer_id = of_get_dml_pipe_index(np, "tx"); consumer_id = of_get_dml_pipe_index(np, "tx");
producer_id = of_get_dml_pipe_index(np, "rx"); producer_id = of_get_dml_pipe_index(np, "rx");
if (producer_id < 0 || consumer_id < 0) if (producer_id < 0 || consumer_id < 0) {
return -ENODEV; host->variant->qcom_dml = false;
return;
}
base = host->base + DML_OFFSET; base = host->base + DML_OFFSET;
...@@ -172,6 +175,13 @@ int dml_hw_init(struct mmci_host *host, struct device_node *np) ...@@ -172,6 +175,13 @@ int dml_hw_init(struct mmci_host *host, struct device_node *np)
/* Make sure dml initialization is finished */ /* Make sure dml initialization is finished */
mb(); mb();
}
return 0; static struct mmci_host_ops qcom_variant_ops = {
.dma_setup = qcom_dma_setup,
};
void qcom_variant_init(struct mmci_host *host)
{
host->ops = &qcom_variant_ops;
} }
...@@ -16,12 +16,11 @@ ...@@ -16,12 +16,11 @@
#define __MMC_QCOM_DML_H__ #define __MMC_QCOM_DML_H__
#ifdef CONFIG_MMC_QCOM_DML #ifdef CONFIG_MMC_QCOM_DML
int dml_hw_init(struct mmci_host *host, struct device_node *np); void qcom_variant_init(struct mmci_host *host);
void dml_start_xfer(struct mmci_host *host, struct mmc_data *data); void dml_start_xfer(struct mmci_host *host, struct mmc_data *data);
#else #else
static inline int dml_hw_init(struct mmci_host *host, struct device_node *np) static inline void qcom_variant_init(struct mmci_host *host)
{ {
return -ENOSYS;
} }
static inline void dml_start_xfer(struct mmci_host *host, struct mmc_data *data) static inline void dml_start_xfer(struct mmci_host *host, struct mmc_data *data)
{ {
......
...@@ -58,11 +58,11 @@ struct pxamci_host { ...@@ -58,11 +58,11 @@ struct pxamci_host {
void __iomem *base; void __iomem *base;
struct clk *clk; struct clk *clk;
unsigned long clkrate; unsigned long clkrate;
int irq;
unsigned int clkrt; unsigned int clkrt;
unsigned int cmdat; unsigned int cmdat;
unsigned int imask; unsigned int imask;
unsigned int power_mode; unsigned int power_mode;
unsigned long detect_delay_ms;
struct pxamci_platform_data *pdata; struct pxamci_platform_data *pdata;
struct mmc_request *mrq; struct mmc_request *mrq;
...@@ -72,64 +72,48 @@ struct pxamci_host { ...@@ -72,64 +72,48 @@ struct pxamci_host {
struct dma_chan *dma_chan_rx; struct dma_chan *dma_chan_rx;
struct dma_chan *dma_chan_tx; struct dma_chan *dma_chan_tx;
dma_cookie_t dma_cookie; dma_cookie_t dma_cookie;
dma_addr_t sg_dma;
unsigned int dma_len; unsigned int dma_len;
unsigned int dma_dir; unsigned int dma_dir;
unsigned int dma_drcmrrx;
unsigned int dma_drcmrtx;
struct regulator *vcc;
}; };
static inline void pxamci_init_ocr(struct pxamci_host *host) static int pxamci_init_ocr(struct pxamci_host *host)
{ {
#ifdef CONFIG_REGULATOR struct mmc_host *mmc = host->mmc;
host->vcc = devm_regulator_get_optional(mmc_dev(host->mmc), "vmmc"); int ret;
if (IS_ERR(host->vcc)) ret = mmc_regulator_get_supply(mmc);
host->vcc = NULL; if (ret < 0)
else { return ret;
host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc);
if (host->pdata && host->pdata->ocr_mask) if (IS_ERR(mmc->supply.vmmc)) {
dev_warn(mmc_dev(host->mmc),
"ocr_mask/setpower will not be used\n");
}
#endif
if (host->vcc == NULL) {
/* fall-back to platform data */ /* fall-back to platform data */
host->mmc->ocr_avail = host->pdata ? mmc->ocr_avail = host->pdata ?
host->pdata->ocr_mask : host->pdata->ocr_mask :
MMC_VDD_32_33 | MMC_VDD_33_34; MMC_VDD_32_33 | MMC_VDD_33_34;
} }
return 0;
} }
static inline int pxamci_set_power(struct pxamci_host *host, static inline int pxamci_set_power(struct pxamci_host *host,
unsigned char power_mode, unsigned char power_mode,
unsigned int vdd) unsigned int vdd)
{ {
struct mmc_host *mmc = host->mmc;
struct regulator *supply = mmc->supply.vmmc;
int on; int on;
if (host->vcc) { if (!IS_ERR(supply))
int ret; return mmc_regulator_set_ocr(mmc, supply, vdd);
if (power_mode == MMC_POWER_UP) { if (host->pdata &&
ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
if (ret)
return ret;
} else if (power_mode == MMC_POWER_OFF) {
ret = mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
if (ret)
return ret;
}
}
if (!host->vcc && host->pdata &&
gpio_is_valid(host->pdata->gpio_power)) { gpio_is_valid(host->pdata->gpio_power)) {
on = ((1 << vdd) & host->pdata->ocr_mask); on = ((1 << vdd) & host->pdata->ocr_mask);
gpio_set_value(host->pdata->gpio_power, gpio_set_value(host->pdata->gpio_power,
!!on ^ host->pdata->gpio_power_invert); !!on ^ host->pdata->gpio_power_invert);
} }
if (!host->vcc && host->pdata && host->pdata->setpower)
if (host->pdata && host->pdata->setpower)
return host->pdata->setpower(mmc_dev(host->mmc), vdd); return host->pdata->setpower(mmc_dev(host->mmc), vdd);
return 0; return 0;
...@@ -584,7 +568,7 @@ static irqreturn_t pxamci_detect_irq(int irq, void *devid) ...@@ -584,7 +568,7 @@ static irqreturn_t pxamci_detect_irq(int irq, void *devid)
{ {
struct pxamci_host *host = mmc_priv(devid); struct pxamci_host *host = mmc_priv(devid);
mmc_detect_change(devid, msecs_to_jiffies(host->pdata->detect_delay_ms)); mmc_detect_change(devid, msecs_to_jiffies(host->detect_delay_ms));
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -596,37 +580,30 @@ static const struct of_device_id pxa_mmc_dt_ids[] = { ...@@ -596,37 +580,30 @@ static const struct of_device_id pxa_mmc_dt_ids[] = {
MODULE_DEVICE_TABLE(of, pxa_mmc_dt_ids); MODULE_DEVICE_TABLE(of, pxa_mmc_dt_ids);
static int pxamci_of_init(struct platform_device *pdev) static int pxamci_of_init(struct platform_device *pdev,
struct mmc_host *mmc)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
struct pxamci_platform_data *pdata; struct pxamci_host *host = mmc_priv(mmc);
u32 tmp; u32 tmp;
int ret;
if (!np)
return 0;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
pdata->gpio_card_detect = if (!np)
of_get_named_gpio(np, "cd-gpios", 0); return 0;
pdata->gpio_card_ro =
of_get_named_gpio(np, "wp-gpios", 0);
/* pxa-mmc specific */ /* pxa-mmc specific */
pdata->gpio_power =
of_get_named_gpio(np, "pxa-mmc,gpio-power", 0);
if (of_property_read_u32(np, "pxa-mmc,detect-delay-ms", &tmp) == 0) if (of_property_read_u32(np, "pxa-mmc,detect-delay-ms", &tmp) == 0)
pdata->detect_delay_ms = tmp; host->detect_delay_ms = tmp;
pdev->dev.platform_data = pdata; ret = mmc_of_parse(mmc);
if (ret < 0)
return ret;
return 0; return 0;
} }
#else #else
static int pxamci_of_init(struct platform_device *pdev) static int pxamci_of_init(struct platform_device *pdev,
struct mmc_host *mmc)
{ {
return 0; return 0;
} }
...@@ -636,19 +613,16 @@ static int pxamci_probe(struct platform_device *pdev) ...@@ -636,19 +613,16 @@ static int pxamci_probe(struct platform_device *pdev)
{ {
struct mmc_host *mmc; struct mmc_host *mmc;
struct pxamci_host *host = NULL; struct pxamci_host *host = NULL;
struct device *dev = &pdev->dev;
struct resource *r; struct resource *r;
int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1; int ret, irq;
ret = pxamci_of_init(pdev);
if (ret)
return ret;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) if (irq < 0)
return irq; return irq;
mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev); mmc = mmc_alloc_host(sizeof(struct pxamci_host), dev);
if (!mmc) { if (!mmc) {
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
...@@ -677,12 +651,16 @@ static int pxamci_probe(struct platform_device *pdev) ...@@ -677,12 +651,16 @@ static int pxamci_probe(struct platform_device *pdev)
*/ */
mmc->max_blk_count = 65535; mmc->max_blk_count = 65535;
ret = pxamci_of_init(pdev, mmc);
if (ret)
return ret;
host = mmc_priv(mmc); host = mmc_priv(mmc);
host->mmc = mmc; host->mmc = mmc;
host->pdata = pdev->dev.platform_data; host->pdata = pdev->dev.platform_data;
host->clkrt = CLKRT_OFF; host->clkrt = CLKRT_OFF;
host->clk = devm_clk_get(&pdev->dev, NULL); host->clk = devm_clk_get(dev, NULL);
if (IS_ERR(host->clk)) { if (IS_ERR(host->clk)) {
ret = PTR_ERR(host->clk); ret = PTR_ERR(host->clk);
host->clk = NULL; host->clk = NULL;
...@@ -697,7 +675,9 @@ static int pxamci_probe(struct platform_device *pdev) ...@@ -697,7 +675,9 @@ static int pxamci_probe(struct platform_device *pdev)
mmc->f_min = (host->clkrate + 63) / 64; mmc->f_min = (host->clkrate + 63) / 64;
mmc->f_max = (mmc_has_26MHz()) ? 26000000 : host->clkrate; mmc->f_max = (mmc_has_26MHz()) ? 26000000 : host->clkrate;
pxamci_init_ocr(host); ret = pxamci_init_ocr(host);
if (ret < 0)
return ret;
mmc->caps = 0; mmc->caps = 0;
host->cmdat = 0; host->cmdat = 0;
...@@ -711,10 +691,9 @@ static int pxamci_probe(struct platform_device *pdev) ...@@ -711,10 +691,9 @@ static int pxamci_probe(struct platform_device *pdev)
spin_lock_init(&host->lock); spin_lock_init(&host->lock);
host->res = r; host->res = r;
host->irq = irq;
host->imask = MMC_I_MASK_ALL; host->imask = MMC_I_MASK_ALL;
host->base = devm_ioremap_resource(&pdev->dev, r); host->base = devm_ioremap_resource(dev, r);
if (IS_ERR(host->base)) { if (IS_ERR(host->base)) {
ret = PTR_ERR(host->base); ret = PTR_ERR(host->base);
goto out; goto out;
...@@ -729,69 +708,76 @@ static int pxamci_probe(struct platform_device *pdev) ...@@ -729,69 +708,76 @@ static int pxamci_probe(struct platform_device *pdev)
writel(64, host->base + MMC_RESTO); writel(64, host->base + MMC_RESTO);
writel(host->imask, host->base + MMC_I_MASK); writel(host->imask, host->base + MMC_I_MASK);
ret = devm_request_irq(&pdev->dev, host->irq, pxamci_irq, 0, ret = devm_request_irq(dev, irq, pxamci_irq, 0,
DRIVER_NAME, host); DRIVER_NAME, host);
if (ret) if (ret)
goto out; goto out;
platform_set_drvdata(pdev, mmc); platform_set_drvdata(pdev, mmc);
host->dma_chan_rx = dma_request_slave_channel(&pdev->dev, "rx"); host->dma_chan_rx = dma_request_slave_channel(dev, "rx");
if (host->dma_chan_rx == NULL) { if (host->dma_chan_rx == NULL) {
dev_err(&pdev->dev, "unable to request rx dma channel\n"); dev_err(dev, "unable to request rx dma channel\n");
ret = -ENODEV; ret = -ENODEV;
goto out; goto out;
} }
host->dma_chan_tx = dma_request_slave_channel(&pdev->dev, "tx"); host->dma_chan_tx = dma_request_slave_channel(dev, "tx");
if (host->dma_chan_tx == NULL) { if (host->dma_chan_tx == NULL) {
dev_err(&pdev->dev, "unable to request tx dma channel\n"); dev_err(dev, "unable to request tx dma channel\n");
ret = -ENODEV; ret = -ENODEV;
goto out; goto out;
} }
if (host->pdata) { if (host->pdata) {
gpio_cd = host->pdata->gpio_card_detect; int gpio_cd = host->pdata->gpio_card_detect;
gpio_ro = host->pdata->gpio_card_ro; int gpio_ro = host->pdata->gpio_card_ro;
gpio_power = host->pdata->gpio_power; int gpio_power = host->pdata->gpio_power;
}
if (gpio_is_valid(gpio_power)) { host->detect_delay_ms = host->pdata->detect_delay_ms;
ret = devm_gpio_request(&pdev->dev, gpio_power,
"mmc card power"); if (gpio_is_valid(gpio_power)) {
if (ret) { ret = devm_gpio_request(dev, gpio_power,
dev_err(&pdev->dev, "Failed requesting gpio_power %d\n", "mmc card power");
gpio_power); if (ret) {
goto out; dev_err(dev,
"Failed requesting gpio_power %d\n",
gpio_power);
goto out;
}
gpio_direction_output(gpio_power,
host->pdata->gpio_power_invert);
} }
gpio_direction_output(gpio_power,
host->pdata->gpio_power_invert); if (gpio_is_valid(gpio_ro)) {
} ret = mmc_gpio_request_ro(mmc, gpio_ro);
if (gpio_is_valid(gpio_ro)) { if (ret) {
ret = mmc_gpio_request_ro(mmc, gpio_ro); dev_err(dev,
"Failed requesting gpio_ro %d\n",
gpio_ro);
goto out;
} else {
mmc->caps2 |= host->pdata->gpio_card_ro_invert ?
0 : MMC_CAP2_RO_ACTIVE_HIGH;
}
}
if (gpio_is_valid(gpio_cd))
ret = mmc_gpio_request_cd(mmc, gpio_cd, 0);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n", dev_err(dev, "Failed requesting gpio_cd %d\n",
gpio_ro); gpio_cd);
goto out; goto out;
} else {
mmc->caps2 |= host->pdata->gpio_card_ro_invert ?
0 : MMC_CAP2_RO_ACTIVE_HIGH;
} }
}
if (gpio_is_valid(gpio_cd)) if (host->pdata->init)
ret = mmc_gpio_request_cd(mmc, gpio_cd, 0); host->pdata->init(dev, pxamci_detect_irq, mmc);
if (ret) {
dev_err(&pdev->dev, "Failed requesting gpio_cd %d\n", gpio_cd);
goto out;
}
if (host->pdata && host->pdata->init)
host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc);
if (gpio_is_valid(gpio_power) && host->pdata->setpower) if (gpio_is_valid(gpio_power) && host->pdata->setpower)
dev_warn(&pdev->dev, "gpio_power and setpower() both defined\n"); dev_warn(dev, "gpio_power and setpower() both defined\n");
if (gpio_is_valid(gpio_ro) && host->pdata->get_ro) if (gpio_is_valid(gpio_ro) && host->pdata->get_ro)
dev_warn(&pdev->dev, "gpio_ro and get_ro() both defined\n"); dev_warn(dev, "gpio_ro and get_ro() both defined\n");
}
mmc_add_host(mmc); mmc_add_host(mmc);
...@@ -812,18 +798,12 @@ static int pxamci_probe(struct platform_device *pdev) ...@@ -812,18 +798,12 @@ static int pxamci_probe(struct platform_device *pdev)
static int pxamci_remove(struct platform_device *pdev) static int pxamci_remove(struct platform_device *pdev)
{ {
struct mmc_host *mmc = platform_get_drvdata(pdev); struct mmc_host *mmc = platform_get_drvdata(pdev);
int gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
if (mmc) { if (mmc) {
struct pxamci_host *host = mmc_priv(mmc); struct pxamci_host *host = mmc_priv(mmc);
mmc_remove_host(mmc); mmc_remove_host(mmc);
if (host->pdata) {
gpio_cd = host->pdata->gpio_card_detect;
gpio_ro = host->pdata->gpio_card_ro;
gpio_power = host->pdata->gpio_power;
}
if (host->pdata && host->pdata->exit) if (host->pdata && host->pdata->exit)
host->pdata->exit(&pdev->dev, mmc); host->pdata->exit(&pdev->dev, mmc);
...@@ -839,6 +819,7 @@ static int pxamci_remove(struct platform_device *pdev) ...@@ -839,6 +819,7 @@ static int pxamci_remove(struct platform_device *pdev)
mmc_free_host(mmc); mmc_free_host(mmc);
} }
return 0; return 0;
} }
......
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