You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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 ...
This commit is contained in:
@@ -37,6 +37,8 @@ Optional Properties:
|
||||
- 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
|
||||
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:
|
||||
sdhci@e0100000 {
|
||||
|
||||
@@ -8,10 +8,9 @@ Required properties:
|
||||
|
||||
Optional properties:
|
||||
- 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
|
||||
and the properties used by the pxa-mmc driver.
|
||||
In addition to the properties described in this docuent, the details
|
||||
described in mmc.txt are supported.
|
||||
|
||||
Examples:
|
||||
|
||||
@@ -19,6 +18,7 @@ mmc0: mmc@41100000 {
|
||||
compatible = "marvell,pxa-mmc";
|
||||
reg = <0x41100000 0x1000>;
|
||||
interrupts = <23>;
|
||||
vmmc-supply = <&mmc_regulator>;
|
||||
cd-gpios = <&gpio 23 0>;
|
||||
wp-gpios = <&gpio 24 0>;
|
||||
};
|
||||
|
||||
@@ -14,6 +14,7 @@ Required Properties:
|
||||
before RK3288
|
||||
- "rockchip,rk3288-dw-mshc": for Rockchip RK3288
|
||||
- "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,rk3228-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK322x
|
||||
- "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
|
||||
and the properties used by the sdhci-msm driver.
|
||||
|
||||
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:
|
||||
- Host controller register map (required)
|
||||
- SD Core register map (required)
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
* 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:
|
||||
"renesas,sdhi-r8a7796" - SDHI IP on R8A7796 SoC
|
||||
"renesas,sdhi-r8a77965" - SDHI IP on R8A77965 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-shmobile" - a generic sh-mobile SDHI controller
|
||||
"renesas,rcar-gen1-sdhi" - a generic R-Car Gen1 SDHI controller
|
||||
|
||||
@@ -12916,6 +12916,13 @@ S: Maintained
|
||||
F: drivers/mmc/host/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
|
||||
M: Ben Dooks <ben-linux@fluff.org>
|
||||
M: Jaehoon Chung <jh80.chung@samsung.com>
|
||||
|
||||
+1
-47
@@ -2078,7 +2078,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
|
||||
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
|
||||
/* Do not retry else we can't see errors */
|
||||
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",
|
||||
err, cmd.resp[0]);
|
||||
err = -EIO;
|
||||
@@ -2716,52 +2716,6 @@ void mmc_stop_host(struct mmc_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
|
||||
/* 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
|
||||
|
||||
@@ -28,8 +28,6 @@ struct mmc_bus_ops {
|
||||
int (*resume)(struct mmc_host *);
|
||||
int (*runtime_suspend)(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 (*shutdown)(struct mmc_host *);
|
||||
int (*hw_reset)(struct mmc_host *);
|
||||
|
||||
+15
-1
@@ -1169,6 +1169,10 @@ static int mmc_select_hs400(struct mmc_card *card)
|
||||
/* Set host controller to HS timing */
|
||||
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 */
|
||||
max_dtr = card->ext_csd.hs_max_dtr;
|
||||
mmc_set_clock(host, max_dtr);
|
||||
@@ -1209,6 +1213,9 @@ static int mmc_select_hs400(struct mmc_card *card)
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
if (host->ops->hs400_complete)
|
||||
host->ops->hs400_complete(host);
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
@@ -1256,6 +1263,9 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
|
||||
|
||||
mmc_set_timing(host, MMC_TIMING_MMC_HS);
|
||||
|
||||
if (host->ops->hs400_downgrade)
|
||||
host->ops->hs400_downgrade(host);
|
||||
|
||||
err = mmc_switch_status(card);
|
||||
if (err)
|
||||
goto out_err;
|
||||
@@ -1338,8 +1348,12 @@ static int mmc_select_hs400es(struct mmc_card *card)
|
||||
goto out_err;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Switch card to HS mode */
|
||||
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)
|
||||
if (status & R1_SPI_ILLEGAL_COMMAND)
|
||||
return -EBADMSG;
|
||||
} else {
|
||||
if (status & 0xFDFFA000)
|
||||
if (R1_STATUS(status))
|
||||
pr_warn("%s: unexpected status %#x after switch\n",
|
||||
mmc_hostname(host), status);
|
||||
if (status & R1_SWITCH_ERROR)
|
||||
|
||||
@@ -1076,7 +1076,6 @@ static const struct mmc_bus_ops mmc_sdio_ops = {
|
||||
.resume = mmc_sdio_resume,
|
||||
.runtime_suspend = mmc_sdio_runtime_suspend,
|
||||
.runtime_resume = mmc_sdio_runtime_resume,
|
||||
.power_restore = mmc_sdio_power_restore,
|
||||
.alive = mmc_sdio_alive,
|
||||
.hw_reset = mmc_sdio_hw_reset,
|
||||
.sw_reset = mmc_sdio_sw_reset,
|
||||
|
||||
@@ -176,6 +176,17 @@ config MMC_SDHCI_OF_HLWD
|
||||
|
||||
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
|
||||
tristate "SDHCI support for the Cadence SD/SDIO/eMMC controller"
|
||||
depends on MMC_SDHCI_PLTFM
|
||||
|
||||
@@ -11,7 +11,8 @@ obj-$(CONFIG_MMC_MXC) += mxcmmc.o
|
||||
obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
|
||||
obj-$(CONFIG_MMC_SDHCI) += sdhci.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-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o
|
||||
obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.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_ESDHC) += sdhci-of-esdhc.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_IPROC) += sdhci-iproc.o
|
||||
obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o
|
||||
|
||||
@@ -175,6 +175,20 @@ static int dw_mci_exynos_runtime_resume(struct device *dev)
|
||||
|
||||
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
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
static int dw_mci_exynos_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct dw_mci *host = dev_get_drvdata(dev);
|
||||
struct dw_mci_exynos_priv_data *priv = host->priv;
|
||||
u32 clksel;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_force_resume(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
|
||||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
|
||||
@@ -207,11 +225,11 @@ static int dw_mci_exynos_resume_noirq(struct device *dev)
|
||||
mci_writel(host, CLKSEL, clksel);
|
||||
}
|
||||
|
||||
pm_runtime_put(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define dw_mci_exynos_resume_noirq NULL
|
||||
#endif /* CONFIG_PM */
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops dw_mci_exynos_pmops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
|
||||
pm_runtime_force_resume)
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend_noirq,
|
||||
dw_mci_exynos_resume_noirq)
|
||||
SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
|
||||
dw_mci_exynos_runtime_resume,
|
||||
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 = {
|
||||
|
||||
+6
-76
@@ -48,78 +48,6 @@
|
||||
|
||||
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 = {
|
||||
.fifosize = 16 * 4,
|
||||
.fifohalfsize = 8 * 4,
|
||||
@@ -280,6 +208,7 @@ static struct variant_data variant_qcom = {
|
||||
.mmcimask1 = true,
|
||||
.start_err = MCI_STARTBITERR,
|
||||
.opendrain = MCI_ROD,
|
||||
.init = qcom_variant_init,
|
||||
};
|
||||
|
||||
/* Busy detection for the ST Micro variant */
|
||||
@@ -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)
|
||||
{
|
||||
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_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx");
|
||||
@@ -537,9 +465,8 @@ static void mmci_dma_setup(struct mmci_host *host)
|
||||
host->mmc->max_seg_size = max_seg_size;
|
||||
}
|
||||
|
||||
if (variant->qcom_dml && host->dma_rx_channel && host->dma_tx_channel)
|
||||
if (dml_hw_init(host, host->mmc->parent->of_node))
|
||||
variant->qcom_dml = false;
|
||||
if (host->ops && host->ops->dma_setup)
|
||||
host->ops->dma_setup(host);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1706,6 +1633,9 @@ static int mmci_probe(struct amba_device *dev,
|
||||
goto clk_disable;
|
||||
}
|
||||
|
||||
if (variant->init)
|
||||
variant->init(host);
|
||||
|
||||
/*
|
||||
* The ARM and ST versions of the block have slightly different
|
||||
* clock divider equations which means that the minimum divider
|
||||
|
||||
+80
-1
@@ -195,8 +195,86 @@
|
||||
#define MMCI_PINCTRL_STATE_OPENDRAIN "opendrain"
|
||||
|
||||
struct clk;
|
||||
struct variant_data;
|
||||
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 dma_async_tx_descriptor *dma_desc;
|
||||
@@ -228,6 +306,7 @@ struct mmci_host {
|
||||
u32 mask1_reg;
|
||||
bool vqmmc_enabled;
|
||||
struct mmci_platform_data *plat;
|
||||
struct mmci_host_ops *ops;
|
||||
struct variant_data *variant;
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *pins_default;
|
||||
|
||||
@@ -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 */
|
||||
int dml_hw_init(struct mmci_host *host, struct device_node *np)
|
||||
static void qcom_dma_setup(struct mmci_host *host)
|
||||
{
|
||||
u32 config;
|
||||
void __iomem *base;
|
||||
int consumer_id, producer_id;
|
||||
struct device_node *np = host->mmc->parent->of_node;
|
||||
|
||||
consumer_id = of_get_dml_pipe_index(np, "tx");
|
||||
producer_id = of_get_dml_pipe_index(np, "rx");
|
||||
|
||||
if (producer_id < 0 || consumer_id < 0)
|
||||
return -ENODEV;
|
||||
if (producer_id < 0 || consumer_id < 0) {
|
||||
host->variant->qcom_dml = false;
|
||||
return;
|
||||
}
|
||||
|
||||
base = host->base + DML_OFFSET;
|
||||
|
||||
@@ -172,6 +175,13 @@ int dml_hw_init(struct mmci_host *host, struct device_node *np)
|
||||
|
||||
/* Make sure dml initialization is finished */
|
||||
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 @@
|
||||
#define __MMC_QCOM_DML_H__
|
||||
|
||||
#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);
|
||||
#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)
|
||||
{
|
||||
|
||||
+96
-115
@@ -58,11 +58,11 @@ struct pxamci_host {
|
||||
void __iomem *base;
|
||||
struct clk *clk;
|
||||
unsigned long clkrate;
|
||||
int irq;
|
||||
unsigned int clkrt;
|
||||
unsigned int cmdat;
|
||||
unsigned int imask;
|
||||
unsigned int power_mode;
|
||||
unsigned long detect_delay_ms;
|
||||
struct pxamci_platform_data *pdata;
|
||||
|
||||
struct mmc_request *mrq;
|
||||
@@ -72,64 +72,48 @@ struct pxamci_host {
|
||||
struct dma_chan *dma_chan_rx;
|
||||
struct dma_chan *dma_chan_tx;
|
||||
dma_cookie_t dma_cookie;
|
||||
dma_addr_t sg_dma;
|
||||
unsigned int dma_len;
|
||||
|
||||
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
|
||||
host->vcc = devm_regulator_get_optional(mmc_dev(host->mmc), "vmmc");
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
int ret;
|
||||
|
||||
if (IS_ERR(host->vcc))
|
||||
host->vcc = NULL;
|
||||
else {
|
||||
host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc);
|
||||
if (host->pdata && host->pdata->ocr_mask)
|
||||
dev_warn(mmc_dev(host->mmc),
|
||||
"ocr_mask/setpower will not be used\n");
|
||||
}
|
||||
#endif
|
||||
if (host->vcc == NULL) {
|
||||
ret = mmc_regulator_get_supply(mmc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (IS_ERR(mmc->supply.vmmc)) {
|
||||
/* fall-back to platform data */
|
||||
host->mmc->ocr_avail = host->pdata ?
|
||||
mmc->ocr_avail = host->pdata ?
|
||||
host->pdata->ocr_mask :
|
||||
MMC_VDD_32_33 | MMC_VDD_33_34;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int pxamci_set_power(struct pxamci_host *host,
|
||||
unsigned char power_mode,
|
||||
unsigned int vdd)
|
||||
{
|
||||
struct mmc_host *mmc = host->mmc;
|
||||
struct regulator *supply = mmc->supply.vmmc;
|
||||
int on;
|
||||
|
||||
if (host->vcc) {
|
||||
int ret;
|
||||
if (!IS_ERR(supply))
|
||||
return mmc_regulator_set_ocr(mmc, supply, vdd);
|
||||
|
||||
if (power_mode == MMC_POWER_UP) {
|
||||
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 &&
|
||||
if (host->pdata &&
|
||||
gpio_is_valid(host->pdata->gpio_power)) {
|
||||
on = ((1 << vdd) & host->pdata->ocr_mask);
|
||||
gpio_set_value(host->pdata->gpio_power,
|
||||
!!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 0;
|
||||
@@ -584,7 +568,7 @@ static irqreturn_t pxamci_detect_irq(int irq, void *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;
|
||||
}
|
||||
|
||||
@@ -596,37 +580,30 @@ static const struct of_device_id 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 pxamci_platform_data *pdata;
|
||||
u32 tmp;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct pxamci_host *host = mmc_priv(mmc);
|
||||
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 =
|
||||
of_get_named_gpio(np, "cd-gpios", 0);
|
||||
pdata->gpio_card_ro =
|
||||
of_get_named_gpio(np, "wp-gpios", 0);
|
||||
if (!np)
|
||||
return 0;
|
||||
|
||||
/* 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)
|
||||
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
|
||||
static int pxamci_of_init(struct platform_device *pdev)
|
||||
static int pxamci_of_init(struct platform_device *pdev,
|
||||
struct mmc_host *mmc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -636,19 +613,16 @@ static int pxamci_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mmc_host *mmc;
|
||||
struct pxamci_host *host = NULL;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *r;
|
||||
int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
|
||||
|
||||
ret = pxamci_of_init(pdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
int ret, irq;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
mmc = mmc_alloc_host(sizeof(struct pxamci_host), &pdev->dev);
|
||||
mmc = mmc_alloc_host(sizeof(struct pxamci_host), dev);
|
||||
if (!mmc) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
@@ -677,12 +651,16 @@ static int pxamci_probe(struct platform_device *pdev)
|
||||
*/
|
||||
mmc->max_blk_count = 65535;
|
||||
|
||||
ret = pxamci_of_init(pdev, mmc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
host = mmc_priv(mmc);
|
||||
host->mmc = mmc;
|
||||
host->pdata = pdev->dev.platform_data;
|
||||
host->clkrt = CLKRT_OFF;
|
||||
|
||||
host->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
host->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(host->clk)) {
|
||||
ret = PTR_ERR(host->clk);
|
||||
host->clk = NULL;
|
||||
@@ -697,7 +675,9 @@ static int pxamci_probe(struct platform_device *pdev)
|
||||
mmc->f_min = (host->clkrate + 63) / 64;
|
||||
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;
|
||||
host->cmdat = 0;
|
||||
@@ -711,10 +691,9 @@ static int pxamci_probe(struct platform_device *pdev)
|
||||
|
||||
spin_lock_init(&host->lock);
|
||||
host->res = r;
|
||||
host->irq = irq;
|
||||
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)) {
|
||||
ret = PTR_ERR(host->base);
|
||||
goto out;
|
||||
@@ -729,70 +708,77 @@ static int pxamci_probe(struct platform_device *pdev)
|
||||
writel(64, host->base + MMC_RESTO);
|
||||
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);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
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) {
|
||||
dev_err(&pdev->dev, "unable to request rx dma channel\n");
|
||||
dev_err(dev, "unable to request rx dma channel\n");
|
||||
ret = -ENODEV;
|
||||
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) {
|
||||
dev_err(&pdev->dev, "unable to request tx dma channel\n");
|
||||
dev_err(dev, "unable to request tx dma channel\n");
|
||||
ret = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (host->pdata) {
|
||||
gpio_cd = host->pdata->gpio_card_detect;
|
||||
gpio_ro = host->pdata->gpio_card_ro;
|
||||
gpio_power = host->pdata->gpio_power;
|
||||
}
|
||||
if (gpio_is_valid(gpio_power)) {
|
||||
ret = devm_gpio_request(&pdev->dev, gpio_power,
|
||||
"mmc card power");
|
||||
int gpio_cd = host->pdata->gpio_card_detect;
|
||||
int gpio_ro = host->pdata->gpio_card_ro;
|
||||
int gpio_power = host->pdata->gpio_power;
|
||||
|
||||
host->detect_delay_ms = host->pdata->detect_delay_ms;
|
||||
|
||||
if (gpio_is_valid(gpio_power)) {
|
||||
ret = devm_gpio_request(dev, gpio_power,
|
||||
"mmc card power");
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"Failed requesting gpio_power %d\n",
|
||||
gpio_power);
|
||||
goto out;
|
||||
}
|
||||
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 (ret) {
|
||||
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) {
|
||||
dev_err(&pdev->dev, "Failed requesting gpio_power %d\n",
|
||||
gpio_power);
|
||||
dev_err(dev, "Failed requesting gpio_cd %d\n",
|
||||
gpio_cd);
|
||||
goto out;
|
||||
}
|
||||
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 (ret) {
|
||||
dev_err(&pdev->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) {
|
||||
dev_err(&pdev->dev, "Failed requesting gpio_cd %d\n", gpio_cd);
|
||||
goto out;
|
||||
if (host->pdata->init)
|
||||
host->pdata->init(dev, pxamci_detect_irq, mmc);
|
||||
|
||||
if (gpio_is_valid(gpio_power) && host->pdata->setpower)
|
||||
dev_warn(dev, "gpio_power and setpower() both defined\n");
|
||||
if (gpio_is_valid(gpio_ro) && host->pdata->get_ro)
|
||||
dev_warn(dev, "gpio_ro and get_ro() both defined\n");
|
||||
}
|
||||
|
||||
if (host->pdata && host->pdata->init)
|
||||
host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc);
|
||||
|
||||
if (gpio_is_valid(gpio_power) && host->pdata->setpower)
|
||||
dev_warn(&pdev->dev, "gpio_power and setpower() both defined\n");
|
||||
if (gpio_is_valid(gpio_ro) && host->pdata->get_ro)
|
||||
dev_warn(&pdev->dev, "gpio_ro and get_ro() both defined\n");
|
||||
|
||||
mmc_add_host(mmc);
|
||||
|
||||
return 0;
|
||||
@@ -812,18 +798,12 @@ out:
|
||||
static int pxamci_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mmc_host *mmc = platform_get_drvdata(pdev);
|
||||
int gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
|
||||
|
||||
if (mmc) {
|
||||
struct pxamci_host *host = mmc_priv(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)
|
||||
host->pdata->exit(&pdev->dev, mmc);
|
||||
|
||||
@@ -839,6 +819,7 @@ static int pxamci_remove(struct platform_device *pdev)
|
||||
|
||||
mmc_free_host(mmc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user