]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge tag 'mmc-updates-for-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 9 Apr 2014 15:39:39 +0000 (08:39 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 9 Apr 2014 15:39:39 +0000 (08:39 -0700)
Pull MMC updates from Chris Ball:
 "MMC highlights for 3.15:

  Core:
   - CONFIG_MMC_UNSAFE_RESUME=y is now default behavior
   - DT bindings for SDHCI UHS, eMMC HS200, high-speed DDR, at 1.8/1.2V
   - Add GPIO descriptor based slot-gpio card detect API

  Drivers:
   - dw_mmc: Refactor SOCFPGA support as a variant inside dw_mmc-pltfm.c
   - mmci: Support HW busy detection on ux500
   - omap: Support MMC_ERASE
   - omap_hsmmc: Support MMC_PM_KEEP_POWER, MMC_PM_WAKE_SDIO_IRQ, (a)cmd23
   - rtsx: Support pre-req/post-req async
   - sdhci: Add support for Realtek RTS5250 controllers
   - sdhci-acpi: Add support for 80860F16, fix 80860F14/SDIO card detect
   - sdhci-msm: Add new driver for Qualcomm SDHCI chipset support
   - sdhci-pxav3: Add support for Marvell Armada 380 and 385 SoCs"

* tag 'mmc-updates-for-3.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (102 commits)
  mmc: sdhci-acpi: Intel SDIO has broken card detect
  mmc: sdhci-pxav3: add support for the Armada 38x SDHCI controller
  mmc: sdhci-msm: Add platform_execute_tuning implementation
  mmc: sdhci-msm: Initial support for Qualcomm chipsets
  mmc: sdhci-msm: Qualcomm SDHCI binding documentation
  sdhci: only reprogram retuning timer when flag is set
  mmc: rename ARCH_BCM to ARCH_BCM_MOBILE
  mmc: sdhci: Allow for irq being shared
  mmc: sdhci-acpi: Add device id 80860F16
  mmc: sdhci-acpi: Fix broken card detect for ACPI HID 80860F14
  mmc: slot-gpio: Add GPIO descriptor based CD GPIO API
  mmc: slot-gpio: Split out CD IRQ request into a separate function
  mmc: slot-gpio: Record GPIO descriptors instead of GPIO numbers
  Revert "dts: socfpga: Add support for SD/MMC on the SOCFPGA platform"
  mmc: sdhci-spear: use generic card detection gpio support
  mmc: sdhci-spear: remove support for power gpio
  mmc: sdhci-spear: simplify resource handling
  mmc: sdhci-spear: fix platform_data usage
  mmc: sdhci-spear: fix error handling paths for DT
  mmc: sdhci-bcm-kona: fix build errors when built-in
  ...

63 files changed:
Documentation/devicetree/bindings/mmc/mmc.txt
Documentation/devicetree/bindings/mmc/sdhci-msm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/sdhci-pxa.txt
Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
Documentation/devicetree/bindings/regulator/pbias-regulator.txt [new file with mode: 0644]
MAINTAINERS
arch/arm/boot/dts/dra7.dtsi
arch/arm/boot/dts/omap2430.dtsi
arch/arm/boot/dts/omap3-ldp.dts
arch/arm/boot/dts/omap3.dtsi
arch/arm/boot/dts/omap4.dtsi
arch/arm/boot/dts/omap5.dtsi
arch/arm/configs/omap2plus_defconfig
drivers/mfd/rtsx_pcr.c
drivers/mmc/card/block.c
drivers/mmc/core/Kconfig
drivers/mmc/core/bus.c
drivers/mmc/core/core.c
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/sd.c
drivers/mmc/core/slot-gpio.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/davinci_mmc.c
drivers/mmc/host/dw_mmc-k3.c
drivers/mmc/host/dw_mmc-pltfm.c
drivers/mmc/host/dw_mmc-socfpga.c [deleted file]
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h
drivers/mmc/host/mmci.c
drivers/mmc/host/mmci.h
drivers/mmc/host/omap.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/rtsx_pci_sdmmc.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci-bcm-kona.c
drivers/mmc/host/sdhci-dove.c
drivers/mmc/host/sdhci-msm.c [new file with mode: 0644]
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-pxav3.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci-spear.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sh_mobile_sdhi.c
drivers/mmc/host/tmio_mmc.c
drivers/mmc/host/tmio_mmc.h
drivers/mmc/host/tmio_mmc_pio.c
drivers/mmc/host/ushc.c
drivers/mmc/host/wmt-sdmmc.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/pbias-regulator.c [new file with mode: 0644]
include/linux/mfd/rtsx_common.h
include/linux/mfd/rtsx_pci.h
include/linux/mmc/core.h
include/linux/mmc/host.h
include/linux/mmc/sdhci-spear.h
include/linux/mmc/sdhci.h
include/linux/mmc/slot-gpio.h
include/linux/platform_data/mmc-msm_sdcc.h
include/linux/platform_data/mmc-mvsdio.h

index 458b57f199afe6d56eb425ee4cbdceb532c28b53..9dce540771fb115f9b1eb8e0d73dca574589595e 100644 (file)
@@ -26,9 +26,18 @@ Optional properties:
   this system, even if the controller claims it is.
 - cap-sd-highspeed: SD high-speed timing is supported
 - cap-mmc-highspeed: MMC high-speed timing is supported
+- sd-uhs-sdr12: SD UHS SDR12 speed is supported
+- sd-uhs-sdr25: SD UHS SDR25 speed is supported
+- sd-uhs-sdr50: SD UHS SDR50 speed is supported
+- sd-uhs-sdr104: SD UHS SDR104 speed is supported
+- sd-uhs-ddr50: SD UHS DDR50 speed is supported
 - cap-power-off-card: powering off the card is safe
 - cap-sdio-irq: enable SDIO IRQ signalling on this interface
 - full-pwr-cycle: full power cycle of the card is supported
+- mmc-highspeed-ddr-1_8v: eMMC high-speed DDR mode(1.8V I/O) is supported
+- mmc-highspeed-ddr-1_2v: eMMC high-speed DDR mode(1.2V I/O) is supported
+- mmc-hs200-1_8v: eMMC HS200 mode(1.8V I/O) is supported
+- mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
 
 *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
 polarity properties, we have to fix the meaning of the "normal" and "inverted"
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
new file mode 100644 (file)
index 0000000..81b33b5
--- /dev/null
@@ -0,0 +1,55 @@
+* Qualcomm SDHCI controller (sdhci-msm)
+
+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".
+- reg: Base address and length of the register in the following order:
+       - Host controller register map (required)
+       - SD Core register map (required)
+- interrupts: Should contain an interrupt-specifiers for the interrupts:
+       - Host controller interrupt (required)
+- pinctrl-names: Should contain only one value - "default".
+- pinctrl-0: Should specify pin control groups used for this controller.
+- clocks: A list of phandle + clock-specifier pairs for the clocks listed in clock-names.
+- clock-names: Should contain the following:
+       "iface" - Main peripheral bus clock (PCLK/HCLK - AHB Bus clock) (required)
+       "core"  - SDC MMC clock (MCLK) (required)
+       "bus"   - SDCC bus voter clock (optional)
+
+Example:
+
+       sdhc_1: sdhci@f9824900 {
+               compatible = "qcom,sdhci-msm-v4";
+               reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
+               interrupts = <0 123 0>;
+               bus-width = <8>;
+               non-removable;
+
+               vmmc = <&pm8941_l20>;
+               vqmmc = <&pm8941_s3>;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&sdc1_clk &sdc1_cmd &sdc1_data>;
+
+               clocks = <&gcc GCC_SDCC1_APPS_CLK>, <&gcc GCC_SDCC1_AHB_CLK>;
+               clock-names = "core", "iface";
+       };
+
+       sdhc_2: sdhci@f98a4900 {
+               compatible = "qcom,sdhci-msm-v4";
+               reg = <0xf98a4900 0x11c>, <0xf98a4000 0x800>;
+               interrupts = <0 125 0>;
+               bus-width = <4>;
+               cd-gpios = <&msmgpio 62 0x1>;
+
+               vmmc = <&pm8941_l21>;
+               vqmmc = <&pm8941_l13>;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&sdc2_clk &sdc2_cmd &sdc2_data>;
+
+               clocks = <&gcc GCC_SDCC2_APPS_CLK>, <&gcc GCC_SDCC2_AHB_CLK>;
+               clock-names = "core", "iface";
+       };
index dbe98a3c183a53b534ef7fbfbafcd481ba516deb..86223c3eda905ad38234ce09443148b8eb0f0a72 100644 (file)
@@ -4,7 +4,14 @@ This file documents differences between the core properties in mmc.txt
 and the properties used by the sdhci-pxav2 and sdhci-pxav3 drivers.
 
 Required properties:
-- compatible: Should be "mrvl,pxav2-mmc" or "mrvl,pxav3-mmc".
+- compatible: Should be "mrvl,pxav2-mmc", "mrvl,pxav3-mmc" or
+  "marvell,armada-380-sdhci".
+- reg:
+  * for "mrvl,pxav2-mmc" and "mrvl,pxav3-mmc", one register area for
+    the SDHCI registers.
+  * for "marvell,armada-380-sdhci", two register areas. The first one
+    for the SDHCI registers themselves, and the second one for the
+    AXI/Mbus bridge registers of the SDHCI unit.
 
 Optional properties:
 - mrvl,clk-delay-cycles: Specify a number of cycles to delay for tuning.
@@ -19,3 +26,11 @@ sdhci@d4280800 {
        non-removable;
        mrvl,clk-delay-cycles = <31>;
 };
+
+sdhci@d8000 {
+       compatible = "marvell,armada-380-sdhci";
+       reg = <0xd8000 0x1000>, <0xdc000 0x100>;
+       interrupts = <0 25 0x4>;
+       clocks = <&gateclk 17>;
+       mrvl,clk-delay-cycles = <0x1F>;
+};
index 8c8908ab84bab3a570b422a93f15a7f8367adaa8..ce8056116fb0bd9c281ec4a2d60844e9eb551953 100644 (file)
@@ -10,6 +10,7 @@ Required properties:
 - compatible:
  Should be "ti,omap2-hsmmc", for OMAP2 controllers
  Should be "ti,omap3-hsmmc", for OMAP3 controllers
+ Should be "ti,omap3-pre-es3-hsmmc" for OMAP3 controllers pre ES3.0
  Should be "ti,omap4-hsmmc", for OMAP4 controllers
 - ti,hwmods: Must be "mmc<n>", n is controller instance starting 1
 
diff --git a/Documentation/devicetree/bindings/regulator/pbias-regulator.txt b/Documentation/devicetree/bindings/regulator/pbias-regulator.txt
new file mode 100644 (file)
index 0000000..32aa26f
--- /dev/null
@@ -0,0 +1,27 @@
+PBIAS internal regulator for SD card dual voltage i/o pads on OMAP SoCs.
+
+Required properties:
+- compatible:
+  - "ti,pbias-omap" for OMAP2, OMAP3, OMAP4, OMAP5, DRA7.
+- reg: pbias register offset from syscon base and size of pbias register.
+- syscon : phandle of the system control module
+- regulator-name : should be
+                       pbias_mmc_omap2430 for OMAP2430, OMAP3 SoCs
+                       pbias_sim_omap3 for OMAP3 SoCs
+                       pbias_mmc_omap4 for OMAP4 SoCs
+                       pbias_mmc_omap5 for OMAP5 and DRA7 SoC
+
+Optional properties:
+- Any optional property defined in bindings/regulator/regulator.txt
+
+Example:
+
+               pbias_regulator: pbias_regulator {
+                       compatible = "ti,pbias-omap";
+                       reg = <0 0x4>;
+                       syscon = <&omap5_padconf_global>;
+                       pbias_mmc_reg: pbias_mmc_omap5 {
+                               regulator-name = "pbias_mmc_omap5";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3000000>;
+                       };
index 7faf310014373593fe25ecc44f5d218eb75d1c5d..a769432bddbed4be6ce16fed58f4fb0822816b0c 100644 (file)
@@ -5930,6 +5930,7 @@ F:        include/linux/mfd/
 
 MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
 M:     Chris Ball <chris@printf.net>
+M:     Ulf Hansson <ulf.hansson@linaro.org>
 L:     linux-mmc@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git
 S:     Maintained
index 9e3caf3d19fbcf34187495a14eda3daf17aade4a..1c0f8e1893aed11eb3dfb8ca43360cbed2e961f6 100644 (file)
                        ti,hwmods = "counter_32k";
                };
 
+               dra7_ctrl_general: tisyscon@4a002e00 {
+                       compatible = "syscon";
+                       reg = <0x4a002e00 0x7c>;
+               };
+
+               pbias_regulator: pbias_regulator {
+                       compatible = "ti,pbias-omap";
+                       reg = <0 0x4>;
+                       syscon = <&dra7_ctrl_general>;
+                       pbias_mmc_reg: pbias_mmc_omap5 {
+                               regulator-name = "pbias_mmc_omap5";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3000000>;
+                       };
+               };
+
                dra7_pmx_core: pinmux@4a003400 {
                        compatible = "pinctrl-single";
                        reg = <0x4a003400 0x0464>;
                        dmas = <&sdma 61>, <&sdma 62>;
                        dma-names = "tx", "rx";
                        status = "disabled";
+                       pbias-supply = <&pbias_mmc_reg>;
                };
 
                mmc2: mmc@480b4000 {
index 9d2f028fd6872fd139a3855b4bf051411dbd9c23..d09697dab55e80063a737361c65138822bbdf828 100644 (file)
                        pinctrl-single,function-mask = <0x3f>;
                };
 
+               omap2_scm_general: tisyscon@49002270 {
+                       compatible = "syscon";
+                       reg = <0x49002270 0x240>;
+               };
+
+               pbias_regulator: pbias_regulator {
+                       compatible = "ti,pbias-omap";
+                       reg = <0x230 0x4>;
+                       syscon = <&omap2_scm_general>;
+                       pbias_mmc_reg: pbias_mmc_omap2430 {
+                               regulator-name = "pbias_mmc_omap2430";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3000000>;
+                       };
+               };
+
                gpio1: gpio@4900c000 {
                        compatible = "ti,omap2-gpio";
                        reg = <0x4900c000 0x200>;
                        ti,dual-volt;
                        dmas = <&sdma 61>, <&sdma 62>;
                        dma-names = "tx", "rx";
+                       pbias-supply = <&pbias_mmc_reg>;
                };
 
                mmc2: mmc@480b4000 {
index ddce0d807f7044ccb788b98ede9453d1a862a5eb..0abe986a4ecc19a7606690df50ec560e200b1f31 100644 (file)
 };
 
 &mmc1 {
+       /* See 35xx errata 2.1.1.128 in SPRZ278F */
+       compatible = "ti,omap3-pre-es3-hsmmc";
        vmmc-supply = <&vmmc1>;
        bus-width = <4>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc1_pins>;
+};
+
+&mmc2 {
+       status="disabled";
+};
+
+&mmc3 {
+       status="disabled";
 };
 
 &omap3_pmx_core {
                        0x174 (PIN_OUTPUT | MUX_MODE0)  /* hsusb0_stp.hsusb0_stp */
                >;
        };
+
+       mmc1_pins: pinmux_mmc1_pins {
+               pinctrl-single,pins = <
+                       OMAP3_CORE1_IOPAD(0x2144, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_clk.mmc1_clk */
+                       OMAP3_CORE1_IOPAD(0x2146, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_cmd.mmc1_cmd */
+                       OMAP3_CORE1_IOPAD(0x2148, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat0.mmc1_dat0 */
+                       OMAP3_CORE1_IOPAD(0x214A, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat1.mmc1_dat1 */
+                       OMAP3_CORE1_IOPAD(0x214C, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat2.mmc1_dat2 */
+                       OMAP3_CORE1_IOPAD(0x214e, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat3.mmc1_dat3 */
+               >;
+       };
 };
 
 &usb_otg_hs {
index 3d05eff67e25ea501410a3505788f513d20991f6..5e5790f631eba4b5b1085ac64a1c4d5a0f6062c9 100644 (file)
                        pinctrl-single,function-mask = <0xff1f>;
                };
 
+               omap3_scm_general: tisyscon@48002270 {
+                       compatible = "syscon";
+                       reg = <0x48002270 0x2f0>;
+               };
+
+               pbias_regulator: pbias_regulator {
+                       compatible = "ti,pbias-omap";
+                       reg = <0x2b0 0x4>;
+                       syscon = <&omap3_scm_general>;
+                       pbias_mmc_reg: pbias_mmc_omap2430 {
+                               regulator-name = "pbias_mmc_omap2430";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3000000>;
+                       };
+               };
+
                gpio1: gpio@48310000 {
                        compatible = "ti,omap3-gpio";
                        reg = <0x48310000 0x200>;
                        ti,dual-volt;
                        dmas = <&sdma 61>, <&sdma 62>;
                        dma-names = "tx", "rx";
+                       pbias-supply = <&pbias_mmc_reg>;
                };
 
                mmc2: mmc@480b4000 {
index 2b4c1cbbce3351e1cb6b9711307bc684242c7718..27fcac874742894879bb978b8157f213a1c49eb2 100644 (file)
                        pinctrl-single,function-mask = <0x7fff>;
                };
 
+               omap4_padconf_global: tisyscon@4a1005a0 {
+                       compatible = "syscon";
+                       reg = <0x4a1005a0 0x170>;
+               };
+
+               pbias_regulator: pbias_regulator {
+                       compatible = "ti,pbias-omap";
+                       reg = <0x60 0x4>;
+                       syscon = <&omap4_padconf_global>;
+                       pbias_mmc_reg: pbias_mmc_omap4 {
+                               regulator-name = "pbias_mmc_omap4";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3000000>;
+                       };
+               };
+
                sdma: dma-controller@4a056000 {
                        compatible = "ti,omap4430-sdma";
                        reg = <0x4a056000 0x1000>;
                        ti,needs-special-reset;
                        dmas = <&sdma 61>, <&sdma 62>;
                        dma-names = "tx", "rx";
+                       pbias-supply = <&pbias_mmc_reg>;
                };
 
                mmc2: mmc@480b4000 {
index 19155bb8483502dc4505c2d08e55dea8228b007b..6f3de22fb2660f20a61f2ec4438be6708ab40a6d 100644 (file)
                        pinctrl-single,function-mask = <0x7fff>;
                };
 
+               omap5_padconf_global: tisyscon@4a002da0 {
+                       compatible = "syscon";
+                       reg = <0x4A002da0 0xec>;
+               };
+
+               pbias_regulator: pbias_regulator {
+                       compatible = "ti,pbias-omap";
+                       reg = <0x60 0x4>;
+                       syscon = <&omap5_padconf_global>;
+                       pbias_mmc_reg: pbias_mmc_omap5 {
+                               regulator-name = "pbias_mmc_omap5";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3000000>;
+                       };
+               };
+
                sdma: dma-controller@4a056000 {
                        compatible = "ti,omap4430-sdma";
                        reg = <0x4a056000 0x1000>;
                        ti,needs-special-reset;
                        dmas = <&sdma 61>, <&sdma 62>;
                        dma-names = "tx", "rx";
+                       pbias-supply = <&pbias_mmc_reg>;
                };
 
                mmc2: mmc@480b4000 {
index 364ba38e40f3138317ef10407588b356732ab729..a9667957b7578bac7b218ea9163e657ecb385f88 100644 (file)
@@ -170,6 +170,7 @@ CONFIG_DRA752_THERMAL=y
 CONFIG_WATCHDOG=y
 CONFIG_OMAP_WATCHDOG=y
 CONFIG_TWL4030_WATCHDOG=y
+CONFIG_MFD_SYSCON=y
 CONFIG_MFD_PALMAS=y
 CONFIG_MFD_TPS65217=y
 CONFIG_MFD_TPS65910=y
@@ -181,6 +182,7 @@ CONFIG_REGULATOR_TPS6507X=y
 CONFIG_REGULATOR_TPS65217=y
 CONFIG_REGULATOR_TPS65910=y
 CONFIG_REGULATOR_TWL4030=y
+CONFIG_REGULATOR_PBIAS=y
 CONFIG_FB=y
 CONFIG_FIRMWARE_EDID=y
 CONFIG_FB_MODE_HELPERS=y
index 1d15735f9ef930ed18e384b1c63b7deb1fd42981..c9de3d598ea515279ff0f79f1214984b041266db 100644 (file)
@@ -338,58 +338,28 @@ int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
                int num_sg, bool read, int timeout)
 {
        struct completion trans_done;
-       u8 dir;
-       int err = 0, i, count;
+       int err = 0, count;
        long timeleft;
        unsigned long flags;
-       struct scatterlist *sg;
-       enum dma_data_direction dma_dir;
-       u32 val;
-       dma_addr_t addr;
-       unsigned int len;
-
-       dev_dbg(&(pcr->pci->dev), "--> %s: num_sg = %d\n", __func__, num_sg);
-
-       /* don't transfer data during abort processing */
-       if (pcr->remove_pci)
-               return -EINVAL;
-
-       if ((sglist == NULL) || (num_sg <= 0))
-               return -EINVAL;
 
-       if (read) {
-               dir = DEVICE_TO_HOST;
-               dma_dir = DMA_FROM_DEVICE;
-       } else {
-               dir = HOST_TO_DEVICE;
-               dma_dir = DMA_TO_DEVICE;
-       }
-
-       count = dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir);
+       count = rtsx_pci_dma_map_sg(pcr, sglist, num_sg, read);
        if (count < 1) {
                dev_err(&(pcr->pci->dev), "scatterlist map failed\n");
                return -EINVAL;
        }
        dev_dbg(&(pcr->pci->dev), "DMA mapping count: %d\n", count);
 
-       val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE;
-       pcr->sgi = 0;
-       for_each_sg(sglist, sg, count, i) {
-               addr = sg_dma_address(sg);
-               len = sg_dma_len(sg);
-               rtsx_pci_add_sg_tbl(pcr, addr, len, i == count - 1);
-       }
 
        spin_lock_irqsave(&pcr->lock, flags);
 
        pcr->done = &trans_done;
        pcr->trans_result = TRANS_NOT_READY;
        init_completion(&trans_done);
-       rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr);
-       rtsx_pci_writel(pcr, RTSX_HDBCTLR, val);
 
        spin_unlock_irqrestore(&pcr->lock, flags);
 
+       rtsx_pci_dma_transfer(pcr, sglist, count, read);
+
        timeleft = wait_for_completion_interruptible_timeout(
                        &trans_done, msecs_to_jiffies(timeout));
        if (timeleft <= 0) {
@@ -413,7 +383,7 @@ out:
        pcr->done = NULL;
        spin_unlock_irqrestore(&pcr->lock, flags);
 
-       dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir);
+       rtsx_pci_dma_unmap_sg(pcr, sglist, num_sg, read);
 
        if ((err < 0) && (err != -ENODEV))
                rtsx_pci_stop_cmd(pcr);
@@ -425,6 +395,73 @@ out:
 }
 EXPORT_SYMBOL_GPL(rtsx_pci_transfer_data);
 
+int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+               int num_sg, bool read)
+{
+       enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+       if (pcr->remove_pci)
+               return -EINVAL;
+
+       if ((sglist == NULL) || num_sg < 1)
+               return -EINVAL;
+
+       return dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dir);
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_dma_map_sg);
+
+int rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+               int num_sg, bool read)
+{
+       enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+       if (pcr->remove_pci)
+               return -EINVAL;
+
+       if (sglist == NULL || num_sg < 1)
+               return -EINVAL;
+
+       dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dir);
+       return num_sg;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_dma_unmap_sg);
+
+int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+               int sg_count, bool read)
+{
+       struct scatterlist *sg;
+       dma_addr_t addr;
+       unsigned int len;
+       int i;
+       u32 val;
+       u8 dir = read ? DEVICE_TO_HOST : HOST_TO_DEVICE;
+       unsigned long flags;
+
+       if (pcr->remove_pci)
+               return -EINVAL;
+
+       if ((sglist == NULL) || (sg_count < 1))
+               return -EINVAL;
+
+       val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE;
+       pcr->sgi = 0;
+       for_each_sg(sglist, sg, sg_count, i) {
+               addr = sg_dma_address(sg);
+               len = sg_dma_len(sg);
+               rtsx_pci_add_sg_tbl(pcr, addr, len, i == sg_count - 1);
+       }
+
+       spin_lock_irqsave(&pcr->lock, flags);
+
+       rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr);
+       rtsx_pci_writel(pcr, RTSX_HDBCTLR, val);
+
+       spin_unlock_irqrestore(&pcr->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_dma_transfer);
+
 int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len)
 {
        int err;
@@ -836,6 +873,8 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
        int_reg = rtsx_pci_readl(pcr, RTSX_BIPR);
        /* Clear interrupt flag */
        rtsx_pci_writel(pcr, RTSX_BIPR, int_reg);
+       dev_dbg(&pcr->pci->dev, "=========== BIPR 0x%8x ==========\n", int_reg);
+
        if ((int_reg & pcr->bier) == 0) {
                spin_unlock(&pcr->lock);
                return IRQ_NONE;
@@ -866,17 +905,28 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
        }
 
        if (int_reg & (NEED_COMPLETE_INT | DELINK_INT)) {
-               if (int_reg & (TRANS_FAIL_INT | DELINK_INT)) {
+               if (int_reg & (TRANS_FAIL_INT | DELINK_INT))
                        pcr->trans_result = TRANS_RESULT_FAIL;
-                       if (pcr->done)
-                               complete(pcr->done);
-               } else if (int_reg & TRANS_OK_INT) {
+               else if (int_reg & TRANS_OK_INT)
                        pcr->trans_result = TRANS_RESULT_OK;
-                       if (pcr->done)
-                               complete(pcr->done);
+
+               if (pcr->done)
+                       complete(pcr->done);
+
+               if (int_reg & SD_EXIST) {
+                       struct rtsx_slot *slot = &pcr->slots[RTSX_SD_CARD];
+                       if (slot && slot->done_transfer)
+                               slot->done_transfer(slot->p_dev);
+               }
+
+               if (int_reg & MS_EXIST) {
+                       struct rtsx_slot *slot = &pcr->slots[RTSX_SD_CARD];
+                       if (slot && slot->done_transfer)
+                               slot->done_transfer(slot->p_dev);
                }
        }
 
+
        if (pcr->card_inserted || pcr->card_removed)
                schedule_delayed_work(&pcr->carddet_work,
                                msecs_to_jiffies(200));
index 7b5424f398ace049d0a6c4be9724a191c7ad4f54..452782bffebcfd5977a2935155cbe2b1e143f302 100644 (file)
@@ -415,8 +415,7 @@ static int ioctl_do_sanitize(struct mmc_card *card)
 {
        int err;
 
-       if (!(mmc_can_sanitize(card) &&
-             (card->host->caps2 & MMC_CAP2_SANITIZE))) {
+       if (!mmc_can_sanitize(card)) {
                        pr_warn("%s: %s - SANITIZE is not supported\n",
                                mmc_hostname(card->host), __func__);
                        err = -EOPNOTSUPP;
@@ -722,19 +721,6 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
        return result;
 }
 
-static int send_stop(struct mmc_card *card, u32 *status)
-{
-       struct mmc_command cmd = {0};
-       int err;
-
-       cmd.opcode = MMC_STOP_TRANSMISSION;
-       cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-       err = mmc_wait_for_cmd(card->host, &cmd, 5);
-       if (err == 0)
-               *status = cmd.resp[0];
-       return err;
-}
-
 static int get_card_status(struct mmc_card *card, u32 *status, int retries)
 {
        struct mmc_command cmd = {0};
@@ -750,6 +736,99 @@ static int get_card_status(struct mmc_card *card, u32 *status, int retries)
        return err;
 }
 
+static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms,
+               bool hw_busy_detect, struct request *req, int *gen_err)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
+       int err = 0;
+       u32 status;
+
+       do {
+               err = get_card_status(card, &status, 5);
+               if (err) {
+                       pr_err("%s: error %d requesting status\n",
+                              req->rq_disk->disk_name, err);
+                       return err;
+               }
+
+               if (status & R1_ERROR) {
+                       pr_err("%s: %s: error sending status cmd, status %#x\n",
+                               req->rq_disk->disk_name, __func__, status);
+                       *gen_err = 1;
+               }
+
+               /* We may rely on the host hw to handle busy detection.*/
+               if ((card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) &&
+                       hw_busy_detect)
+                       break;
+
+               /*
+                * Timeout if the device never becomes ready for data and never
+                * leaves the program state.
+                */
+               if (time_after(jiffies, timeout)) {
+                       pr_err("%s: Card stuck in programming state! %s %s\n",
+                               mmc_hostname(card->host),
+                               req->rq_disk->disk_name, __func__);
+                       return -ETIMEDOUT;
+               }
+
+               /*
+                * Some cards mishandle the status bits,
+                * so make sure to check both the busy
+                * indication and the card state.
+                */
+       } while (!(status & R1_READY_FOR_DATA) ||
+                (R1_CURRENT_STATE(status) == R1_STATE_PRG));
+
+       return err;
+}
+
+static int send_stop(struct mmc_card *card, unsigned int timeout_ms,
+               struct request *req, int *gen_err, u32 *stop_status)
+{
+       struct mmc_host *host = card->host;
+       struct mmc_command cmd = {0};
+       int err;
+       bool use_r1b_resp = rq_data_dir(req) == WRITE;
+
+       /*
+        * Normally we use R1B responses for WRITE, but in cases where the host
+        * has specified a max_busy_timeout we need to validate it. A failure
+        * means we need to prevent the host from doing hw busy detection, which
+        * is done by converting to a R1 response instead.
+        */
+       if (host->max_busy_timeout && (timeout_ms > host->max_busy_timeout))
+               use_r1b_resp = false;
+
+       cmd.opcode = MMC_STOP_TRANSMISSION;
+       if (use_r1b_resp) {
+               cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+               cmd.busy_timeout = timeout_ms;
+       } else {
+               cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+       }
+
+       err = mmc_wait_for_cmd(host, &cmd, 5);
+       if (err)
+               return err;
+
+       *stop_status = cmd.resp[0];
+
+       /* No need to check card status in case of READ. */
+       if (rq_data_dir(req) == READ)
+               return 0;
+
+       if (!mmc_host_is_spi(host) &&
+               (*stop_status & R1_ERROR)) {
+               pr_err("%s: %s: general error sending stop command, resp %#x\n",
+                       req->rq_disk->disk_name, __func__, *stop_status);
+               *gen_err = 1;
+       }
+
+       return card_busy_detect(card, timeout_ms, use_r1b_resp, req, gen_err);
+}
+
 #define ERR_NOMEDIUM   3
 #define ERR_RETRY      2
 #define ERR_ABORT      1
@@ -866,26 +945,21 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
         */
        if (R1_CURRENT_STATE(status) == R1_STATE_DATA ||
            R1_CURRENT_STATE(status) == R1_STATE_RCV) {
-               err = send_stop(card, &stop_status);
-               if (err)
+               err = send_stop(card,
+                       DIV_ROUND_UP(brq->data.timeout_ns, 1000000),
+                       req, gen_err, &stop_status);
+               if (err) {
                        pr_err("%s: error %d sending stop command\n",
                               req->rq_disk->disk_name, err);
-
-               /*
-                * If the stop cmd also timed out, the card is probably
-                * not present, so abort.  Other errors are bad news too.
-                */
-               if (err)
+                       /*
+                        * If the stop cmd also timed out, the card is probably
+                        * not present, so abort. Other errors are bad news too.
+                        */
                        return ERR_ABORT;
+               }
+
                if (stop_status & R1_CARD_ECC_FAILED)
                        *ecc_err = 1;
-               if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ)
-                       if (stop_status & R1_ERROR) {
-                               pr_err("%s: %s: general error sending stop command, stop cmd response %#x\n",
-                                      req->rq_disk->disk_name, __func__,
-                                      stop_status);
-                               *gen_err = 1;
-                       }
        }
 
        /* Check for set block count errors */
@@ -1157,8 +1231,7 @@ static int mmc_blk_err_check(struct mmc_card *card,
         * program mode, which we have to wait for it to complete.
         */
        if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
-               u32 status;
-               unsigned long timeout;
+               int err;
 
                /* Check stop command response */
                if (brq->stop.resp[0] & R1_ERROR) {
@@ -1168,39 +1241,10 @@ static int mmc_blk_err_check(struct mmc_card *card,
                        gen_err = 1;
                }
 
-               timeout = jiffies + msecs_to_jiffies(MMC_BLK_TIMEOUT_MS);
-               do {
-                       int err = get_card_status(card, &status, 5);
-                       if (err) {
-                               pr_err("%s: error %d requesting status\n",
-                                      req->rq_disk->disk_name, err);
-                               return MMC_BLK_CMD_ERR;
-                       }
-
-                       if (status & R1_ERROR) {
-                               pr_err("%s: %s: general error sending status command, card status %#x\n",
-                                      req->rq_disk->disk_name, __func__,
-                                      status);
-                               gen_err = 1;
-                       }
-
-                       /* Timeout if the device never becomes ready for data
-                        * and never leaves the program state.
-                        */
-                       if (time_after(jiffies, timeout)) {
-                               pr_err("%s: Card stuck in programming state!"\
-                                       " %s %s\n", mmc_hostname(card->host),
-                                       req->rq_disk->disk_name, __func__);
-
-                               return MMC_BLK_CMD_ERR;
-                       }
-                       /*
-                        * Some cards mishandle the status bits,
-                        * so make sure to check both the busy
-                        * indication and the card state.
-                        */
-               } while (!(status & R1_READY_FOR_DATA) ||
-                        (R1_CURRENT_STATE(status) == R1_STATE_PRG));
+               err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, false, req,
+                                       &gen_err);
+               if (err)
+                       return MMC_BLK_CMD_ERR;
        }
 
        /* if general error occurs, retry the write operation. */
@@ -1335,7 +1379,6 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
        brq->data.blksz = 512;
        brq->stop.opcode = MMC_STOP_TRANSMISSION;
        brq->stop.arg = 0;
-       brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
        brq->data.blocks = blk_rq_sectors(req);
 
        /*
@@ -1378,9 +1421,15 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
        if (rq_data_dir(req) == READ) {
                brq->cmd.opcode = readcmd;
                brq->data.flags |= MMC_DATA_READ;
+               if (brq->mrq.stop)
+                       brq->stop.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 |
+                                       MMC_CMD_AC;
        } else {
                brq->cmd.opcode = writecmd;
                brq->data.flags |= MMC_DATA_WRITE;
+               if (brq->mrq.stop)
+                       brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B |
+                                       MMC_CMD_AC;
        }
 
        if (do_rel_wr)
index 269d072ef55eabc239a4f1ef55980a89918d2186..9ebee72d9c3fd9cd42996f446cea6408e7b6e7c0 100644 (file)
@@ -2,21 +2,6 @@
 # MMC core configuration
 #
 
-config MMC_UNSAFE_RESUME
-       bool "Assume MMC/SD cards are non-removable (DANGEROUS)"
-       help
-         If you say Y here, the MMC layer will assume that all cards
-         stayed in their respective slots during the suspend. The
-         normal behaviour is to remove them at suspend and
-         redetecting them at resume. Breaking this assumption will
-         in most cases result in data corruption.
-
-         This option is usually just for embedded systems which use
-         a MMC/SD card for rootfs. Most people should say N here.
-
-         This option sets a default which can be overridden by the
-         module parameter "removable=0" or "removable=1".
-
 config MMC_CLKGATE
        bool "MMC host clock gating"
        help
index 64145a32b917b37ce862e392fe3600417c99c336..824644875d41691fe6dc099c53e4770f1cbea23e 100644 (file)
@@ -185,24 +185,16 @@ static int mmc_runtime_suspend(struct device *dev)
 {
        struct mmc_card *card = mmc_dev_to_card(dev);
        struct mmc_host *host = card->host;
-       int ret = 0;
 
-       if (host->bus_ops->runtime_suspend)
-               ret = host->bus_ops->runtime_suspend(host);
-
-       return ret;
+       return host->bus_ops->runtime_suspend(host);
 }
 
 static int mmc_runtime_resume(struct device *dev)
 {
        struct mmc_card *card = mmc_dev_to_card(dev);
        struct mmc_host *host = card->host;
-       int ret = 0;
 
-       if (host->bus_ops->runtime_resume)
-               ret = host->bus_ops->runtime_resume(host);
-
-       return ret;
+       return host->bus_ops->runtime_resume(host);
 }
 
 static int mmc_runtime_idle(struct device *dev)
index 098374b1ab2b99cb769d7ddf6a2a9d0a2a7672cb..acbc3f2aaaf9e3adff743de7081e1e6508b6b03c 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/sd.h>
+#include <linux/mmc/slot-gpio.h>
 
 #include "core.h"
 #include "bus.h"
@@ -64,23 +65,6 @@ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
 bool use_spi_crc = 1;
 module_param(use_spi_crc, bool, 0);
 
-/*
- * We normally treat cards as removed during suspend if they are not
- * known to be on a non-removable bus, to avoid the risk of writing
- * back data to a different card after resume.  Allow this to be
- * overridden if necessary.
- */
-#ifdef CONFIG_MMC_UNSAFE_RESUME
-bool mmc_assume_removable;
-#else
-bool mmc_assume_removable = 1;
-#endif
-EXPORT_SYMBOL(mmc_assume_removable);
-module_param_named(removable, mmc_assume_removable, bool, 0644);
-MODULE_PARM_DESC(
-       removable,
-       "MMC/SD cards are removable and may be removed during suspend");
-
 /*
  * Internal function. Schedule delayed work in the MMC work queue.
  */
@@ -302,7 +286,8 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
        }
 
        err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                       EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal, true);
+                       EXT_CSD_BKOPS_START, 1, timeout,
+                       use_busy_signal, true, false);
        if (err) {
                pr_warn("%s: Error %d starting bkops\n",
                        mmc_hostname(card->host), err);
@@ -1950,7 +1935,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
        cmd.opcode = MMC_ERASE;
        cmd.arg = arg;
        cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-       cmd.cmd_timeout_ms = mmc_erase_timeout(card, arg, qty);
+       cmd.busy_timeout = mmc_erase_timeout(card, arg, qty);
        err = mmc_wait_for_cmd(card->host, &cmd, 0);
        if (err) {
                pr_err("mmc_erase: erase error %d, status %#x\n",
@@ -2137,7 +2122,7 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
                y = 0;
                for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) {
                        timeout = mmc_erase_timeout(card, arg, qty + x);
-                       if (timeout > host->max_discard_to)
+                       if (timeout > host->max_busy_timeout)
                                break;
                        if (timeout < last_timeout)
                                break;
@@ -2169,7 +2154,7 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
        struct mmc_host *host = card->host;
        unsigned int max_discard, max_trim;
 
-       if (!host->max_discard_to)
+       if (!host->max_busy_timeout)
                return UINT_MAX;
 
        /*
@@ -2189,7 +2174,7 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
                max_discard = 0;
        }
        pr_debug("%s: calculated max. discard sectors %u for timeout %u ms\n",
-                mmc_hostname(host), max_discard, host->max_discard_to);
+                mmc_hostname(host), max_discard, host->max_busy_timeout);
        return max_discard;
 }
 EXPORT_SYMBOL(mmc_calc_max_discard);
@@ -2248,9 +2233,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
 {
        struct mmc_card *card = host->card;
 
-       if (!host->bus_ops->power_restore)
-               return -EOPNOTSUPP;
-
        if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
                return -EOPNOTSUPP;
 
@@ -2352,7 +2334,7 @@ int _mmc_detect_card_removed(struct mmc_host *host)
 {
        int ret;
 
-       if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive)
+       if (host->caps & MMC_CAP_NONREMOVABLE)
                return 0;
 
        if (!host->card || mmc_card_removed(host->card))
@@ -2435,7 +2417,7 @@ void mmc_rescan(struct work_struct *work)
         * if there is a _removable_ card registered, check whether it is
         * still present
         */
-       if (host->bus_ops && host->bus_ops->detect && !host->bus_dead
+       if (host->bus_ops && !host->bus_dead
            && !(host->caps & MMC_CAP_NONREMOVABLE))
                host->bus_ops->detect(host);
 
@@ -2490,6 +2472,7 @@ void mmc_start_host(struct mmc_host *host)
                mmc_power_off(host);
        else
                mmc_power_up(host, host->ocr_avail);
+       mmc_gpiod_request_cd_irq(host);
        _mmc_detect_change(host, 0, false);
 }
 
@@ -2501,6 +2484,8 @@ void mmc_stop_host(struct mmc_host *host)
        host->removed = 1;
        spin_unlock_irqrestore(&host->lock, flags);
 #endif
+       if (host->slot.cd_irq >= 0)
+               disable_irq(host->slot.cd_irq);
 
        host->rescan_disable = 1;
        cancel_delayed_work_sync(&host->detect);
@@ -2537,7 +2522,7 @@ int mmc_power_save_host(struct mmc_host *host)
 
        mmc_bus_get(host);
 
-       if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
+       if (!host->bus_ops || host->bus_dead) {
                mmc_bus_put(host);
                return -EINVAL;
        }
@@ -2563,7 +2548,7 @@ int mmc_power_restore_host(struct mmc_host *host)
 
        mmc_bus_get(host);
 
-       if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
+       if (!host->bus_ops || host->bus_dead) {
                mmc_bus_put(host);
                return -EINVAL;
        }
@@ -2582,12 +2567,8 @@ EXPORT_SYMBOL(mmc_power_restore_host);
  */
 int mmc_flush_cache(struct mmc_card *card)
 {
-       struct mmc_host *host = card->host;
        int err = 0;
 
-       if (!(host->caps2 & MMC_CAP2_CACHE_CTRL))
-               return err;
-
        if (mmc_card_mmc(card) &&
                        (card->ext_csd.cache_size > 0) &&
                        (card->ext_csd.cache_ctrl & 1)) {
@@ -2602,44 +2583,6 @@ int mmc_flush_cache(struct mmc_card *card)
 }
 EXPORT_SYMBOL(mmc_flush_cache);
 
-/*
- * Turn the cache ON/OFF.
- * Turning the cache OFF shall trigger flushing of the data
- * to the non-volatile storage.
- * This function should be called with host claimed
- */
-int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
-{
-       struct mmc_card *card = host->card;
-       unsigned int timeout;
-       int err = 0;
-
-       if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) ||
-                       mmc_card_is_removable(host))
-               return err;
-
-       if (card && mmc_card_mmc(card) &&
-                       (card->ext_csd.cache_size > 0)) {
-               enable = !!enable;
-
-               if (card->ext_csd.cache_ctrl ^ enable) {
-                       timeout = enable ? card->ext_csd.generic_cmd6_time : 0;
-                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                                       EXT_CSD_CACHE_CTRL, enable, timeout);
-                       if (err)
-                               pr_err("%s: cache %s error %d\n",
-                                               mmc_hostname(card->host),
-                                               enable ? "on" : "off",
-                                               err);
-                       else
-                               card->ext_csd.cache_ctrl = enable;
-               }
-       }
-
-       return err;
-}
-EXPORT_SYMBOL(mmc_cache_ctrl);
-
 #ifdef CONFIG_PM
 
 /* Do the card removal on suspend if card is assumed removeable
@@ -2668,7 +2611,7 @@ int mmc_pm_notify(struct notifier_block *notify_block,
                /* Validate prerequisites for suspend */
                if (host->bus_ops->pre_suspend)
                        err = host->bus_ops->pre_suspend(host);
-               if (!err && host->bus_ops->suspend)
+               if (!err)
                        break;
 
                /* Calling bus_ops->remove() with a claimed host can deadlock */
index 114f6bdfbef3c5dac060d3ccb046fb9fbb1f872d..fdea825dbb240238b66531214b7761bda4b698eb 100644 (file)
@@ -419,6 +419,16 @@ int mmc_of_parse(struct mmc_host *host)
                host->caps |= MMC_CAP_SD_HIGHSPEED;
        if (of_find_property(np, "cap-mmc-highspeed", &len))
                host->caps |= MMC_CAP_MMC_HIGHSPEED;
+       if (of_find_property(np, "sd-uhs-sdr12", &len))
+               host->caps |= MMC_CAP_UHS_SDR12;
+       if (of_find_property(np, "sd-uhs-sdr25", &len))
+               host->caps |= MMC_CAP_UHS_SDR25;
+       if (of_find_property(np, "sd-uhs-sdr50", &len))
+               host->caps |= MMC_CAP_UHS_SDR50;
+       if (of_find_property(np, "sd-uhs-sdr104", &len))
+               host->caps |= MMC_CAP_UHS_SDR104;
+       if (of_find_property(np, "sd-uhs-ddr50", &len))
+               host->caps |= MMC_CAP_UHS_DDR50;
        if (of_find_property(np, "cap-power-off-card", &len))
                host->caps |= MMC_CAP_POWER_OFF_CARD;
        if (of_find_property(np, "cap-sdio-irq", &len))
@@ -429,6 +439,14 @@ int mmc_of_parse(struct mmc_host *host)
                host->pm_caps |= MMC_PM_KEEP_POWER;
        if (of_find_property(np, "enable-sdio-wakeup", &len))
                host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
+       if (of_find_property(np, "mmc-ddr-1_8v", &len))
+               host->caps |= MMC_CAP_1_8V_DDR;
+       if (of_find_property(np, "mmc-ddr-1_2v", &len))
+               host->caps |= MMC_CAP_1_2V_DDR;
+       if (of_find_property(np, "mmc-hs200-1_8v", &len))
+               host->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
+       if (of_find_property(np, "mmc-hs200-1_2v", &len))
+               host->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
 
        return 0;
 
index 98e9eb0f6643149f6b589cb1319b2a0a0905ee1d..1ab5f3a0af5b734a1829e732fe91b5bef8f24d2b 100644 (file)
@@ -856,8 +856,10 @@ static int mmc_select_hs200(struct mmc_card *card)
 
        /* switch to HS200 mode if bus width set successfully */
        if (!err)
-               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                                EXT_CSD_HS_TIMING, 2, 0);
+               err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                               EXT_CSD_HS_TIMING, 2,
+                               card->ext_csd.generic_cmd6_time,
+                               true, true, true);
 err:
        return err;
 }
@@ -1074,9 +1076,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                    host->caps2 & MMC_CAP2_HS200)
                        err = mmc_select_hs200(card);
                else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
-                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                                        EXT_CSD_HS_TIMING, 1,
-                                        card->ext_csd.generic_cmd6_time);
+                       err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                       EXT_CSD_HS_TIMING, 1,
+                                       card->ext_csd.generic_cmd6_time,
+                                       true, true, true);
 
                if (err && err != -EBADMSG)
                        goto free_card;
@@ -1287,8 +1290,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
         * If cache size is higher than 0, this indicates
         * the existence of cache and it can be turned on.
         */
-       if ((host->caps2 & MMC_CAP2_CACHE_CTRL) &&
-                       card->ext_csd.cache_size > 0) {
+       if (card->ext_csd.cache_size > 0) {
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                                EXT_CSD_CACHE_CTRL, 1,
                                card->ext_csd.generic_cmd6_time);
@@ -1356,11 +1358,9 @@ static int mmc_sleep(struct mmc_host *host)
 {
        struct mmc_command cmd = {0};
        struct mmc_card *card = host->card;
+       unsigned int timeout_ms = DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000);
        int err;
 
-       if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
-               return 0;
-
        err = mmc_deselect_cards(host);
        if (err)
                return err;
@@ -1369,7 +1369,19 @@ static int mmc_sleep(struct mmc_host *host)
        cmd.arg = card->rca << 16;
        cmd.arg |= 1 << 15;
 
-       cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+       /*
+        * If the max_busy_timeout of the host is specified, validate it against
+        * the sleep cmd timeout. A failure means we need to prevent the host
+        * from doing hw busy detection, which is done by converting to a R1
+        * response instead of a R1B.
+        */
+       if (host->max_busy_timeout && (timeout_ms > host->max_busy_timeout)) {
+               cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+       } else {
+               cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+               cmd.busy_timeout = timeout_ms;
+       }
+
        err = mmc_wait_for_cmd(host, &cmd, 0);
        if (err)
                return err;
@@ -1380,8 +1392,8 @@ static int mmc_sleep(struct mmc_host *host)
         * SEND_STATUS command to poll the status because that command (and most
         * others) is invalid while the card sleeps.
         */
-       if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
-               mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000));
+       if (!cmd.busy_timeout || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
+               mmc_delay(timeout_ms);
 
        return err;
 }
@@ -1404,7 +1416,7 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
 
        err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                        EXT_CSD_POWER_OFF_NOTIFICATION,
-                       notify_type, timeout, true, false);
+                       notify_type, timeout, true, false, false);
        if (err)
                pr_err("%s: Power Off Notification timed out, %u\n",
                       mmc_hostname(card->host), timeout);
@@ -1484,7 +1496,7 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
                        goto out;
        }
 
-       err = mmc_cache_ctrl(host, 0);
+       err = mmc_flush_cache(host->card);
        if (err)
                goto out;
 
@@ -1634,16 +1646,6 @@ static int mmc_power_restore(struct mmc_host *host)
 }
 
 static const struct mmc_bus_ops mmc_ops = {
-       .remove = mmc_remove,
-       .detect = mmc_detect,
-       .suspend = NULL,
-       .resume = NULL,
-       .power_restore = mmc_power_restore,
-       .alive = mmc_alive,
-       .shutdown = mmc_shutdown,
-};
-
-static const struct mmc_bus_ops mmc_ops_unsafe = {
        .remove = mmc_remove,
        .detect = mmc_detect,
        .suspend = mmc_suspend,
@@ -1655,17 +1657,6 @@ static const struct mmc_bus_ops mmc_ops_unsafe = {
        .shutdown = mmc_shutdown,
 };
 
-static void mmc_attach_bus_ops(struct mmc_host *host)
-{
-       const struct mmc_bus_ops *bus_ops;
-
-       if (!mmc_card_is_removable(host))
-               bus_ops = &mmc_ops_unsafe;
-       else
-               bus_ops = &mmc_ops;
-       mmc_attach_bus(host, bus_ops);
-}
-
 /*
  * Starting point for MMC card init.
  */
@@ -1685,7 +1676,7 @@ int mmc_attach_mmc(struct mmc_host *host)
        if (err)
                return err;
 
-       mmc_attach_bus_ops(host);
+       mmc_attach_bus(host, &mmc_ops);
        if (host->ocr_avail_mmc)
                host->ocr_avail = host->ocr_avail_mmc;
 
index e5b5eeb548d17eb08e1f374a83024dc5e4a1170b..f51b5ba3bbea99ce1f2b74e5b3c80a4b882b972c 100644 (file)
@@ -405,20 +405,30 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
  *                   timeout of zero implies maximum possible timeout
  *     @use_busy_signal: use the busy signal as response type
  *     @send_status: send status cmd to poll for busy
+ *     @ignore_crc: ignore CRC errors when sending status cmd to poll for busy
  *
  *     Modifies the EXT_CSD register for selected card.
  */
 int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
-               unsigned int timeout_ms, bool use_busy_signal, bool send_status)
+               unsigned int timeout_ms, bool use_busy_signal, bool send_status,
+               bool ignore_crc)
 {
+       struct mmc_host *host = card->host;
        int err;
        struct mmc_command cmd = {0};
        unsigned long timeout;
        u32 status = 0;
-       bool ignore_crc = false;
+       bool use_r1b_resp = use_busy_signal;
 
-       BUG_ON(!card);
-       BUG_ON(!card->host);
+       /*
+        * If the cmd timeout and the max_busy_timeout of the host are both
+        * specified, let's validate them. A failure means we need to prevent
+        * the host from doing hw busy detection, which is done by converting
+        * to a R1 response instead of a R1B.
+        */
+       if (timeout_ms && host->max_busy_timeout &&
+               (timeout_ms > host->max_busy_timeout))
+               use_r1b_resp = false;
 
        cmd.opcode = MMC_SWITCH;
        cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
@@ -426,17 +436,21 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                  (value << 8) |
                  set;
        cmd.flags = MMC_CMD_AC;
-       if (use_busy_signal)
+       if (use_r1b_resp) {
                cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
-       else
+               /*
+                * A busy_timeout of zero means the host can decide to use
+                * whatever value it finds suitable.
+                */
+               cmd.busy_timeout = timeout_ms;
+       } else {
                cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
+       }
 
-
-       cmd.cmd_timeout_ms = timeout_ms;
        if (index == EXT_CSD_SANITIZE_START)
                cmd.sanitize_busy = true;
 
-       err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
+       err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
        if (err)
                return err;
 
@@ -445,24 +459,27 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                return 0;
 
        /*
-        * Must check status to be sure of no errors
-        * If CMD13 is to check the busy completion of the timing change,
-        * disable the check of CRC error.
+        * CRC errors shall only be ignored in cases were CMD13 is used to poll
+        * to detect busy completion.
         */
-       if (index == EXT_CSD_HS_TIMING &&
-           !(card->host->caps & MMC_CAP_WAIT_WHILE_BUSY))
-               ignore_crc = true;
+       if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
+               ignore_crc = false;
+
+       /* We have an unspecified cmd timeout, use the fallback value. */
+       if (!timeout_ms)
+               timeout_ms = MMC_OPS_TIMEOUT_MS;
 
-       timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);
+       /* Must check status to be sure of no errors. */
+       timeout = jiffies + msecs_to_jiffies(timeout_ms);
        do {
                if (send_status) {
                        err = __mmc_send_status(card, &status, ignore_crc);
                        if (err)
                                return err;
                }
-               if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
+               if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
                        break;
-               if (mmc_host_is_spi(card->host))
+               if (mmc_host_is_spi(host))
                        break;
 
                /*
@@ -478,18 +495,18 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                /* Timeout if the device never leaves the program state. */
                if (time_after(jiffies, timeout)) {
                        pr_err("%s: Card stuck in programming state! %s\n",
-                               mmc_hostname(card->host), __func__);
+                               mmc_hostname(host), __func__);
                        return -ETIMEDOUT;
                }
        } while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
 
-       if (mmc_host_is_spi(card->host)) {
+       if (mmc_host_is_spi(host)) {
                if (status & R1_SPI_ILLEGAL_COMMAND)
                        return -EBADMSG;
        } else {
                if (status & 0xFDFFA000)
-                       pr_warning("%s: unexpected status %#x after "
-                              "switch", mmc_hostname(card->host), status);
+                       pr_warn("%s: unexpected status %#x after switch\n",
+                               mmc_hostname(host), status);
                if (status & R1_SWITCH_ERROR)
                        return -EBADMSG;
        }
@@ -501,7 +518,8 @@ EXPORT_SYMBOL_GPL(__mmc_switch);
 int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                unsigned int timeout_ms)
 {
-       return __mmc_switch(card, set, index, value, timeout_ms, true, true);
+       return __mmc_switch(card, set, index, value, timeout_ms, true, true,
+                               false);
 }
 EXPORT_SYMBOL_GPL(mmc_switch);
 
index 692fdb177294c242f3df6c9e1313df0584f100b3..2dd359d2242fa811efae1a03d02ca9d9dfba77ca 100644 (file)
@@ -1207,16 +1207,6 @@ static int mmc_sd_power_restore(struct mmc_host *host)
 }
 
 static const struct mmc_bus_ops mmc_sd_ops = {
-       .remove = mmc_sd_remove,
-       .detect = mmc_sd_detect,
-       .suspend = NULL,
-       .resume = NULL,
-       .power_restore = mmc_sd_power_restore,
-       .alive = mmc_sd_alive,
-       .shutdown = mmc_sd_suspend,
-};
-
-static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
        .remove = mmc_sd_remove,
        .detect = mmc_sd_detect,
        .runtime_suspend = mmc_sd_runtime_suspend,
@@ -1228,17 +1218,6 @@ static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
        .shutdown = mmc_sd_suspend,
 };
 
-static void mmc_sd_attach_bus_ops(struct mmc_host *host)
-{
-       const struct mmc_bus_ops *bus_ops;
-
-       if (!mmc_card_is_removable(host))
-               bus_ops = &mmc_sd_ops_unsafe;
-       else
-               bus_ops = &mmc_sd_ops;
-       mmc_attach_bus(host, bus_ops);
-}
-
 /*
  * Starting point for SD card init.
  */
@@ -1254,7 +1233,7 @@ int mmc_attach_sd(struct mmc_host *host)
        if (err)
                return err;
 
-       mmc_sd_attach_bus_ops(host);
+       mmc_attach_bus(host, &mmc_sd_ops);
        if (host->ocr_avail_sd)
                host->ocr_avail = host->ocr_avail_sd;
 
index 46596b71a32f49d5934c62d3f5323b26cf6c1658..f7650b899e3d426fbce08e8b636784adf0d0cdf0 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/err.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
 #include <linux/mmc/host.h>
 #include <linux/slab.h>
 
 struct mmc_gpio {
-       int ro_gpio;
-       int cd_gpio;
+       struct gpio_desc *ro_gpio;
+       struct gpio_desc *cd_gpio;
+       bool override_ro_active_level;
+       bool override_cd_active_level;
        char *ro_label;
        char cd_label[0];
 };
@@ -57,8 +60,6 @@ static int mmc_gpio_alloc(struct mmc_host *host)
                        ctx->ro_label = ctx->cd_label + len;
                        snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
                        snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent));
-                       ctx->cd_gpio = -EINVAL;
-                       ctx->ro_gpio = -EINVAL;
                        host->slot.handler_priv = ctx;
                }
        }
@@ -72,11 +73,14 @@ int mmc_gpio_get_ro(struct mmc_host *host)
 {
        struct mmc_gpio *ctx = host->slot.handler_priv;
 
-       if (!ctx || !gpio_is_valid(ctx->ro_gpio))
+       if (!ctx || !ctx->ro_gpio)
                return -ENOSYS;
 
-       return !gpio_get_value_cansleep(ctx->ro_gpio) ^
-               !!(host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH);
+       if (ctx->override_ro_active_level)
+               return !gpiod_get_raw_value_cansleep(ctx->ro_gpio) ^
+                       !!(host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH);
+
+       return gpiod_get_value_cansleep(ctx->ro_gpio);
 }
 EXPORT_SYMBOL(mmc_gpio_get_ro);
 
@@ -84,11 +88,14 @@ int mmc_gpio_get_cd(struct mmc_host *host)
 {
        struct mmc_gpio *ctx = host->slot.handler_priv;
 
-       if (!ctx || !gpio_is_valid(ctx->cd_gpio))
+       if (!ctx || !ctx->cd_gpio)
                return -ENOSYS;
 
-       return !gpio_get_value_cansleep(ctx->cd_gpio) ^
-               !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH);
+       if (ctx->override_cd_active_level)
+               return !gpiod_get_raw_value_cansleep(ctx->cd_gpio) ^
+                       !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH);
+
+       return gpiod_get_value_cansleep(ctx->cd_gpio);
 }
 EXPORT_SYMBOL(mmc_gpio_get_cd);
 
@@ -125,12 +132,47 @@ int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio)
        if (ret < 0)
                return ret;
 
-       ctx->ro_gpio = gpio;
+       ctx->override_ro_active_level = true;
+       ctx->ro_gpio = gpio_to_desc(gpio);
 
        return 0;
 }
 EXPORT_SYMBOL(mmc_gpio_request_ro);
 
+void mmc_gpiod_request_cd_irq(struct mmc_host *host)
+{
+       struct mmc_gpio *ctx = host->slot.handler_priv;
+       int ret, irq;
+
+       if (host->slot.cd_irq >= 0 || !ctx || !ctx->cd_gpio)
+               return;
+
+       irq = gpiod_to_irq(ctx->cd_gpio);
+
+       /*
+        * Even if gpiod_to_irq() returns a valid IRQ number, the platform might
+        * still prefer to poll, e.g., because that IRQ number is already used
+        * by another unit and cannot be shared.
+        */
+       if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL)
+               irq = -EINVAL;
+
+       if (irq >= 0) {
+               ret = devm_request_threaded_irq(&host->class_dev, irq,
+                       NULL, mmc_gpio_cd_irqt,
+                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                       ctx->cd_label, host);
+               if (ret < 0)
+                       irq = ret;
+       }
+
+       host->slot.cd_irq = irq;
+
+       if (irq < 0)
+               host->caps |= MMC_CAP_NEEDS_POLL;
+}
+EXPORT_SYMBOL(mmc_gpiod_request_cd_irq);
+
 /**
  * mmc_gpio_request_cd - request a gpio for card-detection
  * @host: mmc host
@@ -154,7 +196,6 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio,
                        unsigned int debounce)
 {
        struct mmc_gpio *ctx;
-       int irq = gpio_to_irq(gpio);
        int ret;
 
        ret = mmc_gpio_alloc(host);
@@ -179,29 +220,10 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio,
                        return ret;
        }
 
-       /*
-        * Even if gpio_to_irq() returns a valid IRQ number, the platform might
-        * still prefer to poll, e.g., because that IRQ number is already used
-        * by another unit and cannot be shared.
-        */
-       if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL)
-               irq = -EINVAL;
-
-       if (irq >= 0) {
-               ret = devm_request_threaded_irq(&host->class_dev, irq,
-                       NULL, mmc_gpio_cd_irqt,
-                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-                       ctx->cd_label, host);
-               if (ret < 0)
-                       irq = ret;
-       }
-
-       host->slot.cd_irq = irq;
-
-       if (irq < 0)
-               host->caps |= MMC_CAP_NEEDS_POLL;
+       ctx->override_cd_active_level = true;
+       ctx->cd_gpio = gpio_to_desc(gpio);
 
-       ctx->cd_gpio = gpio;
+       mmc_gpiod_request_cd_irq(host);
 
        return 0;
 }
@@ -219,11 +241,11 @@ void mmc_gpio_free_ro(struct mmc_host *host)
        struct mmc_gpio *ctx = host->slot.handler_priv;
        int gpio;
 
-       if (!ctx || !gpio_is_valid(ctx->ro_gpio))
+       if (!ctx || !ctx->ro_gpio)
                return;
 
-       gpio = ctx->ro_gpio;
-       ctx->ro_gpio = -EINVAL;
+       gpio = desc_to_gpio(ctx->ro_gpio);
+       ctx->ro_gpio = NULL;
 
        devm_gpio_free(&host->class_dev, gpio);
 }
@@ -241,7 +263,7 @@ void mmc_gpio_free_cd(struct mmc_host *host)
        struct mmc_gpio *ctx = host->slot.handler_priv;
        int gpio;
 
-       if (!ctx || !gpio_is_valid(ctx->cd_gpio))
+       if (!ctx || !ctx->cd_gpio)
                return;
 
        if (host->slot.cd_irq >= 0) {
@@ -249,9 +271,87 @@ void mmc_gpio_free_cd(struct mmc_host *host)
                host->slot.cd_irq = -EINVAL;
        }
 
-       gpio = ctx->cd_gpio;
-       ctx->cd_gpio = -EINVAL;
+       gpio = desc_to_gpio(ctx->cd_gpio);
+       ctx->cd_gpio = NULL;
 
        devm_gpio_free(&host->class_dev, gpio);
 }
 EXPORT_SYMBOL(mmc_gpio_free_cd);
+
+/**
+ * mmc_gpiod_request_cd - request a gpio descriptor for card-detection
+ * @host: mmc host
+ * @con_id: function within the GPIO consumer
+ * @idx: index of the GPIO to obtain in the consumer
+ * @override_active_level: ignore %GPIO_ACTIVE_LOW flag
+ * @debounce: debounce time in microseconds
+ *
+ * Use this function in place of mmc_gpio_request_cd() to use the GPIO
+ * descriptor API.  Note that it is paired with mmc_gpiod_free_cd() not
+ * mmc_gpio_free_cd().  Note also that it must be called prior to mmc_add_host()
+ * otherwise the caller must also call mmc_gpiod_request_cd_irq().
+ *
+ * Returns zero on success, else an error.
+ */
+int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
+                        unsigned int idx, bool override_active_level,
+                        unsigned int debounce)
+{
+       struct mmc_gpio *ctx;
+       struct gpio_desc *desc;
+       int ret;
+
+       ret = mmc_gpio_alloc(host);
+       if (ret < 0)
+               return ret;
+
+       ctx = host->slot.handler_priv;
+
+       if (!con_id)
+               con_id = ctx->cd_label;
+
+       desc = devm_gpiod_get_index(host->parent, con_id, idx);
+       if (IS_ERR(desc))
+               return PTR_ERR(desc);
+
+       ret = gpiod_direction_input(desc);
+       if (ret < 0)
+               return ret;
+
+       if (debounce) {
+               ret = gpiod_set_debounce(desc, debounce);
+               if (ret < 0)
+                       return ret;
+       }
+
+       ctx->override_cd_active_level = override_active_level;
+       ctx->cd_gpio = desc;
+
+       return 0;
+}
+EXPORT_SYMBOL(mmc_gpiod_request_cd);
+
+/**
+ * mmc_gpiod_free_cd - free the card-detection gpio descriptor
+ * @host: mmc host
+ *
+ * It's provided only for cases that client drivers need to manually free
+ * up the card-detection gpio requested by mmc_gpiod_request_cd().
+ */
+void mmc_gpiod_free_cd(struct mmc_host *host)
+{
+       struct mmc_gpio *ctx = host->slot.handler_priv;
+
+       if (!ctx || !ctx->cd_gpio)
+               return;
+
+       if (host->slot.cd_irq >= 0) {
+               devm_free_irq(&host->class_dev, host->slot.cd_irq, host);
+               host->slot.cd_irq = -EINVAL;
+       }
+
+       devm_gpiod_put(&host->class_dev, ctx->cd_gpio);
+
+       ctx->cd_gpio = NULL;
+}
+EXPORT_SYMBOL(mmc_gpiod_free_cd);
index 1384f67abe2190ffdb52264f73924b1ec9c3d0e2..8aaf8c1f3f63a398003237828eef9bef8b753e81 100644 (file)
@@ -263,7 +263,7 @@ config MMC_SDHCI_S3C_DMA
 
 config MMC_SDHCI_BCM_KONA
        tristate "SDHCI support on Broadcom KONA platform"
-       depends on ARCH_BCM
+       depends on ARCH_BCM_MOBILE
        select MMC_SDHCI_PLTFM
        help
          This selects the Broadcom Kona Secure Digital Host Controller
@@ -334,6 +334,19 @@ config MMC_ATMELMCI
 
          If unsure, say N.
 
+config MMC_SDHCI_MSM
+       tristate "Qualcomm SDHCI Controller Support"
+       depends on ARCH_QCOM
+       depends on MMC_SDHCI_PLTFM
+       help
+         This selects the Secure Digital Host Controller Interface (SDHCI)
+         support present in Qualcomm SOCs. The controller supports
+         SD/MMC/SDIO devices.
+
+         If you have a controller with this interface, say Y or M here.
+
+         If unsure, say N.
+
 config MMC_MSM
        tristate "Qualcomm SDCC Controller Support"
        depends on MMC && (ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50)
@@ -580,14 +593,6 @@ config MMC_DW_EXYNOS
          Synopsys DesignWare Memory Card Interface driver. Select this option
          for platforms based on Exynos4 and Exynos5 SoC's.
 
-config MMC_DW_SOCFPGA
-       tristate "SOCFPGA specific extensions for Synopsys DW Memory Card Interface"
-       depends on MMC_DW && MFD_SYSCON
-       select MMC_DW_PLTFM
-       help
-         This selects support for Altera SoCFPGA specific extensions to the
-         Synopsys DesignWare Memory Card Interface driver.
-
 config MMC_DW_K3
        tristate "K3 specific extensions for Synopsys DW Memory Card Interface"
        depends on MMC_DW
index 3483b6b6b880a592cfc564a2dd70c66e762760fe..0c8aa5e1e304b55270613d2cb288448502467ff2 100644 (file)
@@ -43,7 +43,6 @@ obj-$(CONFIG_SDH_BFIN)                += bfin_sdh.o
 obj-$(CONFIG_MMC_DW)           += dw_mmc.o
 obj-$(CONFIG_MMC_DW_PLTFM)     += dw_mmc-pltfm.o
 obj-$(CONFIG_MMC_DW_EXYNOS)    += dw_mmc-exynos.o
-obj-$(CONFIG_MMC_DW_SOCFPGA)   += dw_mmc-socfpga.o
 obj-$(CONFIG_MMC_DW_K3)                += dw_mmc-k3.o
 obj-$(CONFIG_MMC_DW_PCI)       += dw_mmc-pci.o
 obj-$(CONFIG_MMC_SH_MMCIF)     += sh_mmcif.o
@@ -64,6 +63,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_ESDHC)      += sdhci-of-esdhc.o
 obj-$(CONFIG_MMC_SDHCI_OF_HLWD)                += sdhci-of-hlwd.o
 obj-$(CONFIG_MMC_SDHCI_BCM_KONA)       += sdhci-bcm-kona.o
 obj-$(CONFIG_MMC_SDHCI_BCM2835)                += sdhci-bcm2835.o
+obj-$(CONFIG_MMC_SDHCI_MSM)            += sdhci-msm.o
 
 ifeq ($(CONFIG_CB710_DEBUG),y)
        CFLAGS-cb710-mmc        += -DDEBUG
index d6153740b77fa174060679a4fe3d31d18e619eb9..5d4c5e0fba2f8d43706a909a1e404467c063de68 100644 (file)
@@ -1192,7 +1192,7 @@ static struct davinci_mmc_config
        struct device_node *np;
        struct davinci_mmc_config *pdata = pdev->dev.platform_data;
        const struct of_device_id *match =
-               of_match_device(of_match_ptr(davinci_mmc_dt_ids), &pdev->dev);
+               of_match_device(davinci_mmc_dt_ids, &pdev->dev);
        u32 data;
 
        np = pdev->dev.of_node;
@@ -1468,7 +1468,7 @@ static struct platform_driver davinci_mmcsd_driver = {
                .name   = "davinci_mmc",
                .owner  = THIS_MODULE,
                .pm     = davinci_mmcsd_pm_ops,
-               .of_match_table = of_match_ptr(davinci_mmc_dt_ids),
+               .of_match_table = davinci_mmc_dt_ids,
        },
        .remove         = __exit_p(davinci_mmcsd_remove),
        .id_table       = davinci_mmc_devtype,
index f567c219cff46110d634a4b56bc971ff26211d06..650f9cc3f7a6b4bddd98e9c755cdf043835791d8 100644 (file)
@@ -50,6 +50,7 @@ static int dw_mci_k3_probe(struct platform_device *pdev)
        return dw_mci_pltfm_register(pdev, drv_data);
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int dw_mci_k3_suspend(struct device *dev)
 {
        struct dw_mci *host = dev_get_drvdata(dev);
@@ -75,6 +76,7 @@ static int dw_mci_k3_resume(struct device *dev)
 
        return dw_mci_resume(host);
 }
+#endif /* CONFIG_PM_SLEEP */
 
 static SIMPLE_DEV_PM_OPS(dw_mci_k3_pmops, dw_mci_k3_suspend, dw_mci_k3_resume);
 
index 5c496565529796f06ca4d26b280724376aa6348c..d4a47a9f55848cbc40f383c3378a9c20304667d6 100644 (file)
 #include "dw_mmc.h"
 #include "dw_mmc-pltfm.h"
 
-static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
+static void dw_mci_pltfm_prepare_command(struct dw_mci *host, u32 *cmdr)
 {
        *cmdr |= SDMMC_CMD_USE_HOLD_REG;
 }
 
 static const struct dw_mci_drv_data rockchip_drv_data = {
-       .prepare_command        = dw_mci_rockchip_prepare_command,
+       .prepare_command        = dw_mci_pltfm_prepare_command,
+};
+
+static const struct dw_mci_drv_data socfpga_drv_data = {
+       .prepare_command        = dw_mci_pltfm_prepare_command,
 };
 
 int dw_mci_pltfm_register(struct platform_device *pdev,
@@ -92,6 +96,8 @@ static const struct of_device_id dw_mci_pltfm_match[] = {
        { .compatible = "snps,dw-mshc", },
        { .compatible = "rockchip,rk2928-dw-mshc",
                .data = &rockchip_drv_data },
+       { .compatible = "altr,socfpga-dw-mshc",
+               .data = &socfpga_drv_data },
        {},
 };
 MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
@@ -123,7 +129,7 @@ static struct platform_driver dw_mci_pltfm_driver = {
        .remove         = dw_mci_pltfm_remove,
        .driver         = {
                .name           = "dw_mmc",
-               .of_match_table = of_match_ptr(dw_mci_pltfm_match),
+               .of_match_table = dw_mci_pltfm_match,
                .pm             = &dw_mci_pltfm_pmops,
        },
 };
diff --git a/drivers/mmc/host/dw_mmc-socfpga.c b/drivers/mmc/host/dw_mmc-socfpga.c
deleted file mode 100644 (file)
index 3e8e53a..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Altera SoCFPGA Specific Extensions for Synopsys DW Multimedia Card Interface
- * driver
- *
- *  Copyright (C) 2012, Samsung Electronics Co., Ltd.
- *  Copyright (C) 2013 Altera Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * Taken from dw_mmc-exynos.c
- */
-#include <linux/clk.h>
-#include <linux/mfd/syscon.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/dw_mmc.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/regmap.h>
-
-#include "dw_mmc.h"
-#include "dw_mmc-pltfm.h"
-
-#define SYSMGR_SDMMCGRP_CTRL_OFFSET            0x108
-#define DRV_CLK_PHASE_SHIFT_SEL_MASK   0x7
-#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel)          \
-       ((((smplsel) & 0x7) << 3) | (((drvsel) & 0x7) << 0))
-
-/* SOCFPGA implementation specific driver private data */
-struct dw_mci_socfpga_priv_data {
-       u8      ciu_div; /* card interface unit divisor */
-       u32     hs_timing; /* bitmask for CIU clock phase shift */
-       struct regmap   *sysreg; /* regmap for system manager register */
-};
-
-static int dw_mci_socfpga_priv_init(struct dw_mci *host)
-{
-       return 0;
-}
-
-static int dw_mci_socfpga_setup_clock(struct dw_mci *host)
-{
-       struct dw_mci_socfpga_priv_data *priv = host->priv;
-
-       clk_disable_unprepare(host->ciu_clk);
-       regmap_write(priv->sysreg, SYSMGR_SDMMCGRP_CTRL_OFFSET,
-               priv->hs_timing);
-       clk_prepare_enable(host->ciu_clk);
-
-       host->bus_hz /= (priv->ciu_div + 1);
-       return 0;
-}
-
-static void dw_mci_socfpga_prepare_command(struct dw_mci *host, u32 *cmdr)
-{
-       struct dw_mci_socfpga_priv_data *priv = host->priv;
-
-       if (priv->hs_timing & DRV_CLK_PHASE_SHIFT_SEL_MASK)
-               *cmdr |= SDMMC_CMD_USE_HOLD_REG;
-}
-
-static int dw_mci_socfpga_parse_dt(struct dw_mci *host)
-{
-       struct dw_mci_socfpga_priv_data *priv;
-       struct device_node *np = host->dev->of_node;
-       u32 timing[2];
-       u32 div = 0;
-       int ret;
-
-       priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv) {
-               dev_err(host->dev, "mem alloc failed for private data\n");
-               return -ENOMEM;
-       }
-
-       priv->sysreg = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
-       if (IS_ERR(priv->sysreg)) {
-               dev_err(host->dev, "regmap for altr,sys-mgr lookup failed.\n");
-               return PTR_ERR(priv->sysreg);
-       }
-
-       ret = of_property_read_u32(np, "altr,dw-mshc-ciu-div", &div);
-       if (ret)
-               dev_info(host->dev, "No dw-mshc-ciu-div specified, assuming 1");
-       priv->ciu_div = div;
-
-       ret = of_property_read_u32_array(np,
-                       "altr,dw-mshc-sdr-timing", timing, 2);
-       if (ret)
-               return ret;
-
-       priv->hs_timing = SYSMGR_SDMMC_CTRL_SET(timing[0], timing[1]);
-       host->priv = priv;
-       return 0;
-}
-
-static const struct dw_mci_drv_data socfpga_drv_data = {
-       .init                   = dw_mci_socfpga_priv_init,
-       .setup_clock            = dw_mci_socfpga_setup_clock,
-       .prepare_command        = dw_mci_socfpga_prepare_command,
-       .parse_dt               = dw_mci_socfpga_parse_dt,
-};
-
-static const struct of_device_id dw_mci_socfpga_match[] = {
-       { .compatible = "altr,socfpga-dw-mshc",
-                       .data = &socfpga_drv_data, },
-       {},
-};
-MODULE_DEVICE_TABLE(of, dw_mci_socfpga_match);
-
-static int dw_mci_socfpga_probe(struct platform_device *pdev)
-{
-       const struct dw_mci_drv_data *drv_data;
-       const struct of_device_id *match;
-
-       match = of_match_node(dw_mci_socfpga_match, pdev->dev.of_node);
-       drv_data = match->data;
-       return dw_mci_pltfm_register(pdev, drv_data);
-}
-
-static struct platform_driver dw_mci_socfpga_pltfm_driver = {
-       .probe          = dw_mci_socfpga_probe,
-       .remove         = __exit_p(dw_mci_pltfm_remove),
-       .driver         = {
-               .name           = "dwmmc_socfpga",
-               .of_match_table = dw_mci_socfpga_match,
-               .pm             = &dw_mci_pltfm_pmops,
-       },
-};
-
-module_platform_driver(dw_mci_socfpga_pltfm_driver);
-
-MODULE_DESCRIPTION("Altera SOCFPGA Specific DW-MSHC Driver Extension");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:dwmmc-socfpga");
index c204b7d1532c0f1c910b25a7435d3f12c8435732..cced599d5aebe22aef357fd427a6aa03d7edaa79 100644 (file)
@@ -1345,7 +1345,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
 
                        if (!err) {
                                if (!data->stop || mrq->sbc) {
-                                       if (mrq->sbc)
+                                       if (mrq->sbc && data->stop)
                                                data->stop->error = 0;
                                        dw_mci_request_end(host, mrq);
                                        goto unlock;
index 6bf24ab917e6453a22d09689befd58e40fa96efd..68349779c39614cd397723c86f810651b8e93754 100644 (file)
 
 extern int dw_mci_probe(struct dw_mci *host);
 extern void dw_mci_remove(struct dw_mci *host);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 extern int dw_mci_suspend(struct dw_mci *host);
 extern int dw_mci_resume(struct dw_mci *host);
 #endif
@@ -244,6 +244,7 @@ struct dw_mci_tuning_data {
  * @prepare_command: handle CMD register extensions.
  * @set_ios: handle bus specific extensions.
  * @parse_dt: parse implementation specific device tree properties.
+ * @execute_tuning: implementation specific tuning procedure.
  *
  * Provide controller implementation specific extensions. The usage of this
  * data structure is fully optional and usage of each member in this structure
index b931226365317b6b64ed2462c1beeb25b7857d16..771c60ab4a320a3edc222b108c49d14a8e0076b1 100644 (file)
@@ -921,6 +921,29 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
 {
        void __iomem *base = host->base;
        bool sbc = (cmd == host->mrq->sbc);
+       bool busy_resp = host->variant->busy_detect &&
+                       (cmd->flags & MMC_RSP_BUSY);
+
+       /* Check if we need to wait for busy completion. */
+       if (host->busy_status && (status & MCI_ST_CARDBUSY))
+               return;
+
+       /* Enable busy completion if needed and supported. */
+       if (!host->busy_status && busy_resp &&
+               !(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) &&
+               (readl(base + MMCISTATUS) & MCI_ST_CARDBUSY)) {
+               writel(readl(base + MMCIMASK0) | MCI_ST_BUSYEND,
+                       base + MMCIMASK0);
+               host->busy_status = status & (MCI_CMDSENT|MCI_CMDRESPEND);
+               return;
+       }
+
+       /* At busy completion, mask the IRQ and complete the request. */
+       if (host->busy_status) {
+               writel(readl(base + MMCIMASK0) & ~MCI_ST_BUSYEND,
+                       base + MMCIMASK0);
+               host->busy_status = 0;
+       }
 
        host->cmd = NULL;
 
@@ -1139,20 +1162,30 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
                        status &= ~MCI_IRQ1MASK;
                }
 
+               /*
+                * We intentionally clear the MCI_ST_CARDBUSY IRQ here (if it's
+                * enabled) since the HW seems to be triggering the IRQ on both
+                * edges while monitoring DAT0 for busy completion.
+                */
                status &= readl(host->base + MMCIMASK0);
                writel(status, host->base + MMCICLEAR);
 
                dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status);
 
+               cmd = host->cmd;
+               if ((status|host->busy_status) & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|
+                       MCI_CMDSENT|MCI_CMDRESPEND) && cmd)
+                       mmci_cmd_irq(host, cmd, status);
+
                data = host->data;
                if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR|
                              MCI_TXUNDERRUN|MCI_RXOVERRUN|MCI_DATAEND|
                              MCI_DATABLOCKEND) && data)
                        mmci_data_irq(host, data, status);
 
-               cmd = host->cmd;
-               if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd)
-                       mmci_cmd_irq(host, cmd, status);
+               /* Don't poll for busy completion in irq context. */
+               if (host->busy_status)
+                       status &= ~MCI_ST_CARDBUSY;
 
                ret = 1;
        } while (status);
@@ -1503,12 +1536,6 @@ static int mmci_probe(struct amba_device *dev,
                goto clk_disable;
        }
 
-       if (variant->busy_detect) {
-               mmci_ops.card_busy = mmci_card_busy;
-               mmci_write_datactrlreg(host, MCI_ST_DPSM_BUSYMODE);
-       }
-
-       mmc->ops = &mmci_ops;
        /*
         * The ARM and ST versions of the block have slightly different
         * clock divider equations which means that the minimum divider
@@ -1542,6 +1569,15 @@ static int mmci_probe(struct amba_device *dev,
        mmc->caps = plat->capabilities;
        mmc->caps2 = plat->capabilities2;
 
+       if (variant->busy_detect) {
+               mmci_ops.card_busy = mmci_card_busy;
+               mmci_write_datactrlreg(host, MCI_ST_DPSM_BUSYMODE);
+               mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
+               mmc->max_busy_timeout = 0;
+       }
+
+       mmc->ops = &mmci_ops;
+
        /* We support these PM capabilities. */
        mmc->pm_caps = MMC_PM_KEEP_POWER;
 
index 84c0e59b792acce9e0508fe038e05d204dd2b2d8..58b1b8896bf2d188f8c0b5f0f53856260a930e25 100644 (file)
 /* Extended status bits for the ST Micro variants */
 #define MCI_ST_SDIOITMASK      (1 << 22)
 #define MCI_ST_CEATAENDMASK    (1 << 23)
+#define MCI_ST_BUSYEND         (1 << 24)
 
 #define MMCIMASK1              0x040
 #define MMCIFIFOCNT            0x048
@@ -187,6 +188,7 @@ struct mmci_host {
        u32                     pwr_reg;
        u32                     clk_reg;
        u32                     datactrl_reg;
+       u32                     busy_status;
        bool                    vqmmc_enabled;
        struct mmci_platform_data *plat;
        struct variant_data     *variant;
index 98b6b6ef7e5c9d737a749e9a3ddf631f5d92c1c0..5c2e58b29305ce4cab01e34c2d3e17b842979334 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/omap-dma.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
 #include <linux/clk.h>
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
@@ -130,7 +131,6 @@ struct mmc_omap_host {
        u32                     dma_rx_burst;
        struct dma_chan         *dma_tx;
        u32                     dma_tx_burst;
-       struct resource         *mem_res;
        void __iomem            *virt_base;
        unsigned int            phys_base;
        int                     irq;
@@ -153,7 +153,6 @@ struct mmc_omap_host {
        u32                     total_bytes_left;
 
        unsigned                features;
-       unsigned                use_dma:1;
        unsigned                brs_received:1, dma_done:1;
        unsigned                dma_in_use:1;
        spinlock_t              dma_lock;
@@ -338,6 +337,7 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
        u32 cmdreg;
        u32 resptype;
        u32 cmdtype;
+       u16 irq_mask;
 
        host->cmd = cmd;
 
@@ -390,12 +390,14 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
        OMAP_MMC_WRITE(host, CTO, 200);
        OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff);
        OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16);
-       OMAP_MMC_WRITE(host, IE,
-                      OMAP_MMC_STAT_A_EMPTY    | OMAP_MMC_STAT_A_FULL    |
-                      OMAP_MMC_STAT_CMD_CRC    | OMAP_MMC_STAT_CMD_TOUT  |
-                      OMAP_MMC_STAT_DATA_CRC   | OMAP_MMC_STAT_DATA_TOUT |
-                      OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR  |
-                      OMAP_MMC_STAT_END_OF_DATA);
+       irq_mask = OMAP_MMC_STAT_A_EMPTY    | OMAP_MMC_STAT_A_FULL    |
+                  OMAP_MMC_STAT_CMD_CRC    | OMAP_MMC_STAT_CMD_TOUT  |
+                  OMAP_MMC_STAT_DATA_CRC   | OMAP_MMC_STAT_DATA_TOUT |
+                  OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR  |
+                  OMAP_MMC_STAT_END_OF_DATA;
+       if (cmd->opcode == MMC_ERASE)
+               irq_mask &= ~OMAP_MMC_STAT_DATA_TOUT;
+       OMAP_MMC_WRITE(host, IE, irq_mask);
        OMAP_MMC_WRITE(host, CMD, cmdreg);
 }
 
@@ -945,7 +947,7 @@ static void
 mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
 {
        struct mmc_data *data = req->data;
-       int i, use_dma, block_size;
+       int i, use_dma = 1, block_size;
        unsigned sg_len;
 
        host->data = data;
@@ -970,13 +972,10 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
        sg_len = (data->blocks == 1) ? 1 : data->sg_len;
 
        /* Only do DMA for entire blocks */
-       use_dma = host->use_dma;
-       if (use_dma) {
-               for (i = 0; i < sg_len; i++) {
-                       if ((data->sg[i].length % block_size) != 0) {
-                               use_dma = 0;
-                               break;
-                       }
+       for (i = 0; i < sg_len; i++) {
+               if ((data->sg[i].length % block_size) != 0) {
+                       use_dma = 0;
+                       break;
                }
        }
 
@@ -1239,7 +1238,7 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id)
 
        mmc->caps = 0;
        if (host->pdata->slots[id].wires >= 4)
-               mmc->caps |= MMC_CAP_4_BIT_DATA;
+               mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_ERASE;
 
        mmc->ops = &mmc_omap_ops;
        mmc->f_min = 400000;
@@ -1262,6 +1261,13 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id)
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
        mmc->max_seg_size = mmc->max_req_size;
 
+       if (slot->pdata->get_cover_state != NULL) {
+               setup_timer(&slot->cover_timer, mmc_omap_cover_timer,
+                           (unsigned long)slot);
+               tasklet_init(&slot->cover_tasklet, mmc_omap_cover_handler,
+                            (unsigned long)slot);
+       }
+
        r = mmc_add_host(mmc);
        if (r < 0)
                goto err_remove_host;
@@ -1278,11 +1284,6 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id)
                                        &dev_attr_cover_switch);
                if (r < 0)
                        goto err_remove_slot_name;
-
-               setup_timer(&slot->cover_timer, mmc_omap_cover_timer,
-                           (unsigned long)slot);
-               tasklet_init(&slot->cover_tasklet, mmc_omap_cover_handler,
-                            (unsigned long)slot);
                tasklet_schedule(&slot->cover_tasklet);
        }
 
@@ -1333,21 +1334,19 @@ static int mmc_omap_probe(struct platform_device *pdev)
                return -EPROBE_DEFER;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       host = devm_kzalloc(&pdev->dev, sizeof(struct mmc_omap_host),
+                           GFP_KERNEL);
+       if (host == NULL)
+               return -ENOMEM;
+
        irq = platform_get_irq(pdev, 0);
-       if (res == NULL || irq < 0)
+       if (irq < 0)
                return -ENXIO;
 
-       res = request_mem_region(res->start, resource_size(res),
-                                pdev->name);
-       if (res == NULL)
-               return -EBUSY;
-
-       host = kzalloc(sizeof(struct mmc_omap_host), GFP_KERNEL);
-       if (host == NULL) {
-               ret = -ENOMEM;
-               goto err_free_mem_region;
-       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       host->virt_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(host->virt_base))
+               return PTR_ERR(host->virt_base);
 
        INIT_WORK(&host->slot_release_work, mmc_omap_slot_release_work);
        INIT_WORK(&host->send_stop_work, mmc_omap_send_stop_work);
@@ -1369,20 +1368,11 @@ static int mmc_omap_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, host);
 
        host->id = pdev->id;
-       host->mem_res = res;
-       host->irq = irq;
-       host->use_dma = 1;
        host->irq = irq;
-       host->phys_base = host->mem_res->start;
-       host->virt_base = ioremap(res->start, resource_size(res));
-       if (!host->virt_base)
-               goto err_ioremap;
-
+       host->phys_base = res->start;
        host->iclk = clk_get(&pdev->dev, "ick");
-       if (IS_ERR(host->iclk)) {
-               ret = PTR_ERR(host->iclk);
-               goto err_free_mmc_host;
-       }
+       if (IS_ERR(host->iclk))
+               return PTR_ERR(host->iclk);
        clk_enable(host->iclk);
 
        host->fclk = clk_get(&pdev->dev, "fck");
@@ -1460,12 +1450,6 @@ err_free_dma:
 err_free_iclk:
        clk_disable(host->iclk);
        clk_put(host->iclk);
-err_free_mmc_host:
-       iounmap(host->virt_base);
-err_ioremap:
-       kfree(host);
-err_free_mem_region:
-       release_mem_region(res->start, resource_size(res));
        return ret;
 }
 
@@ -1493,13 +1477,8 @@ static int mmc_omap_remove(struct platform_device *pdev)
        if (host->dma_rx)
                dma_release_channel(host->dma_rx);
 
-       iounmap(host->virt_base);
-       release_mem_region(pdev->resource[0].start,
-                          pdev->resource[0].end - pdev->resource[0].start + 1);
        destroy_workqueue(host->mmc_omap_wq);
 
-       kfree(host);
-
        return 0;
 }
 
index dbd32ad3b749337a196c98915694b0c013685186..e91ee21549d03ad22c2bcf2287f61074cc3d889b 100644 (file)
@@ -45,6 +45,7 @@
 /* OMAP HSMMC Host Controller Registers */
 #define OMAP_HSMMC_SYSSTATUS   0x0014
 #define OMAP_HSMMC_CON         0x002C
+#define OMAP_HSMMC_SDMASA      0x0100
 #define OMAP_HSMMC_BLK         0x0104
 #define OMAP_HSMMC_ARG         0x0108
 #define OMAP_HSMMC_CMD         0x010C
@@ -58,6 +59,7 @@
 #define OMAP_HSMMC_STAT                0x0130
 #define OMAP_HSMMC_IE          0x0134
 #define OMAP_HSMMC_ISE         0x0138
+#define OMAP_HSMMC_AC12                0x013C
 #define OMAP_HSMMC_CAPA                0x0140
 
 #define VS18                   (1 << 26)
@@ -81,6 +83,7 @@
 #define DTO_MASK               0x000F0000
 #define DTO_SHIFT              16
 #define INIT_STREAM            (1 << 1)
+#define ACEN_ACMD23            (2 << 2)
 #define DP_SELECT              (1 << 21)
 #define DDIR                   (1 << 4)
 #define DMAE                   0x1
 #define SRC                    (1 << 25)
 #define SRD                    (1 << 26)
 #define SOFTRESET              (1 << 1)
-#define RESETDONE              (1 << 0)
 
 /* Interrupt masks for IE and ISE register */
 #define CC_EN                  (1 << 0)
 #define DTO_EN                 (1 << 20)
 #define DCRC_EN                        (1 << 21)
 #define DEB_EN                 (1 << 22)
+#define ACE_EN                 (1 << 24)
 #define CERR_EN                        (1 << 28)
 #define BADA_EN                        (1 << 29)
 
-#define INT_EN_MASK            (BADA_EN | CERR_EN | DEB_EN | DCRC_EN |\
+#define INT_EN_MASK (BADA_EN | CERR_EN | ACE_EN | DEB_EN | DCRC_EN |\
                DTO_EN | CIE_EN | CEB_EN | CCRC_EN | CTO_EN | \
                BRR_EN | BWR_EN | TC_EN | CC_EN)
 
+#define CNI    (1 << 7)
+#define ACIE   (1 << 4)
+#define ACEB   (1 << 3)
+#define ACCE   (1 << 2)
+#define ACTO   (1 << 1)
+#define ACNE   (1 << 0)
+
 #define MMC_AUTOSUSPEND_DELAY  100
 #define MMC_TIMEOUT_MS         20              /* 20 mSec */
 #define MMC_TIMEOUT_US         20000           /* 20000 micro Sec */
 #define OMAP_MMC_MAX_CLOCK     52000000
 #define DRIVER_NAME            "omap_hsmmc"
 
+#define VDD_1V8                        1800000         /* 180000 uV */
+#define VDD_3V0                        3000000         /* 300000 uV */
+#define VDD_165_195            (ffs(MMC_VDD_165_195) - 1)
+
+#define AUTO_CMD23             (1 << 1)        /* Auto CMD23 support */
 /*
  * One controller can have multiple slots, like on some omap boards using
  * omap.c controller driver. Luckily this is not currently done on any known
@@ -164,7 +179,8 @@ struct omap_hsmmc_host {
         */
        struct  regulator       *vcc;
        struct  regulator       *vcc_aux;
-       int                     pbias_disable;
+       struct  regulator       *pbias;
+       bool                    pbias_enabled;
        void    __iomem         *base;
        resource_size_t         mapbase;
        spinlock_t              irq_lock; /* Prevent races with irq handler */
@@ -188,10 +204,19 @@ struct omap_hsmmc_host {
        int                     reqs_blocked;
        int                     use_reg;
        int                     req_in_progress;
+       unsigned long           clk_rate;
+       unsigned int            flags;
        struct omap_hsmmc_next  next_data;
        struct  omap_mmc_platform_data  *pdata;
 };
 
+struct omap_mmc_of_data {
+       u32 reg_offset;
+       u8 controller_flags;
+};
+
+static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host);
+
 static int omap_hsmmc_card_detect(struct device *dev, int slot)
 {
        struct omap_hsmmc_host *host = dev_get_drvdata(dev);
@@ -261,17 +286,19 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
         */
        if (!host->vcc)
                return 0;
-       /*
-        * With DT, never turn OFF the regulator for MMC1. This is because
-        * the pbias cell programming support is still missing when
-        * booting with Device tree
-        */
-       if (host->pbias_disable && !vdd)
-               return 0;
 
        if (mmc_slot(host).before_set_reg)
                mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
 
+       if (host->pbias) {
+               if (host->pbias_enabled == 1) {
+                       ret = regulator_disable(host->pbias);
+                       if (!ret)
+                               host->pbias_enabled = 0;
+               }
+               regulator_set_voltage(host->pbias, VDD_3V0, VDD_3V0);
+       }
+
        /*
         * Assume Vcc regulator is used only to power the card ... OMAP
         * VDDS is used to power the pins, optionally with a transceiver to
@@ -286,11 +313,12 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
         * chips/cards need an interface voltage rail too.
         */
        if (power_on) {
-               ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
+               if (host->vcc)
+                       ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
                /* Enable interface voltage rail, if needed */
                if (ret == 0 && host->vcc_aux) {
                        ret = regulator_enable(host->vcc_aux);
-                       if (ret < 0)
+                       if (ret < 0 && host->vcc)
                                ret = mmc_regulator_set_ocr(host->mmc,
                                                        host->vcc, 0);
                }
@@ -298,16 +326,34 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
                /* Shut down the rail */
                if (host->vcc_aux)
                        ret = regulator_disable(host->vcc_aux);
-               if (!ret) {
+               if (host->vcc) {
                        /* Then proceed to shut down the local regulator */
                        ret = mmc_regulator_set_ocr(host->mmc,
                                                host->vcc, 0);
                }
        }
 
+       if (host->pbias) {
+               if (vdd <= VDD_165_195)
+                       ret = regulator_set_voltage(host->pbias, VDD_1V8,
+                                                               VDD_1V8);
+               else
+                       ret = regulator_set_voltage(host->pbias, VDD_3V0,
+                                                               VDD_3V0);
+               if (ret < 0)
+                       goto error_set_power;
+
+               if (host->pbias_enabled == 0) {
+                       ret = regulator_enable(host->pbias);
+                       if (!ret)
+                               host->pbias_enabled = 1;
+               }
+       }
+
        if (mmc_slot(host).after_set_reg)
                mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
 
+error_set_power:
        return ret;
 }
 
@@ -316,12 +362,12 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
        struct regulator *reg;
        int ocr_value = 0;
 
-       reg = regulator_get(host->dev, "vmmc");
+       reg = devm_regulator_get(host->dev, "vmmc");
        if (IS_ERR(reg)) {
-               dev_err(host->dev, "vmmc regulator missing\n");
+               dev_err(host->dev, "unable to get vmmc regulator %ld\n",
+                       PTR_ERR(reg));
                return PTR_ERR(reg);
        } else {
-               mmc_slot(host).set_power = omap_hsmmc_set_power;
                host->vcc = reg;
                ocr_value = mmc_regulator_get_ocrmask(reg);
                if (!mmc_slot(host).ocr_mask) {
@@ -334,31 +380,29 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
                                return -EINVAL;
                        }
                }
+       }
+       mmc_slot(host).set_power = omap_hsmmc_set_power;
 
-               /* Allow an aux regulator */
-               reg = regulator_get(host->dev, "vmmc_aux");
-               host->vcc_aux = IS_ERR(reg) ? NULL : reg;
+       /* Allow an aux regulator */
+       reg = devm_regulator_get_optional(host->dev, "vmmc_aux");
+       host->vcc_aux = IS_ERR(reg) ? NULL : reg;
 
-               /* For eMMC do not power off when not in sleep state */
-               if (mmc_slot(host).no_regulator_off_init)
-                       return 0;
-               /*
-               * UGLY HACK:  workaround regulator framework bugs.
-               * When the bootloader leaves a supply active, it's
-               * initialized with zero usecount ... and we can't
-               * disable it without first enabling it.  Until the
-               * framework is fixed, we need a workaround like this
-               * (which is safe for MMC, but not in general).
-               */
-               if (regulator_is_enabled(host->vcc) > 0 ||
-                   (host->vcc_aux && regulator_is_enabled(host->vcc_aux))) {
-                       int vdd = ffs(mmc_slot(host).ocr_mask) - 1;
+       reg = devm_regulator_get_optional(host->dev, "pbias");
+       host->pbias = IS_ERR(reg) ? NULL : reg;
 
-                       mmc_slot(host).set_power(host->dev, host->slot_id,
-                                                1, vdd);
-                       mmc_slot(host).set_power(host->dev, host->slot_id,
-                                                0, 0);
-               }
+       /* For eMMC do not power off when not in sleep state */
+       if (mmc_slot(host).no_regulator_off_init)
+               return 0;
+       /*
+        * To disable boot_on regulator, enable regulator
+        * to increase usecount and then disable it.
+        */
+       if ((host->vcc && regulator_is_enabled(host->vcc) > 0) ||
+           (host->vcc_aux && regulator_is_enabled(host->vcc_aux))) {
+               int vdd = ffs(mmc_slot(host).ocr_mask) - 1;
+
+               mmc_slot(host).set_power(host->dev, host->slot_id, 1, vdd);
+               mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
        }
 
        return 0;
@@ -366,8 +410,6 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
 
 static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
 {
-       regulator_put(host->vcc);
-       regulator_put(host->vcc_aux);
        mmc_slot(host).set_power = NULL;
 }
 
@@ -605,9 +647,6 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
        u32 hctl, capa;
        unsigned long timeout;
 
-       if (!OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE)
-               return 1;
-
        if (host->con == OMAP_HSMMC_READ(host->base, CON) &&
            host->hctl == OMAP_HSMMC_READ(host->base, HCTL) &&
            host->sysctl == OMAP_HSMMC_READ(host->base, SYSCTL) &&
@@ -787,6 +826,11 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
 
        cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22);
 
+       if ((host->flags & AUTO_CMD23) && mmc_op_multi(cmd->opcode) &&
+           host->mrq->sbc) {
+               cmdreg |= ACEN_ACMD23;
+               OMAP_HSMMC_WRITE(host->base, SDMASA, host->mrq->sbc->arg);
+       }
        if (data) {
                cmdreg |= DP_SELECT | MSBS | BCE;
                if (data->flags & MMC_DATA_READ)
@@ -864,11 +908,10 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
        else
                data->bytes_xfered = 0;
 
-       if (!data->stop) {
+       if (data->stop && (data->error || !host->mrq->sbc))
+               omap_hsmmc_start_command(host, data->stop, NULL);
+       else
                omap_hsmmc_request_done(host, data->mrq);
-               return;
-       }
-       omap_hsmmc_start_command(host, data->stop, NULL);
 }
 
 /*
@@ -879,6 +922,14 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
 {
        host->cmd = NULL;
 
+       if (host->mrq->sbc && (host->cmd == host->mrq->sbc) &&
+           !host->mrq->sbc->error && !(host->flags & AUTO_CMD23)) {
+               omap_hsmmc_start_dma_transfer(host);
+               omap_hsmmc_start_command(host, host->mrq->cmd,
+                                               host->mrq->data);
+               return;
+       }
+
        if (cmd->flags & MMC_RSP_PRESENT) {
                if (cmd->flags & MMC_RSP_136) {
                        /* response type 2 */
@@ -892,7 +943,7 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
                }
        }
        if ((host->data == NULL && !host->response_busy) || cmd->error)
-               omap_hsmmc_request_done(host, cmd->mrq);
+               omap_hsmmc_request_done(host, host->mrq);
 }
 
 /*
@@ -1015,6 +1066,7 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
 {
        struct mmc_data *data;
        int end_cmd = 0, end_trans = 0;
+       int error = 0;
 
        data = host->data;
        dev_vdbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
@@ -1029,6 +1081,20 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
                else if (status & (CCRC_EN | DCRC_EN))
                        hsmmc_command_incomplete(host, -EILSEQ, end_cmd);
 
+               if (status & ACE_EN) {
+                       u32 ac12;
+                       ac12 = OMAP_HSMMC_READ(host->base, AC12);
+                       if (!(ac12 & ACNE) && host->mrq->sbc) {
+                               end_cmd = 1;
+                               if (ac12 & ACTO)
+                                       error =  -ETIMEDOUT;
+                               else if (ac12 & (ACCE | ACEB | ACIE))
+                                       error = -EILSEQ;
+                               host->mrq->sbc->error = error;
+                               hsmmc_command_incomplete(host, error, end_cmd);
+                       }
+                       dev_dbg(mmc_dev(host->mmc), "AC12 err: 0x%x\n", ac12);
+               }
                if (host->data || host->response_busy) {
                        end_trans = !end_cmd;
                        host->response_busy = 0;
@@ -1236,8 +1302,7 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,
        }
 
        /* Check if next job is already prepared */
-       if (next ||
-           (!next && data->host_cookie != host->next_data.cookie)) {
+       if (next || data->host_cookie != host->next_data.cookie) {
                dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len,
                                     omap_hsmmc_get_dma_dir(host, data));
 
@@ -1262,7 +1327,7 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,
 /*
  * Routine to configure and start DMA for the MMC card
  */
-static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
+static int omap_hsmmc_setup_dma_transfer(struct omap_hsmmc_host *host,
                                        struct mmc_request *req)
 {
        struct dma_slave_config cfg;
@@ -1321,8 +1386,6 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
 
        host->dma_ch = 1;
 
-       dma_async_issue_pending(chan);
-
        return 0;
 }
 
@@ -1338,7 +1401,7 @@ static void set_data_timeout(struct omap_hsmmc_host *host,
        if (clkd == 0)
                clkd = 1;
 
-       cycle_ns = 1000000000 / (clk_get_rate(host->fclk) / clkd);
+       cycle_ns = 1000000000 / (host->clk_rate / clkd);
        timeout = timeout_ns / cycle_ns;
        timeout += timeout_clks;
        if (timeout) {
@@ -1363,6 +1426,21 @@ static void set_data_timeout(struct omap_hsmmc_host *host,
        OMAP_HSMMC_WRITE(host->base, SYSCTL, reg);
 }
 
+static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host)
+{
+       struct mmc_request *req = host->mrq;
+       struct dma_chan *chan;
+
+       if (!req->data)
+               return;
+       OMAP_HSMMC_WRITE(host->base, BLK, (req->data->blksz)
+                               | (req->data->blocks << 16));
+       set_data_timeout(host, req->data->timeout_ns,
+                               req->data->timeout_clks);
+       chan = omap_hsmmc_get_dma_chan(host, req->data);
+       dma_async_issue_pending(chan);
+}
+
 /*
  * Configure block length for MMC/SD cards and initiate the transfer.
  */
@@ -1383,12 +1461,8 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
                return 0;
        }
 
-       OMAP_HSMMC_WRITE(host->base, BLK, (req->data->blksz)
-                                       | (req->data->blocks << 16));
-       set_data_timeout(host, req->data->timeout_ns, req->data->timeout_clks);
-
        if (host->use_dma) {
-               ret = omap_hsmmc_start_dma_transfer(host, req);
+               ret = omap_hsmmc_setup_dma_transfer(host, req);
                if (ret != 0) {
                        dev_err(mmc_dev(host->mmc), "MMC start dma failure\n");
                        return ret;
@@ -1462,6 +1536,7 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
                host->reqs_blocked = 0;
        WARN_ON(host->mrq != NULL);
        host->mrq = req;
+       host->clk_rate = clk_get_rate(host->fclk);
        err = omap_hsmmc_prepare_data(host, req);
        if (err) {
                req->cmd->error = err;
@@ -1471,7 +1546,12 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
                mmc_request_done(mmc, req);
                return;
        }
+       if (req->sbc && !(host->flags & AUTO_CMD23)) {
+               omap_hsmmc_start_command(host, req->sbc, NULL);
+               return;
+       }
 
+       omap_hsmmc_start_dma_transfer(host);
        omap_hsmmc_start_command(host, req->cmd, req->data);
 }
 
@@ -1509,13 +1589,7 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                 * of external transceiver; but they all handle 1.8V.
                 */
                if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
-                       (ios->vdd == DUAL_VOLT_OCR_BIT) &&
-                       /*
-                        * With pbias cell programming missing, this
-                        * can't be allowed on MMC1 when booting with device
-                        * tree.
-                        */
-                       !host->pbias_disable) {
+                       (ios->vdd == DUAL_VOLT_OCR_BIT)) {
                                /*
                                 * The mmc_select_voltage fn of the core does
                                 * not seem to set the power_mode to
@@ -1678,18 +1752,29 @@ static void omap_hsmmc_debugfs(struct mmc_host *mmc)
 #endif
 
 #ifdef CONFIG_OF
-static u16 omap4_reg_offset = 0x100;
+static const struct omap_mmc_of_data omap3_pre_es3_mmc_of_data = {
+       /* See 35xx errata 2.1.1.128 in SPRZ278F */
+       .controller_flags = OMAP_HSMMC_BROKEN_MULTIBLOCK_READ,
+};
+
+static const struct omap_mmc_of_data omap4_mmc_of_data = {
+       .reg_offset = 0x100,
+};
 
 static const struct of_device_id omap_mmc_of_match[] = {
        {
                .compatible = "ti,omap2-hsmmc",
        },
+       {
+               .compatible = "ti,omap3-pre-es3-hsmmc",
+               .data = &omap3_pre_es3_mmc_of_data,
+       },
        {
                .compatible = "ti,omap3-hsmmc",
        },
        {
                .compatible = "ti,omap4-hsmmc",
-               .data = &omap4_reg_offset,
+               .data = &omap4_mmc_of_data,
        },
        {},
 };
@@ -1709,7 +1794,7 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
 
        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata)
-               return NULL; /* out of memory */
+               return ERR_PTR(-ENOMEM); /* out of memory */
 
        if (of_find_property(np, "ti,dual-volt", NULL))
                pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
@@ -1738,13 +1823,19 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
        if (of_find_property(np, "ti,needs-special-hs-handling", NULL))
                pdata->slots[0].features |= HSMMC_HAS_HSPE_SUPPORT;
 
+       if (of_find_property(np, "keep-power-in-suspend", NULL))
+               pdata->slots[0].pm_caps |= MMC_PM_KEEP_POWER;
+
+       if (of_find_property(np, "enable-sdio-wakeup", NULL))
+               pdata->slots[0].pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
+
        return pdata;
 }
 #else
 static inline struct omap_mmc_platform_data
                        *of_get_hsmmc_pdata(struct device *dev)
 {
-       return NULL;
+       return ERR_PTR(-EINVAL);
 }
 #endif
 
@@ -1759,6 +1850,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
        dma_cap_mask_t mask;
        unsigned tx_req, rx_req;
        struct pinctrl *pinctrl;
+       const struct omap_mmc_of_data *data;
 
        match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
        if (match) {
@@ -1768,8 +1860,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
                        return PTR_ERR(pdata);
 
                if (match->data) {
-                       const u16 *offsetp = match->data;
-                       pdata->reg_offset = *offsetp;
+                       data = match->data;
+                       pdata->reg_offset = data->reg_offset;
+                       pdata->controller_flags |= data->controller_flags;
                }
        }
 
@@ -1814,6 +1907,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
        host->base      = ioremap(host->mapbase, SZ_4K);
        host->power_mode = MMC_POWER_OFF;
        host->next_data.cookie = 1;
+       host->pbias_enabled = 0;
 
        platform_set_drvdata(pdev, host);
 
@@ -1847,10 +1941,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
 
        omap_hsmmc_context_save(host);
 
-       /* This can be removed once we support PBIAS with DT */
-       if (host->dev->of_node && res->start == 0x4809c000)
-               host->pbias_disable = 1;
-
        host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
        /*
         * MMC can still work without debounce clock.
index c46feda07d56883b1b6e50cbb46338d73c82bcca..5fb994f9a653570d75f2b3deb6aab32129d17503 100644 (file)
 #include <linux/mfd/rtsx_pci.h>
 #include <asm/unaligned.h>
 
-/* SD Tuning Data Structure
- * Record continuous timing phase path
- */
-struct timing_phase_path {
-       int start;
-       int end;
-       int mid;
-       int len;
+struct realtek_next {
+       unsigned int    sg_count;
+       s32             cookie;
 };
 
 struct realtek_pci_sdmmc {
@@ -46,9 +41,18 @@ struct realtek_pci_sdmmc {
        struct rtsx_pcr         *pcr;
        struct mmc_host         *mmc;
        struct mmc_request      *mrq;
-
-       struct mutex            host_mutex;
-
+       struct mmc_command      *cmd;
+       struct mmc_data         *data;
+
+       spinlock_t              lock;
+       struct timer_list       timer;
+       struct tasklet_struct   cmd_tasklet;
+       struct tasklet_struct   data_tasklet;
+       struct tasklet_struct   finish_tasklet;
+
+       u8                      rsp_type;
+       u8                      rsp_len;
+       int                     sg_count;
        u8                      ssc_depth;
        unsigned int            clock;
        bool                    vpclk;
@@ -58,8 +62,13 @@ struct realtek_pci_sdmmc {
        int                     power_state;
 #define SDMMC_POWER_ON         1
 #define SDMMC_POWER_OFF                0
+
+       struct realtek_next     next_data;
 };
 
+static int sd_start_multi_rw(struct realtek_pci_sdmmc *host,
+               struct mmc_request *mrq);
+
 static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host)
 {
        return &(host->pdev->dev);
@@ -96,6 +105,95 @@ static void sd_print_debug_regs(struct realtek_pci_sdmmc *host)
 #define sd_print_debug_regs(host)
 #endif /* DEBUG */
 
+static void sd_isr_done_transfer(struct platform_device *pdev)
+{
+       struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev);
+
+       spin_lock(&host->lock);
+       if (host->cmd)
+               tasklet_schedule(&host->cmd_tasklet);
+       if (host->data)
+               tasklet_schedule(&host->data_tasklet);
+       spin_unlock(&host->lock);
+}
+
+static void sd_request_timeout(unsigned long host_addr)
+{
+       struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       if (!host->mrq) {
+               dev_err(sdmmc_dev(host), "error: no request exist\n");
+               goto out;
+       }
+
+       if (host->cmd)
+               host->cmd->error = -ETIMEDOUT;
+       if (host->data)
+               host->data->error = -ETIMEDOUT;
+
+       dev_dbg(sdmmc_dev(host), "timeout for request\n");
+
+out:
+       tasklet_schedule(&host->finish_tasklet);
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void sd_finish_request(unsigned long host_addr)
+{
+       struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
+       struct rtsx_pcr *pcr = host->pcr;
+       struct mmc_request *mrq;
+       struct mmc_command *cmd;
+       struct mmc_data *data;
+       unsigned long flags;
+       bool any_error;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       del_timer(&host->timer);
+       mrq = host->mrq;
+       if (!mrq) {
+               dev_err(sdmmc_dev(host), "error: no request need finish\n");
+               goto out;
+       }
+
+       cmd = mrq->cmd;
+       data = mrq->data;
+
+       any_error = (mrq->sbc && mrq->sbc->error) ||
+               (mrq->stop && mrq->stop->error) ||
+               (cmd && cmd->error) || (data && data->error);
+
+       if (any_error) {
+               rtsx_pci_stop_cmd(pcr);
+               sd_clear_error(host);
+       }
+
+       if (data) {
+               if (any_error)
+                       data->bytes_xfered = 0;
+               else
+                       data->bytes_xfered = data->blocks * data->blksz;
+
+               if (!data->host_cookie)
+                       rtsx_pci_dma_unmap_sg(pcr, data->sg, data->sg_len,
+                                       data->flags & MMC_DATA_READ);
+
+       }
+
+       host->mrq = NULL;
+       host->cmd = NULL;
+       host->data = NULL;
+
+out:
+       spin_unlock_irqrestore(&host->lock, flags);
+       mutex_unlock(&pcr->pcr_mutex);
+       mmc_request_done(host->mmc, mrq);
+}
+
 static int sd_read_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt,
                u8 *buf, int buf_len, int timeout)
 {
@@ -213,8 +311,7 @@ static int sd_write_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt,
        return 0;
 }
 
-static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
-               struct mmc_command *cmd)
+static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
 {
        struct rtsx_pcr *pcr = host->pcr;
        u8 cmd_idx = (u8)cmd->opcode;
@@ -222,11 +319,14 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
        int err = 0;
        int timeout = 100;
        int i;
-       u8 *ptr;
-       int stat_idx = 0;
        u8 rsp_type;
        int rsp_len = 5;
-       bool clock_toggled = false;
+       unsigned long flags;
+
+       if (host->cmd)
+               dev_err(sdmmc_dev(host), "error: cmd already exist\n");
+
+       host->cmd = cmd;
 
        dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n",
                        __func__, cmd_idx, arg);
@@ -261,6 +361,8 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
                err = -EINVAL;
                goto out;
        }
+       host->rsp_type = rsp_type;
+       host->rsp_len = rsp_len;
 
        if (rsp_type == SD_RSP_TYPE_R1b)
                timeout = 3000;
@@ -270,8 +372,6 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
                                0xFF, SD_CLK_TOGGLE_EN);
                if (err < 0)
                        goto out;
-
-               clock_toggled = true;
        }
 
        rtsx_pci_init_cmd(pcr);
@@ -295,25 +395,60 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
                /* Read data from ping-pong buffer */
                for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++)
                        rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0);
-               stat_idx = 16;
        } else if (rsp_type != SD_RSP_TYPE_R0) {
                /* Read data from SD_CMDx registers */
                for (i = SD_CMD0; i <= SD_CMD4; i++)
                        rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0);
-               stat_idx = 5;
        }
 
        rtsx_pci_add_cmd(pcr, READ_REG_CMD, SD_STAT1, 0, 0);
 
-       err = rtsx_pci_send_cmd(pcr, timeout);
-       if (err < 0) {
-               sd_print_debug_regs(host);
-               sd_clear_error(host);
-               dev_dbg(sdmmc_dev(host),
-                       "rtsx_pci_send_cmd error (err = %d)\n", err);
+       mod_timer(&host->timer, jiffies + msecs_to_jiffies(timeout));
+
+       spin_lock_irqsave(&pcr->lock, flags);
+       pcr->trans_result = TRANS_NOT_READY;
+       rtsx_pci_send_cmd_no_wait(pcr);
+       spin_unlock_irqrestore(&pcr->lock, flags);
+
+       return;
+
+out:
+       cmd->error = err;
+       tasklet_schedule(&host->finish_tasklet);
+}
+
+static void sd_get_rsp(unsigned long host_addr)
+{
+       struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
+       struct rtsx_pcr *pcr = host->pcr;
+       struct mmc_command *cmd;
+       int i, err = 0, stat_idx;
+       u8 *ptr, rsp_type;
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       cmd = host->cmd;
+       host->cmd = NULL;
+
+       if (!cmd) {
+               dev_err(sdmmc_dev(host), "error: cmd not exist\n");
                goto out;
        }
 
+       spin_lock(&pcr->lock);
+       if (pcr->trans_result == TRANS_NO_DEVICE)
+               err = -ENODEV;
+       else if (pcr->trans_result != TRANS_RESULT_OK)
+               err = -EINVAL;
+       spin_unlock(&pcr->lock);
+
+       if (err < 0)
+               goto out;
+
+       rsp_type = host->rsp_type;
+       stat_idx = host->rsp_len;
+
        if (rsp_type == SD_RSP_TYPE_R0) {
                err = 0;
                goto out;
@@ -350,26 +485,106 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
                                cmd->resp[0]);
        }
 
+       if (cmd == host->mrq->sbc) {
+               sd_send_cmd(host, host->mrq->cmd);
+               spin_unlock_irqrestore(&host->lock, flags);
+               return;
+       }
+
+       if (cmd == host->mrq->stop)
+               goto out;
+
+       if (cmd->data) {
+               sd_start_multi_rw(host, host->mrq);
+               spin_unlock_irqrestore(&host->lock, flags);
+               return;
+       }
+
 out:
        cmd->error = err;
 
-       if (err && clock_toggled)
-               rtsx_pci_write_register(pcr, SD_BUS_STAT,
-                               SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
+       tasklet_schedule(&host->finish_tasklet);
+       spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq)
+static int sd_pre_dma_transfer(struct realtek_pci_sdmmc *host,
+                       struct mmc_data *data, struct realtek_next *next)
+{
+       struct rtsx_pcr *pcr = host->pcr;
+       int read = data->flags & MMC_DATA_READ;
+       int sg_count = 0;
+
+       if (!next && data->host_cookie &&
+               data->host_cookie != host->next_data.cookie) {
+               dev_err(sdmmc_dev(host),
+                       "error: invalid cookie data[%d] host[%d]\n",
+                       data->host_cookie, host->next_data.cookie);
+               data->host_cookie = 0;
+       }
+
+       if (next || (!next && data->host_cookie != host->next_data.cookie))
+               sg_count = rtsx_pci_dma_map_sg(pcr,
+                               data->sg, data->sg_len, read);
+       else
+               sg_count = host->next_data.sg_count;
+
+       if (next) {
+               next->sg_count = sg_count;
+               if (++next->cookie < 0)
+                       next->cookie = 1;
+               data->host_cookie = next->cookie;
+       }
+
+       return sg_count;
+}
+
+static void sdmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
+               bool is_first_req)
+{
+       struct realtek_pci_sdmmc *host = mmc_priv(mmc);
+       struct mmc_data *data = mrq->data;
+
+       if (data->host_cookie) {
+               dev_err(sdmmc_dev(host),
+                       "error: descard already cookie data[%d]\n",
+                       data->host_cookie);
+               data->host_cookie = 0;
+       }
+
+       dev_dbg(sdmmc_dev(host), "dma sg prepared: %d\n",
+               sd_pre_dma_transfer(host, data, &host->next_data));
+}
+
+static void sdmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
+               int err)
+{
+       struct realtek_pci_sdmmc *host = mmc_priv(mmc);
+       struct rtsx_pcr *pcr = host->pcr;
+       struct mmc_data *data = mrq->data;
+       int read = data->flags & MMC_DATA_READ;
+
+       rtsx_pci_dma_unmap_sg(pcr, data->sg, data->sg_len, read);
+       data->host_cookie = 0;
+}
+
+static int sd_start_multi_rw(struct realtek_pci_sdmmc *host,
+               struct mmc_request *mrq)
 {
        struct rtsx_pcr *pcr = host->pcr;
        struct mmc_host *mmc = host->mmc;
        struct mmc_card *card = mmc->card;
        struct mmc_data *data = mrq->data;
        int uhs = mmc_card_uhs(card);
-       int read = (data->flags & MMC_DATA_READ) ? 1 : 0;
+       int read = data->flags & MMC_DATA_READ;
        u8 cfg2, trans_mode;
        int err;
        size_t data_len = data->blksz * data->blocks;
 
+       if (host->data)
+               dev_err(sdmmc_dev(host), "error: data already exist\n");
+
+       host->data = data;
+
        if (read) {
                cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
                        SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0;
@@ -420,17 +635,56 @@ static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq)
        rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER,
                        SD_TRANSFER_END, SD_TRANSFER_END);
 
+       mod_timer(&host->timer, jiffies + 10 * HZ);
        rtsx_pci_send_cmd_no_wait(pcr);
 
-       err = rtsx_pci_transfer_data(pcr, data->sg, data->sg_len, read, 10000);
+       err = rtsx_pci_dma_transfer(pcr, data->sg, host->sg_count, read);
        if (err < 0) {
-               sd_clear_error(host);
-               return err;
+               data->error = err;
+               tasklet_schedule(&host->finish_tasklet);
        }
-
        return 0;
 }
 
+static void sd_finish_multi_rw(unsigned long host_addr)
+{
+       struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
+       struct rtsx_pcr *pcr = host->pcr;
+       struct mmc_data *data;
+       int err = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       if (!host->data) {
+               dev_err(sdmmc_dev(host), "error: no data exist\n");
+               goto out;
+       }
+
+       data = host->data;
+       host->data = NULL;
+
+       if (pcr->trans_result == TRANS_NO_DEVICE)
+               err = -ENODEV;
+       else if (pcr->trans_result != TRANS_RESULT_OK)
+               err = -EINVAL;
+
+       if (err < 0) {
+               data->error = err;
+               goto out;
+       }
+
+       if (!host->mrq->sbc && data->stop) {
+               sd_send_cmd(host, data->stop);
+               spin_unlock_irqrestore(&host->lock, flags);
+               return;
+       }
+
+out:
+       tasklet_schedule(&host->finish_tasklet);
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
 static inline void sd_enable_initial_mode(struct realtek_pci_sdmmc *host)
 {
        rtsx_pci_write_register(host->pcr, SD_CFG1,
@@ -511,85 +765,47 @@ static int sd_change_phase(struct realtek_pci_sdmmc *host,
        return 0;
 }
 
-static u8 sd_search_final_phase(struct realtek_pci_sdmmc *host, u32 phase_map)
+static inline u32 test_phase_bit(u32 phase_map, unsigned int bit)
 {
-       struct timing_phase_path path[MAX_PHASE + 1];
-       int i, j, cont_path_cnt;
-       int new_block, max_len, final_path_idx;
-       u8 final_phase = 0xFF;
+       bit %= RTSX_PHASE_MAX;
+       return phase_map & (1 << bit);
+}
 
-       /* Parse phase_map, take it as a bit-ring */
-       cont_path_cnt = 0;
-       new_block = 1;
-       j = 0;
-       for (i = 0; i < MAX_PHASE + 1; i++) {
-               if (phase_map & (1 << i)) {
-                       if (new_block) {
-                               new_block = 0;
-                               j = cont_path_cnt++;
-                               path[j].start = i;
-                               path[j].end = i;
-                       } else {
-                               path[j].end = i;
-                       }
-               } else {
-                       new_block = 1;
-                       if (cont_path_cnt) {
-                               /* Calculate path length and middle point */
-                               int idx = cont_path_cnt - 1;
-                               path[idx].len =
-                                       path[idx].end - path[idx].start + 1;
-                               path[idx].mid =
-                                       path[idx].start + path[idx].len / 2;
-                       }
-               }
-       }
+static int sd_get_phase_len(u32 phase_map, unsigned int start_bit)
+{
+       int i;
 
-       if (cont_path_cnt == 0) {
-               dev_dbg(sdmmc_dev(host), "No continuous phase path\n");
-               goto finish;
-       } else {
-               /* Calculate last continuous path length and middle point */
-               int idx = cont_path_cnt - 1;
-               path[idx].len = path[idx].end - path[idx].start + 1;
-               path[idx].mid = path[idx].start + path[idx].len / 2;
+       for (i = 0; i < RTSX_PHASE_MAX; i++) {
+               if (test_phase_bit(phase_map, start_bit + i) == 0)
+                       return i;
        }
+       return RTSX_PHASE_MAX;
+}
+
+static u8 sd_search_final_phase(struct realtek_pci_sdmmc *host, u32 phase_map)
+{
+       int start = 0, len = 0;
+       int start_final = 0, len_final = 0;
+       u8 final_phase = 0xFF;
 
-       /* Connect the first and last continuous paths if they are adjacent */
-       if (!path[0].start && (path[cont_path_cnt - 1].end == MAX_PHASE)) {
-               /* Using negative index */
-               path[0].start = path[cont_path_cnt - 1].start - MAX_PHASE - 1;
-               path[0].len += path[cont_path_cnt - 1].len;
-               path[0].mid = path[0].start + path[0].len / 2;
-               /* Convert negative middle point index to positive one */
-               if (path[0].mid < 0)
-                       path[0].mid += MAX_PHASE + 1;
-               cont_path_cnt--;
+       if (phase_map == 0) {
+               dev_err(sdmmc_dev(host), "phase error: [map:%x]\n", phase_map);
+               return final_phase;
        }
 
-       /* Choose the longest continuous phase path */
-       max_len = 0;
-       final_phase = 0;
-       final_path_idx = 0;
-       for (i = 0; i < cont_path_cnt; i++) {
-               if (path[i].len > max_len) {
-                       max_len = path[i].len;
-                       final_phase = (u8)path[i].mid;
-                       final_path_idx = i;
+       while (start < RTSX_PHASE_MAX) {
+               len = sd_get_phase_len(phase_map, start);
+               if (len_final < len) {
+                       start_final = start;
+                       len_final = len;
                }
-
-               dev_dbg(sdmmc_dev(host), "path[%d].start = %d\n",
-                               i, path[i].start);
-               dev_dbg(sdmmc_dev(host), "path[%d].end = %d\n",
-                               i, path[i].end);
-               dev_dbg(sdmmc_dev(host), "path[%d].len = %d\n",
-                               i, path[i].len);
-               dev_dbg(sdmmc_dev(host), "path[%d].mid = %d\n",
-                               i, path[i].mid);
+               start += len ? len : 1;
        }
 
-finish:
-       dev_dbg(sdmmc_dev(host), "Final chosen phase: %d\n", final_phase);
+       final_phase = (start_final + len_final / 2) % RTSX_PHASE_MAX;
+       dev_dbg(sdmmc_dev(host), "phase: [map:%x] [maxlen:%d] [final:%d]\n",
+               phase_map, len_final, final_phase);
+
        return final_phase;
 }
 
@@ -635,7 +851,7 @@ static int sd_tuning_phase(struct realtek_pci_sdmmc *host,
        int err, i;
        u32 raw_phase_map = 0;
 
-       for (i = MAX_PHASE; i >= 0; i--) {
+       for (i = 0; i < RTSX_PHASE_MAX; i++) {
                err = sd_tuning_rx_cmd(host, opcode, (u8)i);
                if (err == 0)
                        raw_phase_map |= 1 << i;
@@ -685,6 +901,13 @@ static int sd_tuning_rx(struct realtek_pci_sdmmc *host, u8 opcode)
        return 0;
 }
 
+static inline bool sd_use_muti_rw(struct mmc_command *cmd)
+{
+       return mmc_op_multi(cmd->opcode) ||
+               (cmd->opcode == MMC_READ_SINGLE_BLOCK) ||
+               (cmd->opcode == MMC_WRITE_BLOCK);
+}
+
 static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
 {
        struct realtek_pci_sdmmc *host = mmc_priv(mmc);
@@ -693,6 +916,14 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
        struct mmc_data *data = mrq->data;
        unsigned int data_size = 0;
        int err;
+       unsigned long flags;
+
+       mutex_lock(&pcr->pcr_mutex);
+       spin_lock_irqsave(&host->lock, flags);
+
+       if (host->mrq)
+               dev_err(sdmmc_dev(host), "error: request already exist\n");
+       host->mrq = mrq;
 
        if (host->eject) {
                cmd->error = -ENOMEDIUM;
@@ -705,8 +936,6 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
                goto finish;
        }
 
-       mutex_lock(&pcr->pcr_mutex);
-
        rtsx_pci_start_run(pcr);
 
        rtsx_pci_switch_clock(pcr, host->clock, host->ssc_depth,
@@ -715,46 +944,28 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
        rtsx_pci_write_register(pcr, CARD_SHARE_MODE,
                        CARD_SHARE_MASK, CARD_SHARE_48_SD);
 
-       mutex_lock(&host->host_mutex);
-       host->mrq = mrq;
-       mutex_unlock(&host->host_mutex);
-
        if (mrq->data)
                data_size = data->blocks * data->blksz;
 
-       if (!data_size || mmc_op_multi(cmd->opcode) ||
-                       (cmd->opcode == MMC_READ_SINGLE_BLOCK) ||
-                       (cmd->opcode == MMC_WRITE_BLOCK)) {
-               sd_send_cmd_get_rsp(host, cmd);
-
-               if (!cmd->error && data_size) {
-                       sd_rw_multi(host, mrq);
+       if (sd_use_muti_rw(cmd))
+               host->sg_count = sd_pre_dma_transfer(host, data, NULL);
 
-                       if (mmc_op_multi(cmd->opcode) && mrq->stop)
-                               sd_send_cmd_get_rsp(host, mrq->stop);
-               }
+       if (!data_size || sd_use_muti_rw(cmd)) {
+               if (mrq->sbc)
+                       sd_send_cmd(host, mrq->sbc);
+               else
+                       sd_send_cmd(host, cmd);
+               spin_unlock_irqrestore(&host->lock, flags);
        } else {
+               spin_unlock_irqrestore(&host->lock, flags);
                sd_normal_rw(host, mrq);
+               tasklet_schedule(&host->finish_tasklet);
        }
-
-       if (mrq->data) {
-               if (cmd->error || data->error)
-                       data->bytes_xfered = 0;
-               else
-                       data->bytes_xfered = data->blocks * data->blksz;
-       }
-
-       mutex_unlock(&pcr->pcr_mutex);
+       return;
 
 finish:
-       if (cmd->error)
-               dev_dbg(sdmmc_dev(host), "cmd->error = %d\n", cmd->error);
-
-       mutex_lock(&host->host_mutex);
-       host->mrq = NULL;
-       mutex_unlock(&host->host_mutex);
-
-       mmc_request_done(mmc, mrq);
+       tasklet_schedule(&host->finish_tasklet);
+       spin_unlock_irqrestore(&host->lock, flags);
 }
 
 static int sd_set_bus_width(struct realtek_pci_sdmmc *host,
@@ -1189,6 +1400,8 @@ out:
 }
 
 static const struct mmc_host_ops realtek_pci_sdmmc_ops = {
+       .pre_req = sdmmc_pre_req,
+       .post_req = sdmmc_post_req,
        .request = sdmmc_request,
        .set_ios = sdmmc_set_ios,
        .get_ro = sdmmc_get_ro,
@@ -1252,6 +1465,7 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
        struct realtek_pci_sdmmc *host;
        struct rtsx_pcr *pcr;
        struct pcr_handle *handle = pdev->dev.platform_data;
+       unsigned long host_addr;
 
        if (!handle)
                return -ENXIO;
@@ -1275,8 +1489,15 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
        pcr->slots[RTSX_SD_CARD].p_dev = pdev;
        pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event;
 
-       mutex_init(&host->host_mutex);
+       host_addr = (unsigned long)host;
+       host->next_data.cookie = 1;
+       setup_timer(&host->timer, sd_request_timeout, host_addr);
+       tasklet_init(&host->cmd_tasklet, sd_get_rsp, host_addr);
+       tasklet_init(&host->data_tasklet, sd_finish_multi_rw, host_addr);
+       tasklet_init(&host->finish_tasklet, sd_finish_request, host_addr);
+       spin_lock_init(&host->lock);
 
+       pcr->slots[RTSX_SD_CARD].done_transfer = sd_isr_done_transfer;
        realtek_init_host(host);
 
        mmc_add_host(mmc);
@@ -1289,6 +1510,8 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
        struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev);
        struct rtsx_pcr *pcr;
        struct mmc_host *mmc;
+       struct mmc_request *mrq;
+       unsigned long flags;
 
        if (!host)
                return 0;
@@ -1296,25 +1519,37 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
        pcr = host->pcr;
        pcr->slots[RTSX_SD_CARD].p_dev = NULL;
        pcr->slots[RTSX_SD_CARD].card_event = NULL;
+       pcr->slots[RTSX_SD_CARD].done_transfer = NULL;
        mmc = host->mmc;
-       host->eject = true;
+       mrq = host->mrq;
 
-       mutex_lock(&host->host_mutex);
+       spin_lock_irqsave(&host->lock, flags);
        if (host->mrq) {
                dev_dbg(&(pdev->dev),
                        "%s: Controller removed during transfer\n",
                        mmc_hostname(mmc));
 
-               rtsx_pci_complete_unfinished_transfer(pcr);
+               if (mrq->sbc)
+                       mrq->sbc->error = -ENOMEDIUM;
+               if (mrq->cmd)
+                       mrq->cmd->error = -ENOMEDIUM;
+               if (mrq->stop)
+                       mrq->stop->error = -ENOMEDIUM;
+               if (mrq->data)
+                       mrq->data->error = -ENOMEDIUM;
 
-               host->mrq->cmd->error = -ENOMEDIUM;
-               if (host->mrq->stop)
-                       host->mrq->stop->error = -ENOMEDIUM;
-               mmc_request_done(mmc, host->mrq);
+               tasklet_schedule(&host->finish_tasklet);
        }
-       mutex_unlock(&host->host_mutex);
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       del_timer_sync(&host->timer);
+       tasklet_kill(&host->cmd_tasklet);
+       tasklet_kill(&host->data_tasklet);
+       tasklet_kill(&host->finish_tasklet);
 
        mmc_remove_host(mmc);
+       host->eject = true;
+
        mmc_free_host(mmc);
 
        dev_dbg(&(pdev->dev),
index 9ce17f6e4014d9f4fc0b45c8e6856056ddebdb52..ebb3f392b5894f6af8705604a38476b4e0048aa3 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/err.h>
-#include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #include <linux/acpi.h>
 #include <linux/pm.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/pm.h>
+#include <linux/mmc/slot-gpio.h>
 #include <linux/mmc/sdhci.h>
 
 #include "sdhci.h"
 
 enum {
-       SDHCI_ACPI_SD_CD        = BIT(0),
-       SDHCI_ACPI_RUNTIME_PM   = BIT(1),
+       SDHCI_ACPI_SD_CD                = BIT(0),
+       SDHCI_ACPI_RUNTIME_PM           = BIT(1),
+       SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL = BIT(2),
 };
 
 struct sdhci_acpi_chip {
@@ -121,6 +122,7 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
 };
 
 static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
+       .quirks  = SDHCI_QUIRK_BROKEN_CARD_DETECTION,
        .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
        .caps    = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD,
        .flags   = SDHCI_ACPI_RUNTIME_PM,
@@ -128,7 +130,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
 };
 
 static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
-       .flags   = SDHCI_ACPI_SD_CD | SDHCI_ACPI_RUNTIME_PM,
+       .flags   = SDHCI_ACPI_SD_CD | SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL |
+                  SDHCI_ACPI_RUNTIME_PM,
        .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON,
 };
 
@@ -141,6 +144,7 @@ struct sdhci_acpi_uid_slot {
 static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = {
        { "80860F14" , "1" , &sdhci_acpi_slot_int_emmc },
        { "80860F14" , "3" , &sdhci_acpi_slot_int_sd   },
+       { "80860F16" , NULL, &sdhci_acpi_slot_int_sd   },
        { "INT33BB"  , "2" , &sdhci_acpi_slot_int_sdio },
        { "INT33C6"  , NULL, &sdhci_acpi_slot_int_sdio },
        { "INT3436"  , NULL, &sdhci_acpi_slot_int_sdio },
@@ -150,6 +154,7 @@ static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = {
 
 static const struct acpi_device_id sdhci_acpi_ids[] = {
        { "80860F14" },
+       { "80860F16" },
        { "INT33BB"  },
        { "INT33C6"  },
        { "INT3436"  },
@@ -192,59 +197,6 @@ static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(acpi_handle handle,
        return slot;
 }
 
-#ifdef CONFIG_PM_RUNTIME
-
-static irqreturn_t sdhci_acpi_sd_cd(int irq, void *dev_id)
-{
-       mmc_detect_change(dev_id, msecs_to_jiffies(200));
-       return IRQ_HANDLED;
-}
-
-static int sdhci_acpi_add_own_cd(struct device *dev, struct mmc_host *mmc)
-{
-       struct gpio_desc *desc;
-       unsigned long flags;
-       int err, irq;
-
-       desc = devm_gpiod_get_index(dev, "sd_cd", 0);
-       if (IS_ERR(desc)) {
-               err = PTR_ERR(desc);
-               goto out;
-       }
-
-       err = gpiod_direction_input(desc);
-       if (err)
-               goto out_free;
-
-       irq = gpiod_to_irq(desc);
-       if (irq < 0) {
-               err = irq;
-               goto out_free;
-       }
-
-       flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
-       err = devm_request_irq(dev, irq, sdhci_acpi_sd_cd, flags, "sd_cd", mmc);
-       if (err)
-               goto out_free;
-
-       return 0;
-
-out_free:
-       devm_gpiod_put(dev, desc);
-out:
-       dev_warn(dev, "failed to setup card detect wake up\n");
-       return err;
-}
-
-#else
-
-static int sdhci_acpi_add_own_cd(struct device *dev, struct mmc_host *mmc)
-{
-       return 0;
-}
-
-#endif
-
 static int sdhci_acpi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -332,15 +284,19 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
 
        host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP;
 
-       err = sdhci_add_host(host);
-       if (err)
-               goto err_free;
-
        if (sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD)) {
-               if (sdhci_acpi_add_own_cd(dev, host->mmc))
+               bool v = sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL);
+
+               if (mmc_gpiod_request_cd(host->mmc, NULL, 0, v, 0)) {
+                       dev_warn(dev, "failed to setup card detect gpio\n");
                        c->use_runtime_pm = false;
+               }
        }
 
+       err = sdhci_add_host(host);
+       if (err)
+               goto err_free;
+
        if (c->use_runtime_pm) {
                pm_runtime_set_active(dev);
                pm_suspend_ignore_children(dev, 1);
index 7a190fe4dff1b799958bfedf7bb01dd5d405a0f8..6f166e63b8172fd5484796584cb36c8291410aeb 100644 (file)
@@ -54,6 +54,7 @@
 
 struct sdhci_bcm_kona_dev {
        struct mutex    write_lock; /* protect back to back writes */
+       struct clk      *external_clk;
 };
 
 
@@ -257,6 +258,24 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
                goto err_pltfm_free;
        }
 
+       /* Get and enable the external clock */
+       kona_dev->external_clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(kona_dev->external_clk)) {
+               dev_err(dev, "Failed to get external clock\n");
+               ret = PTR_ERR(kona_dev->external_clk);
+               goto err_pltfm_free;
+       }
+
+       if (clk_set_rate(kona_dev->external_clk, host->mmc->f_max) != 0) {
+               dev_err(dev, "Failed to set rate external clock\n");
+               goto err_pltfm_free;
+       }
+
+       if (clk_prepare_enable(kona_dev->external_clk) != 0) {
+               dev_err(dev, "Failed to enable external clock\n");
+               goto err_pltfm_free;
+       }
+
        dev_dbg(dev, "non-removable=%c\n",
                (host->mmc->caps & MMC_CAP_NONREMOVABLE) ? 'Y' : 'N');
        dev_dbg(dev, "cd_gpio %c, wp_gpio %c\n",
@@ -271,7 +290,7 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
 
        ret = sdhci_bcm_kona_sd_reset(host);
        if (ret)
-               goto err_pltfm_free;
+               goto err_clk_disable;
 
        sdhci_bcm_kona_sd_init(host);
 
@@ -307,6 +326,9 @@ err_remove_host:
 err_reset:
        sdhci_bcm_kona_sd_reset(host);
 
+err_clk_disable:
+       clk_disable_unprepare(kona_dev->external_clk);
+
 err_pltfm_free:
        sdhci_pltfm_free(pdev);
 
@@ -314,9 +336,20 @@ err_pltfm_free:
        return ret;
 }
 
-static int __exit sdhci_bcm_kona_remove(struct platform_device *pdev)
+static int sdhci_bcm_kona_remove(struct platform_device *pdev)
 {
-       return sdhci_pltfm_unregister(pdev);
+       struct sdhci_host *host = platform_get_drvdata(pdev);
+       struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host);
+       struct sdhci_bcm_kona_dev *kona_dev = sdhci_pltfm_priv(pltfm_priv);
+       int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+
+       sdhci_remove_host(host, dead);
+
+       clk_disable_unprepare(kona_dev->external_clk);
+
+       sdhci_pltfm_free(pdev);
+
+       return 0;
 }
 
 static struct platform_driver sdhci_bcm_kona_driver = {
index 8424839660f844b748f7960a46a5e9cf5df88e56..736d7a2eb7ec454a0bde08de0ae9bc3ba0b006e0 100644 (file)
@@ -208,7 +208,7 @@ static struct platform_driver sdhci_dove_driver = {
                .name   = "sdhci-dove",
                .owner  = THIS_MODULE,
                .pm     = SDHCI_PLTFM_PMOPS,
-               .of_match_table = of_match_ptr(sdhci_dove_of_match_table),
+               .of_match_table = sdhci_dove_of_match_table,
        },
        .probe          = sdhci_dove_probe,
        .remove         = sdhci_dove_remove,
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
new file mode 100644 (file)
index 0000000..acb0e9e
--- /dev/null
@@ -0,0 +1,618 @@
+/*
+ * drivers/mmc/host/sdhci-msm.c - Qualcomm SDHCI Platform driver
+ *
+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <linux/mmc/mmc.h>
+#include <linux/slab.h>
+
+#include "sdhci-pltfm.h"
+
+#define CORE_HC_MODE           0x78
+#define HC_MODE_EN             0x1
+#define CORE_POWER             0x0
+#define CORE_SW_RST            BIT(7)
+
+#define MAX_PHASES             16
+#define CORE_DLL_LOCK          BIT(7)
+#define CORE_DLL_EN            BIT(16)
+#define CORE_CDR_EN            BIT(17)
+#define CORE_CK_OUT_EN         BIT(18)
+#define CORE_CDR_EXT_EN                BIT(19)
+#define CORE_DLL_PDN           BIT(29)
+#define CORE_DLL_RST           BIT(30)
+#define CORE_DLL_CONFIG                0x100
+#define CORE_DLL_STATUS                0x108
+
+#define CORE_VENDOR_SPEC       0x10c
+#define CORE_CLK_PWRSAVE       BIT(1)
+
+#define CDR_SELEXT_SHIFT       20
+#define CDR_SELEXT_MASK                (0xf << CDR_SELEXT_SHIFT)
+#define CMUX_SHIFT_PHASE_SHIFT 24
+#define CMUX_SHIFT_PHASE_MASK  (7 << CMUX_SHIFT_PHASE_SHIFT)
+
+static const u32 tuning_block_64[] = {
+       0x00ff0fff, 0xccc3ccff, 0xffcc3cc3, 0xeffefffe,
+       0xddffdfff, 0xfbfffbff, 0xff7fffbf, 0xefbdf777,
+       0xf0fff0ff, 0x3cccfc0f, 0xcfcc33cc, 0xeeffefff,
+       0xfdfffdff, 0xffbfffdf, 0xfff7ffbb, 0xde7b7ff7
+};
+
+static const u32 tuning_block_128[] = {
+       0xff00ffff, 0x0000ffff, 0xccccffff, 0xcccc33cc,
+       0xcc3333cc, 0xffffcccc, 0xffffeeff, 0xffeeeeff,
+       0xffddffff, 0xddddffff, 0xbbffffff, 0xbbffffff,
+       0xffffffbb, 0xffffff77, 0x77ff7777, 0xffeeddbb,
+       0x00ffffff, 0x00ffffff, 0xccffff00, 0xcc33cccc,
+       0x3333cccc, 0xffcccccc, 0xffeeffff, 0xeeeeffff,
+       0xddffffff, 0xddffffff, 0xffffffdd, 0xffffffbb,
+       0xffffbbbb, 0xffff77ff, 0xff7777ff, 0xeeddbb77
+};
+
+struct sdhci_msm_host {
+       struct platform_device *pdev;
+       void __iomem *core_mem; /* MSM SDCC mapped address */
+       struct clk *clk;        /* main SD/MMC bus clock */
+       struct clk *pclk;       /* SDHC peripheral bus clock */
+       struct clk *bus_clk;    /* SDHC bus voter clock */
+       struct mmc_host *mmc;
+       struct sdhci_pltfm_data sdhci_msm_pdata;
+};
+
+/* Platform specific tuning */
+static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll)
+{
+       u32 wait_cnt = 50;
+       u8 ck_out_en;
+       struct mmc_host *mmc = host->mmc;
+
+       /* Poll for CK_OUT_EN bit.  max. poll time = 50us */
+       ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
+                       CORE_CK_OUT_EN);
+
+       while (ck_out_en != poll) {
+               if (--wait_cnt == 0) {
+                       dev_err(mmc_dev(mmc), "%s: CK_OUT_EN bit is not %d\n",
+                              mmc_hostname(mmc), poll);
+                       return -ETIMEDOUT;
+               }
+               udelay(1);
+
+               ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
+                               CORE_CK_OUT_EN);
+       }
+
+       return 0;
+}
+
+static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)
+{
+       int rc;
+       static const u8 grey_coded_phase_table[] = {
+               0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
+               0xc, 0xd, 0xf, 0xe, 0xa, 0xb, 0x9, 0x8
+       };
+       unsigned long flags;
+       u32 config;
+       struct mmc_host *mmc = host->mmc;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
+       config &= ~(CORE_CDR_EN | CORE_CK_OUT_EN);
+       config |= (CORE_CDR_EXT_EN | CORE_DLL_EN);
+       writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+
+       /* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '0' */
+       rc = msm_dll_poll_ck_out_en(host, 0);
+       if (rc)
+               goto err_out;
+
+       /*
+        * Write the selected DLL clock output phase (0 ... 15)
+        * to CDR_SELEXT bit field of DLL_CONFIG register.
+        */
+       config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
+       config &= ~CDR_SELEXT_MASK;
+       config |= grey_coded_phase_table[phase] << CDR_SELEXT_SHIFT;
+       writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+
+       /* Set CK_OUT_EN bit of DLL_CONFIG register to 1. */
+       writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+                       | CORE_CK_OUT_EN), host->ioaddr + CORE_DLL_CONFIG);
+
+       /* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '1' */
+       rc = msm_dll_poll_ck_out_en(host, 1);
+       if (rc)
+               goto err_out;
+
+       config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
+       config |= CORE_CDR_EN;
+       config &= ~CORE_CDR_EXT_EN;
+       writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+       goto out;
+
+err_out:
+       dev_err(mmc_dev(mmc), "%s: Failed to set DLL phase: %d\n",
+              mmc_hostname(mmc), phase);
+out:
+       spin_unlock_irqrestore(&host->lock, flags);
+       return rc;
+}
+
+/*
+ * Find out the greatest range of consecuitive selected
+ * DLL clock output phases that can be used as sampling
+ * setting for SD3.0 UHS-I card read operation (in SDR104
+ * timing mode) or for eMMC4.5 card read operation (in HS200
+ * timing mode).
+ * Select the 3/4 of the range and configure the DLL with the
+ * selected DLL clock output phase.
+ */
+
+static int msm_find_most_appropriate_phase(struct sdhci_host *host,
+                                          u8 *phase_table, u8 total_phases)
+{
+       int ret;
+       u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
+       u8 phases_per_row[MAX_PHASES] = { 0 };
+       int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
+       int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
+       bool phase_0_found = false, phase_15_found = false;
+       struct mmc_host *mmc = host->mmc;
+
+       if (!total_phases || (total_phases > MAX_PHASES)) {
+               dev_err(mmc_dev(mmc), "%s: Invalid argument: total_phases=%d\n",
+                      mmc_hostname(mmc), total_phases);
+               return -EINVAL;
+       }
+
+       for (cnt = 0; cnt < total_phases; cnt++) {
+               ranges[row_index][col_index] = phase_table[cnt];
+               phases_per_row[row_index] += 1;
+               col_index++;
+
+               if ((cnt + 1) == total_phases) {
+                       continue;
+               /* check if next phase in phase_table is consecutive or not */
+               } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
+                       row_index++;
+                       col_index = 0;
+               }
+       }
+
+       if (row_index >= MAX_PHASES)
+               return -EINVAL;
+
+       /* Check if phase-0 is present in first valid window? */
+       if (!ranges[0][0]) {
+               phase_0_found = true;
+               phase_0_raw_index = 0;
+               /* Check if cycle exist between 2 valid windows */
+               for (cnt = 1; cnt <= row_index; cnt++) {
+                       if (phases_per_row[cnt]) {
+                               for (i = 0; i < phases_per_row[cnt]; i++) {
+                                       if (ranges[cnt][i] == 15) {
+                                               phase_15_found = true;
+                                               phase_15_raw_index = cnt;
+                                               break;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* If 2 valid windows form cycle then merge them as single window */
+       if (phase_0_found && phase_15_found) {
+               /* number of phases in raw where phase 0 is present */
+               u8 phases_0 = phases_per_row[phase_0_raw_index];
+               /* number of phases in raw where phase 15 is present */
+               u8 phases_15 = phases_per_row[phase_15_raw_index];
+
+               if (phases_0 + phases_15 >= MAX_PHASES)
+                       /*
+                        * If there are more than 1 phase windows then total
+                        * number of phases in both the windows should not be
+                        * more than or equal to MAX_PHASES.
+                        */
+                       return -EINVAL;
+
+               /* Merge 2 cyclic windows */
+               i = phases_15;
+               for (cnt = 0; cnt < phases_0; cnt++) {
+                       ranges[phase_15_raw_index][i] =
+                           ranges[phase_0_raw_index][cnt];
+                       if (++i >= MAX_PHASES)
+                               break;
+               }
+
+               phases_per_row[phase_0_raw_index] = 0;
+               phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
+       }
+
+       for (cnt = 0; cnt <= row_index; cnt++) {
+               if (phases_per_row[cnt] > curr_max) {
+                       curr_max = phases_per_row[cnt];
+                       selected_row_index = cnt;
+               }
+       }
+
+       i = (curr_max * 3) / 4;
+       if (i)
+               i--;
+
+       ret = ranges[selected_row_index][i];
+
+       if (ret >= MAX_PHASES) {
+               ret = -EINVAL;
+               dev_err(mmc_dev(mmc), "%s: Invalid phase selected=%d\n",
+                      mmc_hostname(mmc), ret);
+       }
+
+       return ret;
+}
+
+static inline void msm_cm_dll_set_freq(struct sdhci_host *host)
+{
+       u32 mclk_freq = 0, config;
+
+       /* Program the MCLK value to MCLK_FREQ bit field */
+       if (host->clock <= 112000000)
+               mclk_freq = 0;
+       else if (host->clock <= 125000000)
+               mclk_freq = 1;
+       else if (host->clock <= 137000000)
+               mclk_freq = 2;
+       else if (host->clock <= 150000000)
+               mclk_freq = 3;
+       else if (host->clock <= 162000000)
+               mclk_freq = 4;
+       else if (host->clock <= 175000000)
+               mclk_freq = 5;
+       else if (host->clock <= 187000000)
+               mclk_freq = 6;
+       else if (host->clock <= 200000000)
+               mclk_freq = 7;
+
+       config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
+       config &= ~CMUX_SHIFT_PHASE_MASK;
+       config |= mclk_freq << CMUX_SHIFT_PHASE_SHIFT;
+       writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+}
+
+/* Initialize the DLL (Programmable Delay Line) */
+static int msm_init_cm_dll(struct sdhci_host *host)
+{
+       struct mmc_host *mmc = host->mmc;
+       int wait_cnt = 50;
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       /*
+        * Make sure that clock is always enabled when DLL
+        * tuning is in progress. Keeping PWRSAVE ON may
+        * turn off the clock.
+        */
+       writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
+                       & ~CORE_CLK_PWRSAVE), host->ioaddr + CORE_VENDOR_SPEC);
+
+       /* Write 1 to DLL_RST bit of DLL_CONFIG register */
+       writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+                       | CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG);
+
+       /* Write 1 to DLL_PDN bit of DLL_CONFIG register */
+       writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+                       | CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG);
+       msm_cm_dll_set_freq(host);
+
+       /* Write 0 to DLL_RST bit of DLL_CONFIG register */
+       writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+                       & ~CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG);
+
+       /* Write 0 to DLL_PDN bit of DLL_CONFIG register */
+       writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+                       & ~CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG);
+
+       /* Set DLL_EN bit to 1. */
+       writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+                       | CORE_DLL_EN), host->ioaddr + CORE_DLL_CONFIG);
+
+       /* Set CK_OUT_EN bit to 1. */
+       writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+                       | CORE_CK_OUT_EN), host->ioaddr + CORE_DLL_CONFIG);
+
+       /* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */
+       while (!(readl_relaxed(host->ioaddr + CORE_DLL_STATUS) &
+                CORE_DLL_LOCK)) {
+               /* max. wait for 50us sec for LOCK bit to be set */
+               if (--wait_cnt == 0) {
+                       dev_err(mmc_dev(mmc), "%s: DLL failed to LOCK\n",
+                              mmc_hostname(mmc));
+                       spin_unlock_irqrestore(&host->lock, flags);
+                       return -ETIMEDOUT;
+               }
+               udelay(1);
+       }
+
+       spin_unlock_irqrestore(&host->lock, flags);
+       return 0;
+}
+
+static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
+{
+       int tuning_seq_cnt = 3;
+       u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
+       const u32 *tuning_block_pattern = tuning_block_64;
+       int size = sizeof(tuning_block_64);     /* Pattern size in bytes */
+       int rc;
+       struct mmc_host *mmc = host->mmc;
+       struct mmc_ios ios = host->mmc->ios;
+
+       /*
+        * Tuning is required for SDR104, HS200 and HS400 cards and
+        * if clock frequency is greater than 100MHz in these modes.
+        */
+       if (host->clock <= 100 * 1000 * 1000 ||
+           !((ios.timing == MMC_TIMING_MMC_HS200) ||
+             (ios.timing == MMC_TIMING_UHS_SDR104)))
+               return 0;
+
+       if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
+           (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
+               tuning_block_pattern = tuning_block_128;
+               size = sizeof(tuning_block_128);
+       }
+
+       data_buf = kmalloc(size, GFP_KERNEL);
+       if (!data_buf)
+               return -ENOMEM;
+
+retry:
+       /* First of all reset the tuning block */
+       rc = msm_init_cm_dll(host);
+       if (rc)
+               goto out;
+
+       phase = 0;
+       do {
+               struct mmc_command cmd = { 0 };
+               struct mmc_data data = { 0 };
+               struct mmc_request mrq = {
+                       .cmd = &cmd,
+                       .data = &data
+               };
+               struct scatterlist sg;
+
+               /* Set the phase in delay line hw block */
+               rc = msm_config_cm_dll_phase(host, phase);
+               if (rc)
+                       goto out;
+
+               cmd.opcode = opcode;
+               cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+               data.blksz = size;
+               data.blocks = 1;
+               data.flags = MMC_DATA_READ;
+               data.timeout_ns = NSEC_PER_SEC; /* 1 second */
+
+               data.sg = &sg;
+               data.sg_len = 1;
+               sg_init_one(&sg, data_buf, size);
+               memset(data_buf, 0, size);
+               mmc_wait_for_req(mmc, &mrq);
+
+               if (!cmd.error && !data.error &&
+                   !memcmp(data_buf, tuning_block_pattern, size)) {
+                       /* Tuning is successful at this tuning point */
+                       tuned_phases[tuned_phase_cnt++] = phase;
+                       dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
+                                mmc_hostname(mmc), phase);
+               }
+       } while (++phase < ARRAY_SIZE(tuned_phases));
+
+       if (tuned_phase_cnt) {
+               rc = msm_find_most_appropriate_phase(host, tuned_phases,
+                                                    tuned_phase_cnt);
+               if (rc < 0)
+                       goto out;
+               else
+                       phase = rc;
+
+               /*
+                * Finally set the selected phase in delay
+                * line hw block.
+                */
+               rc = msm_config_cm_dll_phase(host, phase);
+               if (rc)
+                       goto out;
+               dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
+                        mmc_hostname(mmc), phase);
+       } else {
+               if (--tuning_seq_cnt)
+                       goto retry;
+               /* Tuning failed */
+               dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n",
+                      mmc_hostname(mmc));
+               rc = -EIO;
+       }
+
+out:
+       kfree(data_buf);
+       return rc;
+}
+
+static const struct of_device_id sdhci_msm_dt_match[] = {
+       { .compatible = "qcom,sdhci-msm-v4" },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
+
+static struct sdhci_ops sdhci_msm_ops = {
+       .platform_execute_tuning = sdhci_msm_execute_tuning,
+};
+
+static int sdhci_msm_probe(struct platform_device *pdev)
+{
+       struct sdhci_host *host;
+       struct sdhci_pltfm_host *pltfm_host;
+       struct sdhci_msm_host *msm_host;
+       struct resource *core_memres;
+       int ret;
+       u16 host_version;
+
+       msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL);
+       if (!msm_host)
+               return -ENOMEM;
+
+       msm_host->sdhci_msm_pdata.ops = &sdhci_msm_ops;
+       host = sdhci_pltfm_init(pdev, &msm_host->sdhci_msm_pdata, 0);
+       if (IS_ERR(host))
+               return PTR_ERR(host);
+
+       pltfm_host = sdhci_priv(host);
+       pltfm_host->priv = msm_host;
+       msm_host->mmc = host->mmc;
+       msm_host->pdev = pdev;
+
+       ret = mmc_of_parse(host->mmc);
+       if (ret)
+               goto pltfm_free;
+
+       sdhci_get_of_property(pdev);
+
+       /* Setup SDCC bus voter clock. */
+       msm_host->bus_clk = devm_clk_get(&pdev->dev, "bus");
+       if (!IS_ERR(msm_host->bus_clk)) {
+               /* Vote for max. clk rate for max. performance */
+               ret = clk_set_rate(msm_host->bus_clk, INT_MAX);
+               if (ret)
+                       goto pltfm_free;
+               ret = clk_prepare_enable(msm_host->bus_clk);
+               if (ret)
+                       goto pltfm_free;
+       }
+
+       /* Setup main peripheral bus clock */
+       msm_host->pclk = devm_clk_get(&pdev->dev, "iface");
+       if (IS_ERR(msm_host->pclk)) {
+               ret = PTR_ERR(msm_host->pclk);
+               dev_err(&pdev->dev, "Perpheral clk setup failed (%d)\n", ret);
+               goto bus_clk_disable;
+       }
+
+       ret = clk_prepare_enable(msm_host->pclk);
+       if (ret)
+               goto bus_clk_disable;
+
+       /* Setup SDC MMC clock */
+       msm_host->clk = devm_clk_get(&pdev->dev, "core");
+       if (IS_ERR(msm_host->clk)) {
+               ret = PTR_ERR(msm_host->clk);
+               dev_err(&pdev->dev, "SDC MMC clk setup failed (%d)\n", ret);
+               goto pclk_disable;
+       }
+
+       ret = clk_prepare_enable(msm_host->clk);
+       if (ret)
+               goto pclk_disable;
+
+       core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       msm_host->core_mem = devm_ioremap_resource(&pdev->dev, core_memres);
+
+       if (IS_ERR(msm_host->core_mem)) {
+               dev_err(&pdev->dev, "Failed to remap registers\n");
+               ret = PTR_ERR(msm_host->core_mem);
+               goto clk_disable;
+       }
+
+       /* Reset the core and Enable SDHC mode */
+       writel_relaxed(readl_relaxed(msm_host->core_mem + CORE_POWER) |
+                      CORE_SW_RST, msm_host->core_mem + CORE_POWER);
+
+       /* SW reset can take upto 10HCLK + 15MCLK cycles. (min 40us) */
+       usleep_range(1000, 5000);
+       if (readl(msm_host->core_mem + CORE_POWER) & CORE_SW_RST) {
+               dev_err(&pdev->dev, "Stuck in reset\n");
+               ret = -ETIMEDOUT;
+               goto clk_disable;
+       }
+
+       /* Set HC_MODE_EN bit in HC_MODE register */
+       writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
+
+       host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+       host->quirks |= SDHCI_QUIRK_SINGLE_POWER_WRITE;
+
+       host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
+       dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n",
+               host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
+                              SDHCI_VENDOR_VER_SHIFT));
+
+       ret = sdhci_add_host(host);
+       if (ret)
+               goto clk_disable;
+
+       return 0;
+
+clk_disable:
+       clk_disable_unprepare(msm_host->clk);
+pclk_disable:
+       clk_disable_unprepare(msm_host->pclk);
+bus_clk_disable:
+       if (!IS_ERR(msm_host->bus_clk))
+               clk_disable_unprepare(msm_host->bus_clk);
+pltfm_free:
+       sdhci_pltfm_free(pdev);
+       return ret;
+}
+
+static int sdhci_msm_remove(struct platform_device *pdev)
+{
+       struct sdhci_host *host = platform_get_drvdata(pdev);
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_msm_host *msm_host = pltfm_host->priv;
+       int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) ==
+                   0xffffffff);
+
+       sdhci_remove_host(host, dead);
+       sdhci_pltfm_free(pdev);
+       clk_disable_unprepare(msm_host->clk);
+       clk_disable_unprepare(msm_host->pclk);
+       if (!IS_ERR(msm_host->bus_clk))
+               clk_disable_unprepare(msm_host->bus_clk);
+       return 0;
+}
+
+static struct platform_driver sdhci_msm_driver = {
+       .probe = sdhci_msm_probe,
+       .remove = sdhci_msm_remove,
+       .driver = {
+                  .name = "sdhci_msm",
+                  .owner = THIS_MODULE,
+                  .of_match_table = sdhci_msm_dt_match,
+       },
+};
+
+module_platform_driver(sdhci_msm_driver);
+
+MODULE_DESCRIPTION("Qualcomm Secure Digital Host Controller Interface driver");
+MODULE_LICENSE("GPL v2");
index 0955777b6c7e619a4041d83ffd6ae29337e98c65..fdc612120362000be42b145240acd96a306695de 100644 (file)
@@ -610,6 +610,18 @@ static const struct sdhci_pci_fixes sdhci_via = {
        .probe          = via_probe,
 };
 
+static int rtsx_probe_slot(struct sdhci_pci_slot *slot)
+{
+       slot->host->mmc->caps2 |= MMC_CAP2_HS200;
+       return 0;
+}
+
+static const struct sdhci_pci_fixes sdhci_rtsx = {
+       .quirks2        = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
+                       SDHCI_QUIRK2_BROKEN_DDR50,
+       .probe_slot     = rtsx_probe_slot,
+};
+
 static const struct pci_device_id pci_ids[] = {
        {
                .vendor         = PCI_VENDOR_ID_RICOH,
@@ -731,6 +743,14 @@ static const struct pci_device_id pci_ids[] = {
                .driver_data    = (kernel_ulong_t)&sdhci_via,
        },
 
+       {
+               .vendor         = PCI_VENDOR_ID_REALTEK,
+               .device         = 0x5250,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_rtsx,
+       },
+
        {
                .vendor         = PCI_VENDOR_ID_INTEL,
                .device         = PCI_DEVICE_ID_INTEL_MRST_SD0,
index 793dacd3b8413c5cd4eae8fc39c420c4f3ffdb5c..2fd73b38c303da0d57a592c82e227e800e6c2b60 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/of_gpio.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
+#include <linux/mbus.h>
 
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
 #define SDCE_MISC_INT          (1<<2)
 #define SDCE_MISC_INT_EN       (1<<1)
 
+/*
+ * These registers are relative to the second register region, for the
+ * MBus bridge.
+ */
+#define SDHCI_WINDOW_CTRL(i)   (0x80 + ((i) << 3))
+#define SDHCI_WINDOW_BASE(i)   (0x84 + ((i) << 3))
+#define SDHCI_MAX_WIN_NUM      8
+
+static int mv_conf_mbus_windows(struct platform_device *pdev,
+                               const struct mbus_dram_target_info *dram)
+{
+       int i;
+       void __iomem *regs;
+       struct resource *res;
+
+       if (!dram) {
+               dev_err(&pdev->dev, "no mbus dram info\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res) {
+               dev_err(&pdev->dev, "cannot get mbus registers\n");
+               return -EINVAL;
+       }
+
+       regs = ioremap(res->start, resource_size(res));
+       if (!regs) {
+               dev_err(&pdev->dev, "cannot map mbus registers\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < SDHCI_MAX_WIN_NUM; i++) {
+               writel(0, regs + SDHCI_WINDOW_CTRL(i));
+               writel(0, regs + SDHCI_WINDOW_BASE(i));
+       }
+
+       for (i = 0; i < dram->num_cs; i++) {
+               const struct mbus_dram_window *cs = dram->cs + i;
+
+               /* Write size, attributes and target id to control register */
+               writel(((cs->size - 1) & 0xffff0000) |
+                       (cs->mbus_attr << 8) |
+                       (dram->mbus_dram_target_id << 4) | 1,
+                       regs + SDHCI_WINDOW_CTRL(i));
+               /* Write base address to base register */
+               writel(cs->base, regs + SDHCI_WINDOW_BASE(i));
+       }
+
+       iounmap(regs);
+
+       return 0;
+}
+
 static void pxav3_set_private_registers(struct sdhci_host *host, u8 mask)
 {
        struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
@@ -187,6 +242,9 @@ static const struct of_device_id sdhci_pxav3_of_match[] = {
        {
                .compatible = "mrvl,pxav3-mmc",
        },
+       {
+               .compatible = "marvell,armada-380-sdhci",
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, sdhci_pxav3_of_match);
@@ -219,6 +277,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
        struct sdhci_pltfm_host *pltfm_host;
        struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
        struct device *dev = &pdev->dev;
+       struct device_node *np = pdev->dev.of_node;
        struct sdhci_host *host = NULL;
        struct sdhci_pxa *pxa = NULL;
        const struct of_device_id *match;
@@ -235,6 +294,14 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
                kfree(pxa);
                return PTR_ERR(host);
        }
+
+       if (of_device_is_compatible(np, "marvell,armada-380-sdhci")) {
+               ret = mv_conf_mbus_windows(pdev, mv_mbus_dram_info());
+               if (ret < 0)
+                       goto err_mbus_win;
+       }
+
+
        pltfm_host = sdhci_priv(host);
        pltfm_host->priv = pxa;
 
@@ -321,6 +388,7 @@ err_add_host:
        clk_disable_unprepare(clk);
        clk_put(clk);
 err_clk_get:
+err_mbus_win:
        sdhci_pltfm_free(pdev);
        kfree(pxa);
        return ret;
index 6debda9521556c530d141cb3fa898af4175a6286..d61eb5a708331d54ad9c4ea948bf7cbb4533d8da 100644 (file)
@@ -51,12 +51,13 @@ struct sdhci_s3c {
        struct platform_device  *pdev;
        struct resource         *ioarea;
        struct s3c_sdhci_platdata *pdata;
-       unsigned int            cur_clk;
+       int                     cur_clk;
        int                     ext_cd_irq;
        int                     ext_cd_gpio;
 
        struct clk              *clk_io;
        struct clk              *clk_bus[MAX_BUS_CLK];
+       unsigned long           clk_rates[MAX_BUS_CLK];
 };
 
 /**
@@ -76,32 +77,6 @@ static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host)
        return sdhci_priv(host);
 }
 
-/**
- * get_curclk - convert ctrl2 register to clock source number
- * @ctrl2: Control2 register value.
- */
-static u32 get_curclk(u32 ctrl2)
-{
-       ctrl2 &= S3C_SDHCI_CTRL2_SELBASECLK_MASK;
-       ctrl2 >>= S3C_SDHCI_CTRL2_SELBASECLK_SHIFT;
-
-       return ctrl2;
-}
-
-static void sdhci_s3c_check_sclk(struct sdhci_host *host)
-{
-       struct sdhci_s3c *ourhost = to_s3c(host);
-       u32 tmp = readl(host->ioaddr + S3C_SDHCI_CONTROL2);
-
-       if (get_curclk(tmp) != ourhost->cur_clk) {
-               dev_dbg(&ourhost->pdev->dev, "restored ctrl2 clock setting\n");
-
-               tmp &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK;
-               tmp |= ourhost->cur_clk << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT;
-               writel(tmp, host->ioaddr + S3C_SDHCI_CONTROL2);
-       }
-}
-
 /**
  * sdhci_s3c_get_max_clk - callback to get maximum clock frequency.
  * @host: The SDHCI host instance.
@@ -111,20 +86,11 @@ static void sdhci_s3c_check_sclk(struct sdhci_host *host)
 static unsigned int sdhci_s3c_get_max_clk(struct sdhci_host *host)
 {
        struct sdhci_s3c *ourhost = to_s3c(host);
-       struct clk *busclk;
-       unsigned int rate, max;
-       int clk;
-
-       /* note, a reset will reset the clock source */
-
-       sdhci_s3c_check_sclk(host);
-
-       for (max = 0, clk = 0; clk < MAX_BUS_CLK; clk++) {
-               busclk = ourhost->clk_bus[clk];
-               if (!busclk)
-                       continue;
+       unsigned long rate, max = 0;
+       int src;
 
-               rate = clk_get_rate(busclk);
+       for (src = 0; src < MAX_BUS_CLK; src++) {
+               rate = ourhost->clk_rates[src];
                if (rate > max)
                        max = rate;
        }
@@ -144,9 +110,9 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,
 {
        unsigned long rate;
        struct clk *clksrc = ourhost->clk_bus[src];
-       int div;
+       int shift;
 
-       if (!clksrc)
+       if (IS_ERR(clksrc))
                return UINT_MAX;
 
        /*
@@ -158,17 +124,24 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,
                return wanted - rate;
        }
 
-       rate = clk_get_rate(clksrc);
+       rate = ourhost->clk_rates[src];
 
-       for (div = 1; div < 256; div *= 2) {
-               if ((rate / div) <= wanted)
+       for (shift = 0; shift <= 8; ++shift) {
+               if ((rate >> shift) <= wanted)
                        break;
        }
 
+       if (shift > 8) {
+               dev_dbg(&ourhost->pdev->dev,
+                       "clk %d: rate %ld, min rate %lu > wanted %u\n",
+                       src, rate, rate / 256, wanted);
+               return UINT_MAX;
+       }
+
        dev_dbg(&ourhost->pdev->dev, "clk %d: rate %ld, want %d, got %ld\n",
-               src, rate, wanted, rate / div);
+               src, rate, wanted, rate >> shift);
 
-       return wanted - (rate / div);
+       return wanted - (rate >> shift);
 }
 
 /**
@@ -209,20 +182,22 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)
                struct clk *clk = ourhost->clk_bus[best_src];
 
                clk_prepare_enable(clk);
-               clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]);
-
-               /* turn clock off to card before changing clock source */
-               writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
+               if (ourhost->cur_clk >= 0)
+                       clk_disable_unprepare(
+                                       ourhost->clk_bus[ourhost->cur_clk]);
 
                ourhost->cur_clk = best_src;
-               host->max_clk = clk_get_rate(clk);
-
-               ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2);
-               ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK;
-               ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT;
-               writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2);
+               host->max_clk = ourhost->clk_rates[best_src];
        }
 
+       /* turn clock off to card before changing clock source */
+       writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
+
+       ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2);
+       ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK;
+       ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT;
+       writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2);
+
        /* reprogram default hardware configuration */
        writel(S3C64XX_SDHCI_CONTROL4_DRIVE_9mA,
                host->ioaddr + S3C64XX_SDHCI_CONTROL4);
@@ -254,17 +229,17 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)
 static unsigned int sdhci_s3c_get_min_clock(struct sdhci_host *host)
 {
        struct sdhci_s3c *ourhost = to_s3c(host);
-       unsigned int delta, min = UINT_MAX;
+       unsigned long rate, min = ULONG_MAX;
        int src;
 
        for (src = 0; src < MAX_BUS_CLK; src++) {
-               delta = sdhci_s3c_consider_clock(ourhost, src, 0);
-               if (delta == UINT_MAX)
+               rate = ourhost->clk_rates[src] / 256;
+               if (!rate)
                        continue;
-               /* delta is a negative value in this case */
-               if (-delta < min)
-                       min = -delta;
+               if (rate < min)
+                       min = rate;
        }
+
        return min;
 }
 
@@ -272,20 +247,44 @@ static unsigned int sdhci_s3c_get_min_clock(struct sdhci_host *host)
 static unsigned int sdhci_cmu_get_max_clock(struct sdhci_host *host)
 {
        struct sdhci_s3c *ourhost = to_s3c(host);
+       unsigned long rate, max = 0;
+       int src;
 
-       return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], UINT_MAX);
+       for (src = 0; src < MAX_BUS_CLK; src++) {
+               struct clk *clk;
+
+               clk = ourhost->clk_bus[src];
+               if (IS_ERR(clk))
+                       continue;
+
+               rate = clk_round_rate(clk, ULONG_MAX);
+               if (rate > max)
+                       max = rate;
+       }
+
+       return max;
 }
 
 /* sdhci_cmu_get_min_clock - callback to get minimal supported clock value. */
 static unsigned int sdhci_cmu_get_min_clock(struct sdhci_host *host)
 {
        struct sdhci_s3c *ourhost = to_s3c(host);
+       unsigned long rate, min = ULONG_MAX;
+       int src;
 
-       /*
-        * initial clock can be in the frequency range of
-        * 100KHz-400KHz, so we set it as max value.
-        */
-       return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], 400000);
+       for (src = 0; src < MAX_BUS_CLK; src++) {
+               struct clk *clk;
+
+               clk = ourhost->clk_bus[src];
+               if (IS_ERR(clk))
+                       continue;
+
+               rate = clk_round_rate(clk, 0);
+               if (rate < min)
+                       min = rate;
+       }
+
+       return min;
 }
 
 /* sdhci_cmu_set_clock - callback on clock change.*/
@@ -552,6 +551,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
        sc->host = host;
        sc->pdev = pdev;
        sc->pdata = pdata;
+       sc->cur_clk = -1;
 
        platform_set_drvdata(pdev, host);
 
@@ -566,25 +566,18 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
        clk_prepare_enable(sc->clk_io);
 
        for (clks = 0, ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
-               struct clk *clk;
                char name[14];
 
                snprintf(name, 14, "mmc_busclk.%d", ptr);
-               clk = devm_clk_get(dev, name);
-               if (IS_ERR(clk))
+               sc->clk_bus[ptr] = devm_clk_get(dev, name);
+               if (IS_ERR(sc->clk_bus[ptr]))
                        continue;
 
                clks++;
-               sc->clk_bus[ptr] = clk;
-
-               /*
-                * save current clock index to know which clock bus
-                * is used later in overriding functions.
-                */
-               sc->cur_clk = ptr;
+               sc->clk_rates[ptr] = clk_get_rate(sc->clk_bus[ptr]);
 
                dev_info(dev, "clock source %d: %s (%ld Hz)\n",
-                        ptr, name, clk_get_rate(clk));
+                               ptr, name, sc->clk_rates[ptr]);
        }
 
        if (clks == 0) {
@@ -593,10 +586,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
                goto err_no_busclks;
        }
 
-#ifndef CONFIG_PM_RUNTIME
-       clk_prepare_enable(sc->clk_bus[sc->cur_clk]);
-#endif
-
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        host->ioaddr = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(host->ioaddr)) {
@@ -709,10 +698,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
        return 0;
 
  err_req_regs:
-#ifndef CONFIG_PM_RUNTIME
-       clk_disable_unprepare(sc->clk_bus[sc->cur_clk]);
-#endif
-
  err_no_busclks:
        clk_disable_unprepare(sc->clk_io);
 
@@ -743,9 +728,6 @@ static int sdhci_s3c_remove(struct platform_device *pdev)
        pm_runtime_dont_use_autosuspend(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
-#ifndef CONFIG_PM_RUNTIME
-       clk_disable_unprepare(sc->clk_bus[sc->cur_clk]);
-#endif
        clk_disable_unprepare(sc->clk_io);
 
        sdhci_free_host(host);
@@ -779,7 +761,8 @@ static int sdhci_s3c_runtime_suspend(struct device *dev)
 
        ret = sdhci_runtime_suspend_host(host);
 
-       clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]);
+       if (ourhost->cur_clk >= 0)
+               clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]);
        clk_disable_unprepare(busclk);
        return ret;
 }
@@ -792,7 +775,8 @@ static int sdhci_s3c_runtime_resume(struct device *dev)
        int ret;
 
        clk_prepare_enable(busclk);
-       clk_prepare_enable(ourhost->clk_bus[ourhost->cur_clk]);
+       if (ourhost->cur_clk >= 0)
+               clk_prepare_enable(ourhost->clk_bus[ourhost->cur_clk]);
        ret = sdhci_runtime_resume_host(host);
        return ret;
 }
index 2dba9f8d1760313e3c47eeca756d6a59247ed924..0316dec3f0060e5ad7a8d83a35421018e210811c 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/sdhci-spear.h>
+#include <linux/mmc/slot-gpio.h>
 #include <linux/io.h>
 #include "sdhci.h"
 
@@ -40,36 +41,6 @@ static const struct sdhci_ops sdhci_pltfm_ops = {
        /* Nothing to do for now. */
 };
 
-/* gpio card detection interrupt handler */
-static irqreturn_t sdhci_gpio_irq(int irq, void *dev_id)
-{
-       struct platform_device *pdev = dev_id;
-       struct sdhci_host *host = platform_get_drvdata(pdev);
-       struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev);
-       unsigned long gpio_irq_type;
-       int val;
-
-       val = gpio_get_value(sdhci->data->card_int_gpio);
-
-       /* val == 1 -> card removed, val == 0 -> card inserted */
-       /* if card removed - set irq for low level, else vice versa */
-       gpio_irq_type = val ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH;
-       irq_set_irq_type(irq, gpio_irq_type);
-
-       if (sdhci->data->card_power_gpio >= 0) {
-               if (!sdhci->data->power_always_enb) {
-                       /* if card inserted, give power, otherwise remove it */
-                       val = sdhci->data->power_active_high ? !val : val ;
-                       gpio_set_value(sdhci->data->card_power_gpio, val);
-               }
-       }
-
-       /* inform sdhci driver about card insertion/removal */
-       tasklet_schedule(&host->card_tasklet);
-
-       return IRQ_HANDLED;
-}
-
 #ifdef CONFIG_OF
 static struct sdhci_plat_data *sdhci_probe_config_dt(struct platform_device *pdev)
 {
@@ -84,14 +55,12 @@ static struct sdhci_plat_data *sdhci_probe_config_dt(struct platform_device *pde
        /* If pdata is required */
        if (cd_gpio != -1) {
                pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-               if (!pdata) {
+               if (!pdata)
                        dev_err(&pdev->dev, "DT: kzalloc failed\n");
-                       return ERR_PTR(-ENOMEM);
-               }
+               else
+                       pdata->card_int_gpio = cd_gpio;
        }
 
-       pdata->card_int_gpio = cd_gpio;
-
        return pdata;
 }
 #else
@@ -107,41 +76,44 @@ static int sdhci_probe(struct platform_device *pdev)
        struct sdhci_host *host;
        struct resource *iomem;
        struct spear_sdhci *sdhci;
+       struct device *dev;
        int ret;
 
-       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!iomem) {
-               ret = -ENOMEM;
-               dev_dbg(&pdev->dev, "memory resource not defined\n");
+       dev = pdev->dev.parent ? pdev->dev.parent : &pdev->dev;
+       host = sdhci_alloc_host(dev, sizeof(*sdhci));
+       if (IS_ERR(host)) {
+               ret = PTR_ERR(host);
+               dev_dbg(&pdev->dev, "cannot allocate memory for sdhci\n");
                goto err;
        }
 
-       if (!devm_request_mem_region(&pdev->dev, iomem->start,
-                               resource_size(iomem), "spear-sdhci")) {
-               ret = -EBUSY;
-               dev_dbg(&pdev->dev, "cannot request region\n");
-               goto err;
+       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       host->ioaddr = devm_ioremap_resource(&pdev->dev, iomem);
+       if (IS_ERR(host->ioaddr)) {
+               ret = PTR_ERR(host->ioaddr);
+               dev_dbg(&pdev->dev, "unable to map iomem: %d\n", ret);
+               goto err_host;
        }
 
-       sdhci = devm_kzalloc(&pdev->dev, sizeof(*sdhci), GFP_KERNEL);
-       if (!sdhci) {
-               ret = -ENOMEM;
-               dev_dbg(&pdev->dev, "cannot allocate memory for sdhci\n");
-               goto err;
-       }
+       host->hw_name = "sdhci";
+       host->ops = &sdhci_pltfm_ops;
+       host->irq = platform_get_irq(pdev, 0);
+       host->quirks = SDHCI_QUIRK_BROKEN_ADMA;
+
+       sdhci = sdhci_priv(host);
 
        /* clk enable */
-       sdhci->clk = clk_get(&pdev->dev, NULL);
+       sdhci->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(sdhci->clk)) {
                ret = PTR_ERR(sdhci->clk);
                dev_dbg(&pdev->dev, "Error getting clock\n");
-               goto err;
+               goto err_host;
        }
 
        ret = clk_prepare_enable(sdhci->clk);
        if (ret) {
                dev_dbg(&pdev->dev, "Error enabling clock\n");
-               goto put_clk;
+               goto err_host;
        }
 
        ret = clk_set_rate(sdhci->clk, 50000000);
@@ -153,118 +125,42 @@ static int sdhci_probe(struct platform_device *pdev)
                sdhci->data = sdhci_probe_config_dt(pdev);
                if (IS_ERR(sdhci->data)) {
                        dev_err(&pdev->dev, "DT: Failed to get pdata\n");
-                       return -ENODEV;
+                       goto disable_clk;
                }
        } else {
                sdhci->data = dev_get_platdata(&pdev->dev);
        }
 
-       pdev->dev.platform_data = sdhci;
-
-       if (pdev->dev.parent)
-               host = sdhci_alloc_host(pdev->dev.parent, 0);
-       else
-               host = sdhci_alloc_host(&pdev->dev, 0);
-
-       if (IS_ERR(host)) {
-               ret = PTR_ERR(host);
-               dev_dbg(&pdev->dev, "error allocating host\n");
-               goto disable_clk;
-       }
-
-       host->hw_name = "sdhci";
-       host->ops = &sdhci_pltfm_ops;
-       host->irq = platform_get_irq(pdev, 0);
-       host->quirks = SDHCI_QUIRK_BROKEN_ADMA;
-
-       host->ioaddr = devm_ioremap(&pdev->dev, iomem->start,
-                       resource_size(iomem));
-       if (!host->ioaddr) {
-               ret = -ENOMEM;
-               dev_dbg(&pdev->dev, "failed to remap registers\n");
-               goto free_host;
+       /*
+        * It is optional to use GPIOs for sdhci card detection. If
+        * sdhci->data is NULL, then use original sdhci lines otherwise
+        * GPIO lines. We use the built-in GPIO support for this.
+        */
+       if (sdhci->data && sdhci->data->card_int_gpio >= 0) {
+               ret = mmc_gpio_request_cd(host->mmc,
+                                         sdhci->data->card_int_gpio, 0);
+               if (ret < 0) {
+                       dev_dbg(&pdev->dev,
+                               "failed to request card-detect gpio%d\n",
+                               sdhci->data->card_int_gpio);
+                       goto disable_clk;
+               }
        }
 
        ret = sdhci_add_host(host);
        if (ret) {
                dev_dbg(&pdev->dev, "error adding host\n");
-               goto free_host;
+               goto disable_clk;
        }
 
        platform_set_drvdata(pdev, host);
 
-       /*
-        * It is optional to use GPIOs for sdhci Power control & sdhci card
-        * interrupt detection. If sdhci->data is NULL, then use original sdhci
-        * lines otherwise GPIO lines.
-        * If GPIO is selected for power control, then power should be disabled
-        * after card removal and should be enabled when card insertion
-        * interrupt occurs
-        */
-       if (!sdhci->data)
-               return 0;
-
-       if (sdhci->data->card_power_gpio >= 0) {
-               int val = 0;
-
-               ret = devm_gpio_request(&pdev->dev,
-                               sdhci->data->card_power_gpio, "sdhci");
-               if (ret < 0) {
-                       dev_dbg(&pdev->dev, "gpio request fail: %d\n",
-                                       sdhci->data->card_power_gpio);
-                       goto set_drvdata;
-               }
-
-               if (sdhci->data->power_always_enb)
-                       val = sdhci->data->power_active_high;
-               else
-                       val = !sdhci->data->power_active_high;
-
-               ret = gpio_direction_output(sdhci->data->card_power_gpio, val);
-               if (ret) {
-                       dev_dbg(&pdev->dev, "gpio set direction fail: %d\n",
-                                       sdhci->data->card_power_gpio);
-                       goto set_drvdata;
-               }
-       }
-
-       if (sdhci->data->card_int_gpio >= 0) {
-               ret = devm_gpio_request(&pdev->dev, sdhci->data->card_int_gpio,
-                               "sdhci");
-               if (ret < 0) {
-                       dev_dbg(&pdev->dev, "gpio request fail: %d\n",
-                                       sdhci->data->card_int_gpio);
-                       goto set_drvdata;
-               }
-
-               ret = gpio_direction_input(sdhci->data->card_int_gpio);
-               if (ret) {
-                       dev_dbg(&pdev->dev, "gpio set direction fail: %d\n",
-                                       sdhci->data->card_int_gpio);
-                       goto set_drvdata;
-               }
-               ret = devm_request_irq(&pdev->dev,
-                               gpio_to_irq(sdhci->data->card_int_gpio),
-                               sdhci_gpio_irq, IRQF_TRIGGER_LOW,
-                               mmc_hostname(host->mmc), pdev);
-               if (ret) {
-                       dev_dbg(&pdev->dev, "gpio request irq fail: %d\n",
-                                       sdhci->data->card_int_gpio);
-                       goto set_drvdata;
-               }
-
-       }
-
        return 0;
 
-set_drvdata:
-       sdhci_remove_host(host, 1);
-free_host:
-       sdhci_free_host(host);
 disable_clk:
        clk_disable_unprepare(sdhci->clk);
-put_clk:
-       clk_put(sdhci->clk);
+err_host:
+       sdhci_free_host(host);
 err:
        dev_err(&pdev->dev, "spear-sdhci probe failed: %d\n", ret);
        return ret;
@@ -273,7 +169,7 @@ err:
 static int sdhci_remove(struct platform_device *pdev)
 {
        struct sdhci_host *host = platform_get_drvdata(pdev);
-       struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev);
+       struct spear_sdhci *sdhci = sdhci_priv(host);
        int dead = 0;
        u32 scratch;
 
@@ -282,9 +178,8 @@ static int sdhci_remove(struct platform_device *pdev)
                dead = 1;
 
        sdhci_remove_host(host, dead);
-       sdhci_free_host(host);
        clk_disable_unprepare(sdhci->clk);
-       clk_put(sdhci->clk);
+       sdhci_free_host(host);
 
        return 0;
 }
@@ -293,7 +188,7 @@ static int sdhci_remove(struct platform_device *pdev)
 static int sdhci_suspend(struct device *dev)
 {
        struct sdhci_host *host = dev_get_drvdata(dev);
-       struct spear_sdhci *sdhci = dev_get_platdata(dev);
+       struct spear_sdhci *sdhci = sdhci_priv(host);
        int ret;
 
        ret = sdhci_suspend_host(host);
@@ -306,7 +201,7 @@ static int sdhci_suspend(struct device *dev)
 static int sdhci_resume(struct device *dev)
 {
        struct sdhci_host *host = dev_get_drvdata(dev);
-       struct spear_sdhci *sdhci = dev_get_platdata(dev);
+       struct spear_sdhci *sdhci = sdhci_priv(host);
        int ret;
 
        ret = clk_enable(sdhci->clk);
index 9ddef47635418d4d18019a8a1433e67ca536628c..9a79fc4b60ca82bb7319fa34a3ae2d79d093833e 100644 (file)
@@ -675,12 +675,12 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
                return 0xE;
 
        /* Unspecified timeout, assume max */
-       if (!data && !cmd->cmd_timeout_ms)
+       if (!data && !cmd->busy_timeout)
                return 0xE;
 
        /* timeout in us */
        if (!data)
-               target_timeout = cmd->cmd_timeout_ms * 1000;
+               target_timeout = cmd->busy_timeout * 1000;
        else {
                target_timeout = data->timeout_ns / 1000;
                if (host->clock)
@@ -1019,8 +1019,8 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
        }
 
        timeout = jiffies;
-       if (!cmd->data && cmd->cmd_timeout_ms > 9000)
-               timeout += DIV_ROUND_UP(cmd->cmd_timeout_ms, 1000) * HZ + HZ;
+       if (!cmd->data && cmd->busy_timeout > 9000)
+               timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
        else
                timeout += 10 * HZ;
        mod_timer(&host->timer, timeout);
@@ -2026,12 +2026,11 @@ out:
                        host->tuning_count * HZ);
                /* Tuning mode 1 limits the maximum data length to 4MB */
                mmc->max_blk_count = (4 * 1024 * 1024) / mmc->max_blk_size;
-       } else {
+       } else if (host->flags & SDHCI_USING_RETUNING_TIMER) {
                host->flags &= ~SDHCI_NEEDS_RETUNING;
                /* Reload the new initial value for timer */
-               if (host->tuning_mode == SDHCI_TUNING_MODE_1)
-                       mod_timer(&host->tuning_timer, jiffies +
-                               host->tuning_count * HZ);
+               mod_timer(&host->tuning_timer, jiffies +
+                         host->tuning_count * HZ);
        }
 
        /*
@@ -2434,9 +2433,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 
        if (host->runtime_suspended) {
                spin_unlock(&host->lock);
-               pr_warning("%s: got irq while runtime suspended\n",
-                      mmc_hostname(host->mmc));
-               return IRQ_HANDLED;
+               return IRQ_NONE;
        }
 
        intmask = sdhci_readl(host, SDHCI_INT_STATUS);
@@ -2941,7 +2938,7 @@ int sdhci_add_host(struct sdhci_host *host)
        if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
                host->timeout_clk = mmc->f_max / 1000;
 
-       mmc->max_discard_to = (1 << 27) / host->timeout_clk;
+       mmc->max_busy_timeout = (1 << 27) / host->timeout_clk;
 
        mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
 
@@ -3020,7 +3017,8 @@ int sdhci_add_host(struct sdhci_host *host)
        } else if (caps[1] & SDHCI_SUPPORT_SDR50)
                mmc->caps |= MMC_CAP_UHS_SDR50;
 
-       if (caps[1] & SDHCI_SUPPORT_DDR50)
+       if ((caps[1] & SDHCI_SUPPORT_DDR50) &&
+               !(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50))
                mmc->caps |= MMC_CAP_UHS_DDR50;
 
        /* Does the host need tuning for SDR50? */
index 2d6ce257a2737c7a55b444d51858d392eda0f97b..91058dabd11afdbe443633140f2732462709d024 100644 (file)
@@ -37,6 +37,8 @@
 
 struct sh_mobile_sdhi_of_data {
        unsigned long tmio_flags;
+       unsigned long capabilities;
+       unsigned long capabilities2;
 };
 
 static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = {
@@ -45,6 +47,31 @@ static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = {
        },
 };
 
+static const struct sh_mobile_sdhi_of_data of_rcar_gen1_compatible = {
+       .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE,
+       .capabilities   = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
+};
+
+static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = {
+       .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE,
+       .capabilities   = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
+       .capabilities2  = MMC_CAP2_NO_MULTI_READ,
+};
+
+static const struct of_device_id sh_mobile_sdhi_of_match[] = {
+       { .compatible = "renesas,sdhi-shmobile" },
+       { .compatible = "renesas,sdhi-sh7372" },
+       { .compatible = "renesas,sdhi-sh73a0", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,sdhi-r8a73a4", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,sdhi-r8a7740", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, },
+       { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, },
+       { .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, },
+       { .compatible = "renesas,sdhi-r8a7791", .data = &of_rcar_gen2_compatible, },
+       {},
+};
+MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match);
+
 struct sh_mobile_sdhi {
        struct clk *clk;
        struct tmio_mmc_data mmc_data;
@@ -114,19 +141,6 @@ static const struct sh_mobile_sdhi_ops sdhi_ops = {
        .cd_wakeup = sh_mobile_sdhi_cd_wakeup,
 };
 
-static const struct of_device_id sh_mobile_sdhi_of_match[] = {
-       { .compatible = "renesas,sdhi-shmobile" },
-       { .compatible = "renesas,sdhi-sh7372" },
-       { .compatible = "renesas,sdhi-sh73a0", .data = &sh_mobile_sdhi_of_cfg[0], },
-       { .compatible = "renesas,sdhi-r8a73a4", .data = &sh_mobile_sdhi_of_cfg[0], },
-       { .compatible = "renesas,sdhi-r8a7740", .data = &sh_mobile_sdhi_of_cfg[0], },
-       { .compatible = "renesas,sdhi-r8a7778", .data = &sh_mobile_sdhi_of_cfg[0], },
-       { .compatible = "renesas,sdhi-r8a7779", .data = &sh_mobile_sdhi_of_cfg[0], },
-       { .compatible = "renesas,sdhi-r8a7790", .data = &sh_mobile_sdhi_of_cfg[0], },
-       {},
-};
-MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match);
-
 static int sh_mobile_sdhi_probe(struct platform_device *pdev)
 {
        const struct of_device_id *of_id =
@@ -212,6 +226,8 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
        if (of_id && of_id->data) {
                const struct sh_mobile_sdhi_of_data *of_data = of_id->data;
                mmc_data->flags |= of_data->tmio_flags;
+               mmc_data->capabilities |= of_data->capabilities;
+               mmc_data->capabilities2 |= of_data->capabilities2;
        }
 
        /* SD control register space size is 0x100, 0x200 for bus_shift=1 */
@@ -316,10 +332,10 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
 }
 
 static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
-       .suspend = tmio_mmc_host_suspend,
-       .resume = tmio_mmc_host_resume,
-       .runtime_suspend = tmio_mmc_host_runtime_suspend,
-       .runtime_resume = tmio_mmc_host_runtime_resume,
+       SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_host_suspend, tmio_mmc_host_resume)
+       SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
+                       tmio_mmc_host_runtime_resume,
+                       NULL)
 };
 
 static struct platform_driver sh_mobile_sdhi_driver = {
index 1900abb0423695ea06f9444376c62f2516b3b998..cfad844730d80195ff63172c3f69aed3e3fe1155 100644 (file)
 
 #include "tmio_mmc.h"
 
-#ifdef CONFIG_PM
-static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int tmio_mmc_suspend(struct device *dev)
 {
-       const struct mfd_cell *cell = mfd_get_cell(dev);
+       struct platform_device *pdev = to_platform_device(dev);
+       const struct mfd_cell *cell = mfd_get_cell(pdev);
        int ret;
 
-       ret = tmio_mmc_host_suspend(&dev->dev);
+       ret = tmio_mmc_host_suspend(dev);
 
        /* Tell MFD core it can disable us now.*/
        if (!ret && cell->disable)
-               cell->disable(dev);
+               cell->disable(pdev);
 
        return ret;
 }
 
-static int tmio_mmc_resume(struct platform_device *dev)
+static int tmio_mmc_resume(struct device *dev)
 {
-       const struct mfd_cell *cell = mfd_get_cell(dev);
+       struct platform_device *pdev = to_platform_device(dev);
+       const struct mfd_cell *cell = mfd_get_cell(pdev);
        int ret = 0;
 
        /* Tell the MFD core we are ready to be enabled */
        if (cell->resume)
-               ret = cell->resume(dev);
+               ret = cell->resume(pdev);
 
        if (!ret)
-               ret = tmio_mmc_host_resume(&dev->dev);
+               ret = tmio_mmc_host_resume(dev);
 
        return ret;
 }
-#else
-#define tmio_mmc_suspend NULL
-#define tmio_mmc_resume NULL
 #endif
 
 static int tmio_mmc_probe(struct platform_device *pdev)
@@ -134,15 +133,18 @@ static int tmio_mmc_remove(struct platform_device *pdev)
 
 /* ------------------- device registration ----------------------- */
 
+static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_suspend, tmio_mmc_resume)
+};
+
 static struct platform_driver tmio_mmc_driver = {
        .driver = {
                .name = "tmio-mmc",
                .owner = THIS_MODULE,
+               .pm = &tmio_mmc_dev_pm_ops,
        },
        .probe = tmio_mmc_probe,
        .remove = tmio_mmc_remove,
-       .suspend = tmio_mmc_suspend,
-       .resume = tmio_mmc_resume,
 };
 
 module_platform_driver(tmio_mmc_driver);
index aaa9c7e9e730ea072a639e00e64eaa382d15c794..100ffe0b2faf932399f3e47af4e61167b7a706ad 100644 (file)
@@ -162,16 +162,15 @@ static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
 }
 #endif
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 int tmio_mmc_host_suspend(struct device *dev);
 int tmio_mmc_host_resume(struct device *dev);
-#else
-#define tmio_mmc_host_suspend NULL
-#define tmio_mmc_host_resume NULL
 #endif
 
+#ifdef CONFIG_PM_RUNTIME
 int tmio_mmc_host_runtime_suspend(struct device *dev);
 int tmio_mmc_host_runtime_resume(struct device *dev);
+#endif
 
 static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr)
 {
index 8d8abf23a61120a03555a9c3a90e9d7571431c15..faf0924e71cb1d08a1fbe10645f713f8524a2bf8 100644 (file)
@@ -1142,7 +1142,7 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
 }
 EXPORT_SYMBOL(tmio_mmc_host_remove);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 int tmio_mmc_host_suspend(struct device *dev)
 {
        struct mmc_host *mmc = dev_get_drvdata(dev);
@@ -1165,9 +1165,9 @@ int tmio_mmc_host_resume(struct device *dev)
        return 0;
 }
 EXPORT_SYMBOL(tmio_mmc_host_resume);
+#endif
 
-#endif /* CONFIG_PM */
-
+#ifdef CONFIG_PM_RUNTIME
 int tmio_mmc_host_runtime_suspend(struct device *dev)
 {
        return 0;
@@ -1184,5 +1184,6 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
        return 0;
 }
 EXPORT_SYMBOL(tmio_mmc_host_runtime_resume);
+#endif
 
 MODULE_LICENSE("GPL v2");
index c0105a2e269a7b89128b3dc1c761118c4f9837c8..d2c386f09d69f4edd20b0ac778624b40f826f1e3 100644 (file)
@@ -504,7 +504,7 @@ static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id
                ret = -ENOMEM;
                goto err;
        }
-       ushc->csw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL);
+       ushc->csw = kzalloc(sizeof(struct ushc_csw), GFP_KERNEL);
        if (ushc->csw == NULL) {
                ret = -ENOMEM;
                goto err;
index e902ed7846b0544012a289368b187d541ced1969..498d1f79908574144408536fa9488ad5f0d0c39f 100644 (file)
@@ -757,7 +757,7 @@ static int wmt_mci_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        const struct of_device_id *of_id =
                of_match_device(wmt_mci_dt_ids, &pdev->dev);
-       const struct wmt_mci_caps *wmt_caps = of_id->data;
+       const struct wmt_mci_caps *wmt_caps;
        int ret;
        int regular_irq, dma_irq;
 
@@ -766,6 +766,8 @@ static int wmt_mci_probe(struct platform_device *pdev)
                return -EFAULT;
        }
 
+       wmt_caps = of_id->data;
+
        if (!np) {
                dev_err(&pdev->dev, "Missing SDMMC description in devicetree\n");
                return -EFAULT;
index 1cd8584a7b887ffd9fd8fd0089c8148dba595064..903eb37f047a916d510685b7e203a4ecdb680cbd 100644 (file)
@@ -392,6 +392,15 @@ config REGULATOR_PALMAS
          on the muxing. This is handled automatically in the driver by
          reading the mux info from OTP.
 
+config REGULATOR_PBIAS
+       tristate "PBIAS OMAP regulator driver"
+       depends on (ARCH_OMAP || COMPILE_TEST) && MFD_SYSCON
+       help
+        Say y here to support pbias regulator for mmc1:SD card i/o
+        on OMAP SoCs.
+        This driver provides support for OMAP pbias modelled
+        regulators.
+
 config REGULATOR_PCAP
        tristate "Motorola PCAP2 regulator driver"
        depends on EZX_PCAP
index f0fe0c50b59c23ffc36680536f17bf0486e4226d..12ef277a48b47c55bdceee69f8f637bc929522f8 100644 (file)
@@ -55,6 +55,7 @@ obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
 obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
 obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
 obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-regulator.o
+obj-$(CONFIG_REGULATOR_PBIAS) += pbias-regulator.o
 obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
 obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
 obj-$(CONFIG_REGULATOR_RC5T583)  += rc5t583-regulator.o
diff --git a/drivers/regulator/pbias-regulator.c b/drivers/regulator/pbias-regulator.c
new file mode 100644 (file)
index 0000000..ded3b35
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * pbias-regulator.c
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Balaji T K <balajitk@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+struct pbias_reg_info {
+       u32 enable;
+       u32 enable_mask;
+       u32 vmode;
+       unsigned int enable_time;
+       char *name;
+};
+
+struct pbias_regulator_data {
+       struct regulator_desc desc;
+       void __iomem *pbias_addr;
+       unsigned int pbias_reg;
+       struct regulator_dev *dev;
+       struct regmap *syscon;
+       const struct pbias_reg_info *info;
+       int voltage;
+};
+
+static int pbias_regulator_set_voltage(struct regulator_dev *dev,
+                       int min_uV, int max_uV, unsigned *selector)
+{
+       struct pbias_regulator_data *data = rdev_get_drvdata(dev);
+       const struct pbias_reg_info *info = data->info;
+       int ret, vmode;
+
+       if (min_uV <= 1800000)
+               vmode = 0;
+       else if (min_uV > 1800000)
+               vmode = info->vmode;
+
+       ret = regmap_update_bits(data->syscon, data->pbias_reg,
+                                               info->vmode, vmode);
+
+       return ret;
+}
+
+static int pbias_regulator_get_voltage(struct regulator_dev *rdev)
+{
+       struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
+       const struct pbias_reg_info *info = data->info;
+       int value, voltage;
+
+       regmap_read(data->syscon, data->pbias_reg, &value);
+       value &= info->vmode;
+
+       voltage = value ? 3000000 : 1800000;
+
+       return voltage;
+}
+
+static int pbias_regulator_enable(struct regulator_dev *rdev)
+{
+       struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
+       const struct pbias_reg_info *info = data->info;
+       int ret;
+
+       ret = regmap_update_bits(data->syscon, data->pbias_reg,
+                                       info->enable_mask, info->enable);
+
+       return ret;
+}
+
+static int pbias_regulator_disable(struct regulator_dev *rdev)
+{
+       struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
+       const struct pbias_reg_info *info = data->info;
+       int ret;
+
+       ret = regmap_update_bits(data->syscon, data->pbias_reg,
+                                               info->enable_mask, 0);
+       return ret;
+}
+
+static int pbias_regulator_is_enable(struct regulator_dev *rdev)
+{
+       struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
+       const struct pbias_reg_info *info = data->info;
+       int value;
+
+       regmap_read(data->syscon, data->pbias_reg, &value);
+
+       return (value & info->enable_mask) == info->enable_mask;
+}
+
+static struct regulator_ops pbias_regulator_voltage_ops = {
+       .set_voltage    = pbias_regulator_set_voltage,
+       .get_voltage    = pbias_regulator_get_voltage,
+       .enable         = pbias_regulator_enable,
+       .disable        = pbias_regulator_disable,
+       .is_enabled     = pbias_regulator_is_enable,
+};
+
+static const struct pbias_reg_info pbias_mmc_omap2430 = {
+       .enable = BIT(1),
+       .enable_mask = BIT(1),
+       .vmode = BIT(0),
+       .enable_time = 100,
+       .name = "pbias_mmc_omap2430"
+};
+
+static const struct pbias_reg_info pbias_sim_omap3 = {
+       .enable = BIT(9),
+       .enable_mask = BIT(9),
+       .vmode = BIT(8),
+       .enable_time = 100,
+       .name = "pbias_sim_omap3"
+};
+
+static const struct pbias_reg_info pbias_mmc_omap4 = {
+       .enable = BIT(26) | BIT(22),
+       .enable_mask = BIT(26) | BIT(25) | BIT(22),
+       .vmode = BIT(21),
+       .enable_time = 100,
+       .name = "pbias_mmc_omap4"
+};
+
+static const struct pbias_reg_info pbias_mmc_omap5 = {
+       .enable = BIT(27) | BIT(26),
+       .enable_mask = BIT(27) | BIT(25) | BIT(26),
+       .vmode = BIT(21),
+       .enable_time = 100,
+       .name = "pbias_mmc_omap5"
+};
+
+static struct of_regulator_match pbias_matches[] = {
+       { .name = "pbias_mmc_omap2430", .driver_data = (void *)&pbias_mmc_omap2430},
+       { .name = "pbias_sim_omap3", .driver_data = (void *)&pbias_sim_omap3},
+       { .name = "pbias_mmc_omap4", .driver_data = (void *)&pbias_mmc_omap4},
+       { .name = "pbias_mmc_omap5", .driver_data = (void *)&pbias_mmc_omap5},
+};
+#define PBIAS_NUM_REGS ARRAY_SIZE(pbias_matches)
+
+static const struct of_device_id pbias_of_match[] = {
+       { .compatible = "ti,pbias-omap", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, pbias_of_match);
+
+static int pbias_regulator_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct pbias_regulator_data *drvdata;
+       struct resource *res;
+       struct regulator_config cfg = { };
+       struct regmap *syscon;
+       const struct pbias_reg_info *info;
+       int ret = 0;
+       int count, idx, data_idx = 0;
+
+       count = of_regulator_match(&pdev->dev, np, pbias_matches,
+                                               PBIAS_NUM_REGS);
+       if (count < 0)
+               return count;
+
+       drvdata = devm_kzalloc(&pdev->dev, sizeof(struct pbias_regulator_data)
+                              * count, GFP_KERNEL);
+       if (drvdata == NULL) {
+               dev_err(&pdev->dev, "Failed to allocate device data\n");
+               return -ENOMEM;
+       }
+
+       syscon = syscon_regmap_lookup_by_phandle(np, "syscon");
+       if (IS_ERR(syscon))
+               return PTR_ERR(syscon);
+
+       cfg.dev = &pdev->dev;
+
+       for (idx = 0; idx < PBIAS_NUM_REGS && data_idx < count; idx++) {
+               if (!pbias_matches[idx].init_data ||
+                       !pbias_matches[idx].of_node)
+                       continue;
+
+               info = pbias_matches[idx].driver_data;
+               if (!info)
+                       return -ENODEV;
+
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               if (!res)
+                       return -EINVAL;
+
+               drvdata[data_idx].pbias_reg = res->start;
+               drvdata[data_idx].syscon = syscon;
+               drvdata[data_idx].info = info;
+               drvdata[data_idx].desc.name = info->name;
+               drvdata[data_idx].desc.owner = THIS_MODULE;
+               drvdata[data_idx].desc.type = REGULATOR_VOLTAGE;
+               drvdata[data_idx].desc.ops = &pbias_regulator_voltage_ops;
+               drvdata[data_idx].desc.n_voltages = 2;
+               drvdata[data_idx].desc.enable_time = info->enable_time;
+
+               cfg.init_data = pbias_matches[idx].init_data;
+               cfg.driver_data = &drvdata[data_idx];
+               cfg.of_node = pbias_matches[idx].of_node;
+
+               drvdata[data_idx].dev = devm_regulator_register(&pdev->dev,
+                                       &drvdata[data_idx].desc, &cfg);
+               if (IS_ERR(drvdata[data_idx].dev)) {
+                       ret = PTR_ERR(drvdata[data_idx].dev);
+                       dev_err(&pdev->dev,
+                               "Failed to register regulator: %d\n", ret);
+                       goto err_regulator;
+               }
+               data_idx++;
+       }
+
+       platform_set_drvdata(pdev, drvdata);
+
+err_regulator:
+       return ret;
+}
+
+static struct platform_driver pbias_regulator_driver = {
+       .probe          = pbias_regulator_probe,
+       .driver         = {
+               .name           = "pbias-regulator",
+               .owner          = THIS_MODULE,
+               .of_match_table = of_match_ptr(pbias_of_match),
+       },
+};
+
+module_platform_driver(pbias_regulator_driver);
+
+MODULE_AUTHOR("Balaji T K <balajitk@ti.com>");
+MODULE_DESCRIPTION("pbias voltage regulator");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pbias-regulator");
index 443176ee1ab04e1f9d2788b51d700eb2a913610c..7c36cc55d2c79b8fe90cdec3898751ac4988165f 100644 (file)
@@ -45,6 +45,7 @@ struct platform_device;
 struct rtsx_slot {
        struct platform_device  *p_dev;
        void                    (*card_event)(struct platform_device *p_dev);
+       void                    (*done_transfer)(struct platform_device *p_dev);
 };
 
 #endif
index 0ce7721055081b3a75e16ea9b485c01b7e83a1f8..8d6bbd609ad9b6142357b0203bf7e0250e923ae4 100644 (file)
 #define HOST_TO_DEVICE         0
 #define DEVICE_TO_HOST         1
 
-#define MAX_PHASE              31
+#define RTSX_PHASE_MAX         32
 #define RX_TUNING_CNT          3
 
 /* SG descriptor */
@@ -943,6 +943,12 @@ void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr);
 int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout);
 int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
                int num_sg, bool read, int timeout);
+int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+               int num_sg, bool read);
+int rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+               int num_sg, bool read);
+int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+               int sg_count, bool read);
 int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len);
 int rtsx_pci_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len);
 int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card);
index 87079fc38011ccaca33f4ef6ad7d5d055ed3087e..f206e29f94d72cb74afbcf10bd14111676424c80 100644 (file)
@@ -95,7 +95,7 @@ struct mmc_command {
  *              actively failing requests
  */
 
-       unsigned int            cmd_timeout_ms; /* in milliseconds */
+       unsigned int            busy_timeout;   /* busy detect timeout in ms */
        /* Set this flag only for blocking sanitize request */
        bool                    sanitize_busy;
 
@@ -152,7 +152,7 @@ extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
        struct mmc_command *, int);
 extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
 extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool,
-                       bool);
+                       bool, bool);
 extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
 extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
 
index 99f5709ac343df3d6c5b7bbda636eeeb42c4e14c..cb61ea4d69455366768fa04bc2263c65795bc92f 100644 (file)
@@ -264,15 +264,12 @@ struct mmc_host {
        u32                     caps2;          /* More host capabilities */
 
 #define MMC_CAP2_BOOTPART_NOACC        (1 << 0)        /* Boot partition no access */
-#define MMC_CAP2_CACHE_CTRL    (1 << 1)        /* Allow cache control */
 #define MMC_CAP2_FULL_PWR_CYCLE        (1 << 2)        /* Can do full power cycle */
 #define MMC_CAP2_NO_MULTI_READ (1 << 3)        /* Multiblock reads don't work */
-#define MMC_CAP2_NO_SLEEP_CMD  (1 << 4)        /* Don't allow sleep command */
 #define MMC_CAP2_HS200_1_8V_SDR        (1 << 5)        /* can support */
 #define MMC_CAP2_HS200_1_2V_SDR        (1 << 6)        /* can support */
 #define MMC_CAP2_HS200         (MMC_CAP2_HS200_1_8V_SDR | \
                                 MMC_CAP2_HS200_1_2V_SDR)
-#define MMC_CAP2_BROKEN_VOLTAGE        (1 << 7)        /* Use the broken voltage */
 #define MMC_CAP2_HC_ERASE_SZ   (1 << 9)        /* High-capacity erase size */
 #define MMC_CAP2_CD_ACTIVE_HIGH        (1 << 10)       /* Card-detect signal active high */
 #define MMC_CAP2_RO_ACTIVE_HIGH        (1 << 11)       /* Write-protect signal active high */
@@ -281,7 +278,6 @@ struct mmc_host {
 #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 */
-#define MMC_CAP2_SANITIZE      (1 << 15)               /* Support Sanitize */
 
        mmc_pm_flag_t           pm_caps;        /* supported pm features */
 
@@ -304,7 +300,7 @@ struct mmc_host {
        unsigned int            max_req_size;   /* maximum number of bytes in one req */
        unsigned int            max_blk_size;   /* maximum size of one mmc block */
        unsigned int            max_blk_count;  /* maximum number of blocks in one req */
-       unsigned int            max_discard_to; /* max. discard timeout in ms */
+       unsigned int            max_busy_timeout; /* max busy timeout in ms */
 
        /* private data */
        spinlock_t              lock;           /* lock for claim and bus ops */
@@ -388,8 +384,6 @@ int mmc_power_restore_host(struct mmc_host *host);
 void mmc_detect_change(struct mmc_host *, unsigned long delay);
 void mmc_request_done(struct mmc_host *, struct mmc_request *);
 
-int mmc_cache_ctrl(struct mmc_host *, u8);
-
 static inline void mmc_signal_sdio_irq(struct mmc_host *host)
 {
        host->ops->enable_sdio_irq(host, 0);
@@ -424,12 +418,9 @@ static inline int mmc_regulator_get_supply(struct mmc_host *mmc)
 
 int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *);
 
-/* Module parameter */
-extern bool mmc_assume_removable;
-
 static inline int mmc_card_is_removable(struct mmc_host *host)
 {
-       return !(host->caps & MMC_CAP_NONREMOVABLE) && mmc_assume_removable;
+       return !(host->caps & MMC_CAP_NONREMOVABLE);
 }
 
 static inline int mmc_card_keep_power(struct mmc_host *host)
index e78c0e236e9dce163fc8df904698f43c455fcf85..8cc095a76cf8e8d7e5ddb75dc5d08f12c5159583 100644 (file)
 /*
  * struct sdhci_plat_data: spear sdhci platform data structure
  *
- * @card_power_gpio: gpio pin for enabling/disabling power to sdhci socket
- * @power_active_high: if set, enable power to sdhci socket by setting
- *                     card_power_gpio
- * @power_always_enb: If set, then enable power on probe, otherwise enable only
- *                     on card insertion and disable on card removal.
  * card_int_gpio: gpio pin used for card detection
  */
 struct sdhci_plat_data {
-       int card_power_gpio;
-       int power_active_high;
-       int power_always_enb;
        int card_int_gpio;
 };
 
index 362927c48f978904d1eb86c57e34e5f267f93f10..7be12b883485965beea0eecf10bf0abd69119b89 100644 (file)
@@ -100,6 +100,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_BROKEN_HOST_CONTROL               (1<<5)
 /* Controller does not support HS200 */
 #define SDHCI_QUIRK2_BROKEN_HS200                      (1<<6)
+/* Controller does not support DDR50 */
+#define SDHCI_QUIRK2_BROKEN_DDR50                      (1<<7)
 
        int irq;                /* Device IRQ */
        void __iomem *ioaddr;   /* Mapped address */
index b0c73e4cacea1484fe4790a49514cb004e0af024..d2433381e8286573cda47c579660562196644c83 100644 (file)
@@ -22,4 +22,10 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio,
                        unsigned int debounce);
 void mmc_gpio_free_cd(struct mmc_host *host);
 
+int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
+                        unsigned int idx, bool override_active_level,
+                        unsigned int debounce);
+void mmc_gpiod_free_cd(struct mmc_host *host);
+void mmc_gpiod_request_cd_irq(struct mmc_host *host);
+
 #endif
index ffcd9e3a6a7e81578f22624d839278c4906f3a99..55aa873c93963011e5f098eed66fc1f012ec88e6 100644 (file)
@@ -1,8 +1,5 @@
-/*
- *  arch/arm/include/asm/mach/mmc.h
- */
-#ifndef ASMARM_MACH_MMC_H
-#define ASMARM_MACH_MMC_H
+#ifndef __MMC_MSM_SDCC_H
+#define __MMC_MSM_SDCC_H
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
index 1190efedcb9487a6913bfef9f6b8be06b608845b..d02704cd36950c5e92c356cb968d96ef0f668b3b 100644 (file)
@@ -1,13 +1,11 @@
 /*
- * arch/arm/plat-orion/include/plat/mvsdio.h
- *
  * This file is licensed under the terms of the GNU General Public
  * License version 2.  This program is licensed "as is" without any
  * warranty of any kind, whether express or implied.
  */
 
-#ifndef __MACH_MVSDIO_H
-#define __MACH_MVSDIO_H
+#ifndef __MMC_MVSDIO_H
+#define __MMC_MVSDIO_H
 
 #include <linux/mbus.h>