Browse Source

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

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
  ...
Linus Torvalds 11 years ago
parent
commit
97e18dc007
63 changed files with 2577 additions and 1166 deletions
  1. 9 0
      Documentation/devicetree/bindings/mmc/mmc.txt
  2. 55 0
      Documentation/devicetree/bindings/mmc/sdhci-msm.txt
  3. 16 1
      Documentation/devicetree/bindings/mmc/sdhci-pxa.txt
  4. 1 0
      Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
  5. 27 0
      Documentation/devicetree/bindings/regulator/pbias-regulator.txt
  6. 1 0
      MAINTAINERS
  7. 17 0
      arch/arm/boot/dts/dra7.dtsi
  8. 17 0
      arch/arm/boot/dts/omap2430.dtsi
  9. 23 0
      arch/arm/boot/dts/omap3-ldp.dts
  10. 17 0
      arch/arm/boot/dts/omap3.dtsi
  11. 17 0
      arch/arm/boot/dts/omap4.dtsi
  12. 17 0
      arch/arm/boot/dts/omap5.dtsi
  13. 2 0
      arch/arm/configs/omap2plus_defconfig
  14. 91 41
      drivers/mfd/rtsx_pcr.c
  15. 115 66
      drivers/mmc/card/block.c
  16. 0 15
      drivers/mmc/core/Kconfig
  17. 2 10
      drivers/mmc/core/bus.c
  18. 15 72
      drivers/mmc/core/core.c
  19. 18 0
      drivers/mmc/core/host.c
  20. 28 37
      drivers/mmc/core/mmc.c
  21. 41 23
      drivers/mmc/core/mmc_ops.c
  22. 1 22
      drivers/mmc/core/sd.c
  23. 140 40
      drivers/mmc/core/slot-gpio.c
  24. 14 9
      drivers/mmc/host/Kconfig
  25. 1 1
      drivers/mmc/host/Makefile
  26. 2 2
      drivers/mmc/host/davinci_mmc.c
  27. 2 0
      drivers/mmc/host/dw_mmc-k3.c
  28. 9 3
      drivers/mmc/host/dw_mmc-pltfm.c
  29. 0 138
      drivers/mmc/host/dw_mmc-socfpga.c
  30. 1 1
      drivers/mmc/host/dw_mmc.c
  31. 2 1
      drivers/mmc/host/dw_mmc.h
  32. 45 9
      drivers/mmc/host/mmci.c
  33. 2 0
      drivers/mmc/host/mmci.h
  34. 36 57
      drivers/mmc/host/omap.c
  35. 166 76
      drivers/mmc/host/omap_hsmmc.c
  36. 382 147
      drivers/mmc/host/rtsx_pci_sdmmc.c
  37. 18 62
      drivers/mmc/host/sdhci-acpi.c
  38. 36 3
      drivers/mmc/host/sdhci-bcm-kona.c
  39. 1 1
      drivers/mmc/host/sdhci-dove.c
  40. 618 0
      drivers/mmc/host/sdhci-msm.c
  41. 20 0
      drivers/mmc/host/sdhci-pci.c
  42. 68 0
      drivers/mmc/host/sdhci-pxav3.c
  43. 77 93
      drivers/mmc/host/sdhci-s3c.c
  44. 47 152
      drivers/mmc/host/sdhci-spear.c
  45. 11 13
      drivers/mmc/host/sdhci.c
  46. 33 17
      drivers/mmc/host/sh_mobile_sdhi.c
  47. 16 14
      drivers/mmc/host/tmio_mmc.c
  48. 3 4
      drivers/mmc/host/tmio_mmc.h
  49. 4 3
      drivers/mmc/host/tmio_mmc_pio.c
  50. 1 1
      drivers/mmc/host/ushc.c
  51. 3 1
      drivers/mmc/host/wmt-sdmmc.c
  52. 9 0
      drivers/regulator/Kconfig
  53. 1 0
      drivers/regulator/Makefile
  54. 255 0
      drivers/regulator/pbias-regulator.c
  55. 1 0
      include/linux/mfd/rtsx_common.h
  56. 7 1
      include/linux/mfd/rtsx_pci.h
  57. 2 2
      include/linux/mmc/core.h
  58. 2 11
      include/linux/mmc/host.h
  59. 0 8
      include/linux/mmc/sdhci-spear.h
  60. 2 0
      include/linux/mmc/sdhci.h
  61. 6 0
      include/linux/mmc/slot-gpio.h
  62. 2 5
      include/linux/platform_data/mmc-msm_sdcc.h
  63. 2 4
      include/linux/platform_data/mmc-mvsdio.h

+ 9 - 0
Documentation/devicetree/bindings/mmc/mmc.txt

@@ -26,9 +26,18 @@ Optional properties:
   this system, even if the controller claims it is.
   this system, even if the controller claims it is.
 - cap-sd-highspeed: SD high-speed timing is supported
 - cap-sd-highspeed: SD high-speed timing is supported
 - cap-mmc-highspeed: MMC 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-power-off-card: powering off the card is safe
 - cap-sdio-irq: enable SDIO IRQ signalling on this interface
 - cap-sdio-irq: enable SDIO IRQ signalling on this interface
 - full-pwr-cycle: full power cycle of the card is supported
 - 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
 *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"
 polarity properties, we have to fix the meaning of the "normal" and "inverted"

+ 55 - 0
Documentation/devicetree/bindings/mmc/sdhci-msm.txt

@@ -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";
+	};

+ 16 - 1
Documentation/devicetree/bindings/mmc/sdhci-pxa.txt

@@ -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.
 and the properties used by the sdhci-pxav2 and sdhci-pxav3 drivers.
 
 
 Required properties:
 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:
 Optional properties:
 - mrvl,clk-delay-cycles: Specify a number of cycles to delay for tuning.
 - mrvl,clk-delay-cycles: Specify a number of cycles to delay for tuning.
@@ -19,3 +26,11 @@ sdhci@d4280800 {
 	non-removable;
 	non-removable;
 	mrvl,clk-delay-cycles = <31>;
 	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>;
+};

+ 1 - 0
Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt

@@ -10,6 +10,7 @@ Required properties:
 - compatible:
 - compatible:
  Should be "ti,omap2-hsmmc", for OMAP2 controllers
  Should be "ti,omap2-hsmmc", for OMAP2 controllers
  Should be "ti,omap3-hsmmc", for OMAP3 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
  Should be "ti,omap4-hsmmc", for OMAP4 controllers
 - ti,hwmods: Must be "mmc<n>", n is controller instance starting 1
 - ti,hwmods: Must be "mmc<n>", n is controller instance starting 1
 
 

+ 27 - 0
Documentation/devicetree/bindings/regulator/pbias-regulator.txt

@@ -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>;
+			};

+ 1 - 0
MAINTAINERS

@@ -5930,6 +5930,7 @@ F:	include/linux/mfd/
 
 
 MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
 MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
 M:	Chris Ball <chris@printf.net>
 M:	Chris Ball <chris@printf.net>
+M:	Ulf Hansson <ulf.hansson@linaro.org>
 L:	linux-mmc@vger.kernel.org
 L:	linux-mmc@vger.kernel.org
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git
 S:	Maintained
 S:	Maintained

+ 17 - 0
arch/arm/boot/dts/dra7.dtsi

@@ -154,6 +154,22 @@
 			ti,hwmods = "counter_32k";
 			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 {
 		dra7_pmx_core: pinmux@4a003400 {
 			compatible = "pinctrl-single";
 			compatible = "pinctrl-single";
 			reg = <0x4a003400 0x0464>;
 			reg = <0x4a003400 0x0464>;
@@ -543,6 +559,7 @@
 			dmas = <&sdma 61>, <&sdma 62>;
 			dmas = <&sdma 61>, <&sdma 62>;
 			dma-names = "tx", "rx";
 			dma-names = "tx", "rx";
 			status = "disabled";
 			status = "disabled";
+			pbias-supply = <&pbias_mmc_reg>;
 		};
 		};
 
 
 		mmc2: mmc@480b4000 {
 		mmc2: mmc@480b4000 {

+ 17 - 0
arch/arm/boot/dts/omap2430.dtsi

@@ -29,6 +29,22 @@
 			pinctrl-single,function-mask = <0x3f>;
 			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 {
 		gpio1: gpio@4900c000 {
 			compatible = "ti,omap2-gpio";
 			compatible = "ti,omap2-gpio";
 			reg = <0x4900c000 0x200>;
 			reg = <0x4900c000 0x200>;
@@ -188,6 +204,7 @@
 			ti,dual-volt;
 			ti,dual-volt;
 			dmas = <&sdma 61>, <&sdma 62>;
 			dmas = <&sdma 61>, <&sdma 62>;
 			dma-names = "tx", "rx";
 			dma-names = "tx", "rx";
+			pbias-supply = <&pbias_mmc_reg>;
 		};
 		};
 
 
 		mmc2: mmc@480b4000 {
 		mmc2: mmc@480b4000 {

+ 23 - 0
arch/arm/boot/dts/omap3-ldp.dts

@@ -174,8 +174,20 @@
 };
 };
 
 
 &mmc1 {
 &mmc1 {
+	/* See 35xx errata 2.1.1.128 in SPRZ278F */
+	compatible = "ti,omap3-pre-es3-hsmmc";
 	vmmc-supply = <&vmmc1>;
 	vmmc-supply = <&vmmc1>;
 	bus-width = <4>;
 	bus-width = <4>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc1_pins>;
+};
+
+&mmc2 {
+	status="disabled";
+};
+
+&mmc3 {
+	status="disabled";
 };
 };
 
 
 &omap3_pmx_core {
 &omap3_pmx_core {
@@ -209,6 +221,17 @@
 			0x174 (PIN_OUTPUT | MUX_MODE0)	/* hsusb0_stp.hsusb0_stp */
 			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 {
 &usb_otg_hs {

+ 17 - 0
arch/arm/boot/dts/omap3.dtsi

@@ -181,6 +181,22 @@
 			pinctrl-single,function-mask = <0xff1f>;
 			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 {
 		gpio1: gpio@48310000 {
 			compatible = "ti,omap3-gpio";
 			compatible = "ti,omap3-gpio";
 			reg = <0x48310000 0x200>;
 			reg = <0x48310000 0x200>;
@@ -395,6 +411,7 @@
 			ti,dual-volt;
 			ti,dual-volt;
 			dmas = <&sdma 61>, <&sdma 62>;
 			dmas = <&sdma 61>, <&sdma 62>;
 			dma-names = "tx", "rx";
 			dma-names = "tx", "rx";
+			pbias-supply = <&pbias_mmc_reg>;
 		};
 		};
 
 
 		mmc2: mmc@480b4000 {
 		mmc2: mmc@480b4000 {

+ 17 - 0
arch/arm/boot/dts/omap4.dtsi

@@ -191,6 +191,22 @@
 			pinctrl-single,function-mask = <0x7fff>;
 			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 {
 		sdma: dma-controller@4a056000 {
 			compatible = "ti,omap4430-sdma";
 			compatible = "ti,omap4430-sdma";
 			reg = <0x4a056000 0x1000>;
 			reg = <0x4a056000 0x1000>;
@@ -427,6 +443,7 @@
 			ti,needs-special-reset;
 			ti,needs-special-reset;
 			dmas = <&sdma 61>, <&sdma 62>;
 			dmas = <&sdma 61>, <&sdma 62>;
 			dma-names = "tx", "rx";
 			dma-names = "tx", "rx";
+			pbias-supply = <&pbias_mmc_reg>;
 		};
 		};
 
 
 		mmc2: mmc@480b4000 {
 		mmc2: mmc@480b4000 {

+ 17 - 0
arch/arm/boot/dts/omap5.dtsi

@@ -198,6 +198,22 @@
 			pinctrl-single,function-mask = <0x7fff>;
 			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 {
 		sdma: dma-controller@4a056000 {
 			compatible = "ti,omap4430-sdma";
 			compatible = "ti,omap4430-sdma";
 			reg = <0x4a056000 0x1000>;
 			reg = <0x4a056000 0x1000>;
@@ -480,6 +496,7 @@
 			ti,needs-special-reset;
 			ti,needs-special-reset;
 			dmas = <&sdma 61>, <&sdma 62>;
 			dmas = <&sdma 61>, <&sdma 62>;
 			dma-names = "tx", "rx";
 			dma-names = "tx", "rx";
+			pbias-supply = <&pbias_mmc_reg>;
 		};
 		};
 
 
 		mmc2: mmc@480b4000 {
 		mmc2: mmc@480b4000 {

+ 2 - 0
arch/arm/configs/omap2plus_defconfig

@@ -170,6 +170,7 @@ CONFIG_DRA752_THERMAL=y
 CONFIG_WATCHDOG=y
 CONFIG_WATCHDOG=y
 CONFIG_OMAP_WATCHDOG=y
 CONFIG_OMAP_WATCHDOG=y
 CONFIG_TWL4030_WATCHDOG=y
 CONFIG_TWL4030_WATCHDOG=y
+CONFIG_MFD_SYSCON=y
 CONFIG_MFD_PALMAS=y
 CONFIG_MFD_PALMAS=y
 CONFIG_MFD_TPS65217=y
 CONFIG_MFD_TPS65217=y
 CONFIG_MFD_TPS65910=y
 CONFIG_MFD_TPS65910=y
@@ -181,6 +182,7 @@ CONFIG_REGULATOR_TPS6507X=y
 CONFIG_REGULATOR_TPS65217=y
 CONFIG_REGULATOR_TPS65217=y
 CONFIG_REGULATOR_TPS65910=y
 CONFIG_REGULATOR_TPS65910=y
 CONFIG_REGULATOR_TWL4030=y
 CONFIG_REGULATOR_TWL4030=y
+CONFIG_REGULATOR_PBIAS=y
 CONFIG_FB=y
 CONFIG_FB=y
 CONFIG_FIRMWARE_EDID=y
 CONFIG_FIRMWARE_EDID=y
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_FB_MODE_HELPERS=y

+ 91 - 41
drivers/mfd/rtsx_pcr.c

@@ -338,58 +338,28 @@ int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
 		int num_sg, bool read, int timeout)
 		int num_sg, bool read, int timeout)
 {
 {
 	struct completion trans_done;
 	struct completion trans_done;
-	u8 dir;
-	int err = 0, i, count;
+	int err = 0, count;
 	long timeleft;
 	long timeleft;
 	unsigned long flags;
 	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) {
 	if (count < 1) {
 		dev_err(&(pcr->pci->dev), "scatterlist map failed\n");
 		dev_err(&(pcr->pci->dev), "scatterlist map failed\n");
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 	dev_dbg(&(pcr->pci->dev), "DMA mapping count: %d\n", count);
 	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);
 	spin_lock_irqsave(&pcr->lock, flags);
 
 
 	pcr->done = &trans_done;
 	pcr->done = &trans_done;
 	pcr->trans_result = TRANS_NOT_READY;
 	pcr->trans_result = TRANS_NOT_READY;
 	init_completion(&trans_done);
 	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);
 	spin_unlock_irqrestore(&pcr->lock, flags);
 
 
+	rtsx_pci_dma_transfer(pcr, sglist, count, read);
+
 	timeleft = wait_for_completion_interruptible_timeout(
 	timeleft = wait_for_completion_interruptible_timeout(
 			&trans_done, msecs_to_jiffies(timeout));
 			&trans_done, msecs_to_jiffies(timeout));
 	if (timeleft <= 0) {
 	if (timeleft <= 0) {
@@ -413,7 +383,7 @@ out:
 	pcr->done = NULL;
 	pcr->done = NULL;
 	spin_unlock_irqrestore(&pcr->lock, flags);
 	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))
 	if ((err < 0) && (err != -ENODEV))
 		rtsx_pci_stop_cmd(pcr);
 		rtsx_pci_stop_cmd(pcr);
@@ -425,6 +395,73 @@ out:
 }
 }
 EXPORT_SYMBOL_GPL(rtsx_pci_transfer_data);
 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 rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len)
 {
 {
 	int err;
 	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);
 	int_reg = rtsx_pci_readl(pcr, RTSX_BIPR);
 	/* Clear interrupt flag */
 	/* Clear interrupt flag */
 	rtsx_pci_writel(pcr, RTSX_BIPR, int_reg);
 	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) {
 	if ((int_reg & pcr->bier) == 0) {
 		spin_unlock(&pcr->lock);
 		spin_unlock(&pcr->lock);
 		return IRQ_NONE;
 		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 & (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;
 			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;
 			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)
 	if (pcr->card_inserted || pcr->card_removed)
 		schedule_delayed_work(&pcr->carddet_work,
 		schedule_delayed_work(&pcr->carddet_work,
 				msecs_to_jiffies(200));
 				msecs_to_jiffies(200));

+ 115 - 66
drivers/mmc/card/block.c

@@ -415,8 +415,7 @@ static int ioctl_do_sanitize(struct mmc_card *card)
 {
 {
 	int err;
 	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",
 			pr_warn("%s: %s - SANITIZE is not supported\n",
 				mmc_hostname(card->host), __func__);
 				mmc_hostname(card->host), __func__);
 			err = -EOPNOTSUPP;
 			err = -EOPNOTSUPP;
@@ -722,19 +721,6 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
 	return result;
 	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)
 static int get_card_status(struct mmc_card *card, u32 *status, int retries)
 {
 {
 	struct mmc_command cmd = {0};
 	struct mmc_command cmd = {0};
@@ -750,6 +736,99 @@ static int get_card_status(struct mmc_card *card, u32 *status, int retries)
 	return err;
 	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_NOMEDIUM	3
 #define ERR_RETRY	2
 #define ERR_RETRY	2
 #define ERR_ABORT	1
 #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 ||
 	if (R1_CURRENT_STATE(status) == R1_STATE_DATA ||
 	    R1_CURRENT_STATE(status) == R1_STATE_RCV) {
 	    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",
 			pr_err("%s: error %d sending stop command\n",
 			       req->rq_disk->disk_name, err);
 			       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;
 			return ERR_ABORT;
+		}
+
 		if (stop_status & R1_CARD_ECC_FAILED)
 		if (stop_status & R1_CARD_ECC_FAILED)
 			*ecc_err = 1;
 			*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 */
 	/* 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.
 	 * program mode, which we have to wait for it to complete.
 	 */
 	 */
 	if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
 	if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
-		u32 status;
-		unsigned long timeout;
+		int err;
 
 
 		/* Check stop command response */
 		/* Check stop command response */
 		if (brq->stop.resp[0] & R1_ERROR) {
 		if (brq->stop.resp[0] & R1_ERROR) {
@@ -1168,39 +1241,10 @@ static int mmc_blk_err_check(struct mmc_card *card,
 			gen_err = 1;
 			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. */
 	/* 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->data.blksz = 512;
 	brq->stop.opcode = MMC_STOP_TRANSMISSION;
 	brq->stop.opcode = MMC_STOP_TRANSMISSION;
 	brq->stop.arg = 0;
 	brq->stop.arg = 0;
-	brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
 	brq->data.blocks = blk_rq_sectors(req);
 	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) {
 	if (rq_data_dir(req) == READ) {
 		brq->cmd.opcode = readcmd;
 		brq->cmd.opcode = readcmd;
 		brq->data.flags |= MMC_DATA_READ;
 		brq->data.flags |= MMC_DATA_READ;
+		if (brq->mrq.stop)
+			brq->stop.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 |
+					MMC_CMD_AC;
 	} else {
 	} else {
 		brq->cmd.opcode = writecmd;
 		brq->cmd.opcode = writecmd;
 		brq->data.flags |= MMC_DATA_WRITE;
 		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)
 	if (do_rel_wr)

+ 0 - 15
drivers/mmc/core/Kconfig

@@ -2,21 +2,6 @@
 # MMC core configuration
 # 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
 config MMC_CLKGATE
 	bool "MMC host clock gating"
 	bool "MMC host clock gating"
 	help
 	help

+ 2 - 10
drivers/mmc/core/bus.c

@@ -185,24 +185,16 @@ static int mmc_runtime_suspend(struct device *dev)
 {
 {
 	struct mmc_card *card = mmc_dev_to_card(dev);
 	struct mmc_card *card = mmc_dev_to_card(dev);
 	struct mmc_host *host = card->host;
 	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)
 static int mmc_runtime_resume(struct device *dev)
 {
 {
 	struct mmc_card *card = mmc_dev_to_card(dev);
 	struct mmc_card *card = mmc_dev_to_card(dev);
 	struct mmc_host *host = card->host;
 	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)
 static int mmc_runtime_idle(struct device *dev)

+ 15 - 72
drivers/mmc/core/core.c

@@ -34,6 +34,7 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/sd.h>
 #include <linux/mmc/sd.h>
+#include <linux/mmc/slot-gpio.h>
 
 
 #include "core.h"
 #include "core.h"
 #include "bus.h"
 #include "bus.h"
@@ -64,23 +65,6 @@ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
 bool use_spi_crc = 1;
 bool use_spi_crc = 1;
 module_param(use_spi_crc, bool, 0);
 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.
  * 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,
 	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) {
 	if (err) {
 		pr_warn("%s: Error %d starting bkops\n",
 		pr_warn("%s: Error %d starting bkops\n",
 			mmc_hostname(card->host), err);
 			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.opcode = MMC_ERASE;
 	cmd.arg = arg;
 	cmd.arg = arg;
 	cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
 	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);
 	err = mmc_wait_for_cmd(card->host, &cmd, 0);
 	if (err) {
 	if (err) {
 		pr_err("mmc_erase: erase error %d, status %#x\n",
 		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;
 		y = 0;
 		for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) {
 		for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) {
 			timeout = mmc_erase_timeout(card, arg, qty + x);
 			timeout = mmc_erase_timeout(card, arg, qty + x);
-			if (timeout > host->max_discard_to)
+			if (timeout > host->max_busy_timeout)
 				break;
 				break;
 			if (timeout < last_timeout)
 			if (timeout < last_timeout)
 				break;
 				break;
@@ -2169,7 +2154,7 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
 	struct mmc_host *host = card->host;
 	struct mmc_host *host = card->host;
 	unsigned int max_discard, max_trim;
 	unsigned int max_discard, max_trim;
 
 
-	if (!host->max_discard_to)
+	if (!host->max_busy_timeout)
 		return UINT_MAX;
 		return UINT_MAX;
 
 
 	/*
 	/*
@@ -2189,7 +2174,7 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
 		max_discard = 0;
 		max_discard = 0;
 	}
 	}
 	pr_debug("%s: calculated max. discard sectors %u for timeout %u ms\n",
 	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;
 	return max_discard;
 }
 }
 EXPORT_SYMBOL(mmc_calc_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;
 	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)
 	if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 
 
@@ -2352,7 +2334,7 @@ int _mmc_detect_card_removed(struct mmc_host *host)
 {
 {
 	int ret;
 	int ret;
 
 
-	if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive)
+	if (host->caps & MMC_CAP_NONREMOVABLE)
 		return 0;
 		return 0;
 
 
 	if (!host->card || mmc_card_removed(host->card))
 	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
 	 * if there is a _removable_ card registered, check whether it is
 	 * still present
 	 * 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->caps & MMC_CAP_NONREMOVABLE))
 		host->bus_ops->detect(host);
 		host->bus_ops->detect(host);
 
 
@@ -2490,6 +2472,7 @@ void mmc_start_host(struct mmc_host *host)
 		mmc_power_off(host);
 		mmc_power_off(host);
 	else
 	else
 		mmc_power_up(host, host->ocr_avail);
 		mmc_power_up(host, host->ocr_avail);
+	mmc_gpiod_request_cd_irq(host);
 	_mmc_detect_change(host, 0, false);
 	_mmc_detect_change(host, 0, false);
 }
 }
 
 
@@ -2501,6 +2484,8 @@ void mmc_stop_host(struct mmc_host *host)
 	host->removed = 1;
 	host->removed = 1;
 	spin_unlock_irqrestore(&host->lock, flags);
 	spin_unlock_irqrestore(&host->lock, flags);
 #endif
 #endif
+	if (host->slot.cd_irq >= 0)
+		disable_irq(host->slot.cd_irq);
 
 
 	host->rescan_disable = 1;
 	host->rescan_disable = 1;
 	cancel_delayed_work_sync(&host->detect);
 	cancel_delayed_work_sync(&host->detect);
@@ -2537,7 +2522,7 @@ int mmc_power_save_host(struct mmc_host *host)
 
 
 	mmc_bus_get(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);
 		mmc_bus_put(host);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
@@ -2563,7 +2548,7 @@ int mmc_power_restore_host(struct mmc_host *host)
 
 
 	mmc_bus_get(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);
 		mmc_bus_put(host);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
@@ -2582,12 +2567,8 @@ EXPORT_SYMBOL(mmc_power_restore_host);
  */
  */
 int mmc_flush_cache(struct mmc_card *card)
 int mmc_flush_cache(struct mmc_card *card)
 {
 {
-	struct mmc_host *host = card->host;
 	int err = 0;
 	int err = 0;
 
 
-	if (!(host->caps2 & MMC_CAP2_CACHE_CTRL))
-		return err;
-
 	if (mmc_card_mmc(card) &&
 	if (mmc_card_mmc(card) &&
 			(card->ext_csd.cache_size > 0) &&
 			(card->ext_csd.cache_size > 0) &&
 			(card->ext_csd.cache_ctrl & 1)) {
 			(card->ext_csd.cache_ctrl & 1)) {
@@ -2602,44 +2583,6 @@ int mmc_flush_cache(struct mmc_card *card)
 }
 }
 EXPORT_SYMBOL(mmc_flush_cache);
 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
 #ifdef CONFIG_PM
 
 
 /* Do the card removal on suspend if card is assumed removeable
 /* 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 */
 		/* Validate prerequisites for suspend */
 		if (host->bus_ops->pre_suspend)
 		if (host->bus_ops->pre_suspend)
 			err = host->bus_ops->pre_suspend(host);
 			err = host->bus_ops->pre_suspend(host);
-		if (!err && host->bus_ops->suspend)
+		if (!err)
 			break;
 			break;
 
 
 		/* Calling bus_ops->remove() with a claimed host can deadlock */
 		/* Calling bus_ops->remove() with a claimed host can deadlock */

+ 18 - 0
drivers/mmc/core/host.c

@@ -419,6 +419,16 @@ int mmc_of_parse(struct mmc_host *host)
 		host->caps |= MMC_CAP_SD_HIGHSPEED;
 		host->caps |= MMC_CAP_SD_HIGHSPEED;
 	if (of_find_property(np, "cap-mmc-highspeed", &len))
 	if (of_find_property(np, "cap-mmc-highspeed", &len))
 		host->caps |= MMC_CAP_MMC_HIGHSPEED;
 		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))
 	if (of_find_property(np, "cap-power-off-card", &len))
 		host->caps |= MMC_CAP_POWER_OFF_CARD;
 		host->caps |= MMC_CAP_POWER_OFF_CARD;
 	if (of_find_property(np, "cap-sdio-irq", &len))
 	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;
 		host->pm_caps |= MMC_PM_KEEP_POWER;
 	if (of_find_property(np, "enable-sdio-wakeup", &len))
 	if (of_find_property(np, "enable-sdio-wakeup", &len))
 		host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
 		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;
 	return 0;
 
 

+ 28 - 37
drivers/mmc/core/mmc.c

@@ -856,8 +856,10 @@ static int mmc_select_hs200(struct mmc_card *card)
 
 
 	/* switch to HS200 mode if bus width set successfully */
 	/* switch to HS200 mode if bus width set successfully */
 	if (!err)
 	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:
 err:
 	return err;
 	return err;
 }
 }
@@ -1074,9 +1076,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
 		    host->caps2 & MMC_CAP2_HS200)
 		    host->caps2 & MMC_CAP2_HS200)
 			err = mmc_select_hs200(card);
 			err = mmc_select_hs200(card);
 		else if	(host->caps & MMC_CAP_MMC_HIGHSPEED)
 		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)
 		if (err && err != -EBADMSG)
 			goto free_card;
 			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
 	 * If cache size is higher than 0, this indicates
 	 * the existence of cache and it can be turned on.
 	 * 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,
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 				EXT_CSD_CACHE_CTRL, 1,
 				EXT_CSD_CACHE_CTRL, 1,
 				card->ext_csd.generic_cmd6_time);
 				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_command cmd = {0};
 	struct mmc_card *card = host->card;
 	struct mmc_card *card = host->card;
+	unsigned int timeout_ms = DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000);
 	int err;
 	int err;
 
 
-	if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
-		return 0;
-
 	err = mmc_deselect_cards(host);
 	err = mmc_deselect_cards(host);
 	if (err)
 	if (err)
 		return err;
 		return err;
@@ -1369,7 +1369,19 @@ static int mmc_sleep(struct mmc_host *host)
 	cmd.arg = card->rca << 16;
 	cmd.arg = card->rca << 16;
 	cmd.arg |= 1 << 15;
 	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);
 	err = mmc_wait_for_cmd(host, &cmd, 0);
 	if (err)
 	if (err)
 		return 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
 	 * SEND_STATUS command to poll the status because that command (and most
 	 * others) is invalid while the card sleeps.
 	 * 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;
 	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,
 	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 			EXT_CSD_POWER_OFF_NOTIFICATION,
 			EXT_CSD_POWER_OFF_NOTIFICATION,
-			notify_type, timeout, true, false);
+			notify_type, timeout, true, false, false);
 	if (err)
 	if (err)
 		pr_err("%s: Power Off Notification timed out, %u\n",
 		pr_err("%s: Power Off Notification timed out, %u\n",
 		       mmc_hostname(card->host), timeout);
 		       mmc_hostname(card->host), timeout);
@@ -1484,7 +1496,7 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
 			goto out;
 			goto out;
 	}
 	}
 
 
-	err = mmc_cache_ctrl(host, 0);
+	err = mmc_flush_cache(host->card);
 	if (err)
 	if (err)
 		goto out;
 		goto out;
 
 
@@ -1634,16 +1646,6 @@ static int mmc_power_restore(struct mmc_host *host)
 }
 }
 
 
 static const struct mmc_bus_ops mmc_ops = {
 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,
 	.remove = mmc_remove,
 	.detect = mmc_detect,
 	.detect = mmc_detect,
 	.suspend = mmc_suspend,
 	.suspend = mmc_suspend,
@@ -1655,17 +1657,6 @@ static const struct mmc_bus_ops mmc_ops_unsafe = {
 	.shutdown = mmc_shutdown,
 	.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.
  * Starting point for MMC card init.
  */
  */
@@ -1685,7 +1676,7 @@ int mmc_attach_mmc(struct mmc_host *host)
 	if (err)
 	if (err)
 		return err;
 		return err;
 
 
-	mmc_attach_bus_ops(host);
+	mmc_attach_bus(host, &mmc_ops);
 	if (host->ocr_avail_mmc)
 	if (host->ocr_avail_mmc)
 		host->ocr_avail = host->ocr_avail_mmc;
 		host->ocr_avail = host->ocr_avail_mmc;
 
 

+ 41 - 23
drivers/mmc/core/mmc_ops.c

@@ -405,20 +405,30 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
  *                   timeout of zero implies maximum possible timeout
  *                   timeout of zero implies maximum possible timeout
  *	@use_busy_signal: use the busy signal as response type
  *	@use_busy_signal: use the busy signal as response type
  *	@send_status: send status cmd to poll for busy
  *	@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.
  *	Modifies the EXT_CSD register for selected card.
  */
  */
 int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
 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;
 	int err;
 	struct mmc_command cmd = {0};
 	struct mmc_command cmd = {0};
 	unsigned long timeout;
 	unsigned long timeout;
 	u32 status = 0;
 	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.opcode = MMC_SWITCH;
 	cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
 	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) |
 		  (value << 8) |
 		  set;
 		  set;
 	cmd.flags = MMC_CMD_AC;
 	cmd.flags = MMC_CMD_AC;
-	if (use_busy_signal)
+	if (use_r1b_resp) {
 		cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
 		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.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
+	}
 
 
-
-	cmd.cmd_timeout_ms = timeout_ms;
 	if (index == EXT_CSD_SANITIZE_START)
 	if (index == EXT_CSD_SANITIZE_START)
 		cmd.sanitize_busy = true;
 		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)
 	if (err)
 		return err;
 		return err;
 
 
@@ -445,24 +459,27 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
 		return 0;
 		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 {
 	do {
 		if (send_status) {
 		if (send_status) {
 			err = __mmc_send_status(card, &status, ignore_crc);
 			err = __mmc_send_status(card, &status, ignore_crc);
 			if (err)
 			if (err)
 				return err;
 				return err;
 		}
 		}
-		if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
+		if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
 			break;
 			break;
-		if (mmc_host_is_spi(card->host))
+		if (mmc_host_is_spi(host))
 			break;
 			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. */
 		/* Timeout if the device never leaves the program state. */
 		if (time_after(jiffies, timeout)) {
 		if (time_after(jiffies, timeout)) {
 			pr_err("%s: Card stuck in programming state! %s\n",
 			pr_err("%s: Card stuck in programming state! %s\n",
-				mmc_hostname(card->host), __func__);
+				mmc_hostname(host), __func__);
 			return -ETIMEDOUT;
 			return -ETIMEDOUT;
 		}
 		}
 	} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
 	} 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)
 		if (status & R1_SPI_ILLEGAL_COMMAND)
 			return -EBADMSG;
 			return -EBADMSG;
 	} else {
 	} else {
 		if (status & 0xFDFFA000)
 		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)
 		if (status & R1_SWITCH_ERROR)
 			return -EBADMSG;
 			return -EBADMSG;
 	}
 	}
@@ -501,7 +518,8 @@ EXPORT_SYMBOL_GPL(__mmc_switch);
 int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
 int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
 		unsigned int timeout_ms)
 		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);
 EXPORT_SYMBOL_GPL(mmc_switch);
 
 

+ 1 - 22
drivers/mmc/core/sd.c

@@ -1207,16 +1207,6 @@ static int mmc_sd_power_restore(struct mmc_host *host)
 }
 }
 
 
 static const struct mmc_bus_ops mmc_sd_ops = {
 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,
 	.remove = mmc_sd_remove,
 	.detect = mmc_sd_detect,
 	.detect = mmc_sd_detect,
 	.runtime_suspend = mmc_sd_runtime_suspend,
 	.runtime_suspend = mmc_sd_runtime_suspend,
@@ -1228,17 +1218,6 @@ static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
 	.shutdown = mmc_sd_suspend,
 	.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.
  * Starting point for SD card init.
  */
  */
@@ -1254,7 +1233,7 @@ int mmc_attach_sd(struct mmc_host *host)
 	if (err)
 	if (err)
 		return err;
 		return err;
 
 
-	mmc_sd_attach_bus_ops(host);
+	mmc_attach_bus(host, &mmc_sd_ops);
 	if (host->ocr_avail_sd)
 	if (host->ocr_avail_sd)
 		host->ocr_avail = host->ocr_avail_sd;
 		host->ocr_avail = host->ocr_avail_sd;
 
 

+ 140 - 40
drivers/mmc/core/slot-gpio.c

@@ -10,6 +10,7 @@
 
 
 #include <linux/err.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
 #include <linux/jiffies.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
@@ -18,8 +19,10 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 
 
 struct mmc_gpio {
 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 *ro_label;
 	char cd_label[0];
 	char cd_label[0];
 };
 };
@@ -57,8 +60,6 @@ static int mmc_gpio_alloc(struct mmc_host *host)
 			ctx->ro_label = ctx->cd_label + len;
 			ctx->ro_label = ctx->cd_label + len;
 			snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
 			snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
 			snprintf(ctx->ro_label, len, "%s ro", 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;
 			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;
 	struct mmc_gpio *ctx = host->slot.handler_priv;
 
 
-	if (!ctx || !gpio_is_valid(ctx->ro_gpio))
+	if (!ctx || !ctx->ro_gpio)
 		return -ENOSYS;
 		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);
 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;
 	struct mmc_gpio *ctx = host->slot.handler_priv;
 
 
-	if (!ctx || !gpio_is_valid(ctx->cd_gpio))
+	if (!ctx || !ctx->cd_gpio)
 		return -ENOSYS;
 		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);
 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)
 	if (ret < 0)
 		return ret;
 		return ret;
 
 
-	ctx->ro_gpio = gpio;
+	ctx->override_ro_active_level = true;
+	ctx->ro_gpio = gpio_to_desc(gpio);
 
 
 	return 0;
 	return 0;
 }
 }
 EXPORT_SYMBOL(mmc_gpio_request_ro);
 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
  * mmc_gpio_request_cd - request a gpio for card-detection
  * @host: mmc host
  * @host: mmc host
@@ -154,7 +196,6 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio,
 			unsigned int debounce)
 			unsigned int debounce)
 {
 {
 	struct mmc_gpio *ctx;
 	struct mmc_gpio *ctx;
-	int irq = gpio_to_irq(gpio);
 	int ret;
 	int ret;
 
 
 	ret = mmc_gpio_alloc(host);
 	ret = mmc_gpio_alloc(host);
@@ -179,29 +220,10 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio,
 			return ret;
 			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;
 	return 0;
 }
 }
@@ -219,11 +241,11 @@ void mmc_gpio_free_ro(struct mmc_host *host)
 	struct mmc_gpio *ctx = host->slot.handler_priv;
 	struct mmc_gpio *ctx = host->slot.handler_priv;
 	int gpio;
 	int gpio;
 
 
-	if (!ctx || !gpio_is_valid(ctx->ro_gpio))
+	if (!ctx || !ctx->ro_gpio)
 		return;
 		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);
 	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;
 	struct mmc_gpio *ctx = host->slot.handler_priv;
 	int gpio;
 	int gpio;
 
 
-	if (!ctx || !gpio_is_valid(ctx->cd_gpio))
+	if (!ctx || !ctx->cd_gpio)
 		return;
 		return;
 
 
 	if (host->slot.cd_irq >= 0) {
 	if (host->slot.cd_irq >= 0) {
@@ -249,9 +271,87 @@ void mmc_gpio_free_cd(struct mmc_host *host)
 		host->slot.cd_irq = -EINVAL;
 		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);
 	devm_gpio_free(&host->class_dev, gpio);
 }
 }
 EXPORT_SYMBOL(mmc_gpio_free_cd);
 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);

+ 14 - 9
drivers/mmc/host/Kconfig

@@ -263,7 +263,7 @@ config MMC_SDHCI_S3C_DMA
 
 
 config MMC_SDHCI_BCM_KONA
 config MMC_SDHCI_BCM_KONA
 	tristate "SDHCI support on Broadcom KONA platform"
 	tristate "SDHCI support on Broadcom KONA platform"
-	depends on ARCH_BCM
+	depends on ARCH_BCM_MOBILE
 	select MMC_SDHCI_PLTFM
 	select MMC_SDHCI_PLTFM
 	help
 	help
 	  This selects the Broadcom Kona Secure Digital Host Controller
 	  This selects the Broadcom Kona Secure Digital Host Controller
@@ -334,6 +334,19 @@ config MMC_ATMELMCI
 
 
 	  If unsure, say N.
 	  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
 config MMC_MSM
 	tristate "Qualcomm SDCC Controller Support"
 	tristate "Qualcomm SDCC Controller Support"
 	depends on MMC && (ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50)
 	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
 	  Synopsys DesignWare Memory Card Interface driver. Select this option
 	  for platforms based on Exynos4 and Exynos5 SoC's.
 	  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
 config MMC_DW_K3
 	tristate "K3 specific extensions for Synopsys DW Memory Card Interface"
 	tristate "K3 specific extensions for Synopsys DW Memory Card Interface"
 	depends on MMC_DW
 	depends on MMC_DW

+ 1 - 1
drivers/mmc/host/Makefile

@@ -43,7 +43,6 @@ obj-$(CONFIG_SDH_BFIN)		+= bfin_sdh.o
 obj-$(CONFIG_MMC_DW)		+= dw_mmc.o
 obj-$(CONFIG_MMC_DW)		+= dw_mmc.o
 obj-$(CONFIG_MMC_DW_PLTFM)	+= dw_mmc-pltfm.o
 obj-$(CONFIG_MMC_DW_PLTFM)	+= dw_mmc-pltfm.o
 obj-$(CONFIG_MMC_DW_EXYNOS)	+= dw_mmc-exynos.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_K3)		+= dw_mmc-k3.o
 obj-$(CONFIG_MMC_DW_PCI)	+= dw_mmc-pci.o
 obj-$(CONFIG_MMC_DW_PCI)	+= dw_mmc-pci.o
 obj-$(CONFIG_MMC_SH_MMCIF)	+= sh_mmcif.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_OF_HLWD)		+= sdhci-of-hlwd.o
 obj-$(CONFIG_MMC_SDHCI_BCM_KONA)	+= sdhci-bcm-kona.o
 obj-$(CONFIG_MMC_SDHCI_BCM_KONA)	+= sdhci-bcm-kona.o
 obj-$(CONFIG_MMC_SDHCI_BCM2835)		+= sdhci-bcm2835.o
 obj-$(CONFIG_MMC_SDHCI_BCM2835)		+= sdhci-bcm2835.o
+obj-$(CONFIG_MMC_SDHCI_MSM)		+= sdhci-msm.o
 
 
 ifeq ($(CONFIG_CB710_DEBUG),y)
 ifeq ($(CONFIG_CB710_DEBUG),y)
 	CFLAGS-cb710-mmc	+= -DDEBUG
 	CFLAGS-cb710-mmc	+= -DDEBUG

+ 2 - 2
drivers/mmc/host/davinci_mmc.c

@@ -1192,7 +1192,7 @@ static struct davinci_mmc_config
 	struct device_node *np;
 	struct device_node *np;
 	struct davinci_mmc_config *pdata = pdev->dev.platform_data;
 	struct davinci_mmc_config *pdata = pdev->dev.platform_data;
 	const struct of_device_id *match =
 	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;
 	u32 data;
 
 
 	np = pdev->dev.of_node;
 	np = pdev->dev.of_node;
@@ -1468,7 +1468,7 @@ static struct platform_driver davinci_mmcsd_driver = {
 		.name	= "davinci_mmc",
 		.name	= "davinci_mmc",
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
 		.pm	= davinci_mmcsd_pm_ops,
 		.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),
 	.remove		= __exit_p(davinci_mmcsd_remove),
 	.id_table	= davinci_mmc_devtype,
 	.id_table	= davinci_mmc_devtype,

+ 2 - 0
drivers/mmc/host/dw_mmc-k3.c

@@ -50,6 +50,7 @@ static int dw_mci_k3_probe(struct platform_device *pdev)
 	return dw_mci_pltfm_register(pdev, drv_data);
 	return dw_mci_pltfm_register(pdev, drv_data);
 }
 }
 
 
+#ifdef CONFIG_PM_SLEEP
 static int dw_mci_k3_suspend(struct device *dev)
 static int dw_mci_k3_suspend(struct device *dev)
 {
 {
 	struct dw_mci *host = dev_get_drvdata(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);
 	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);
 static SIMPLE_DEV_PM_OPS(dw_mci_k3_pmops, dw_mci_k3_suspend, dw_mci_k3_resume);
 
 

+ 9 - 3
drivers/mmc/host/dw_mmc-pltfm.c

@@ -25,13 +25,17 @@
 #include "dw_mmc.h"
 #include "dw_mmc.h"
 #include "dw_mmc-pltfm.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;
 	*cmdr |= SDMMC_CMD_USE_HOLD_REG;
 }
 }
 
 
 static const struct dw_mci_drv_data rockchip_drv_data = {
 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,
 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 = "snps,dw-mshc", },
 	{ .compatible = "rockchip,rk2928-dw-mshc",
 	{ .compatible = "rockchip,rk2928-dw-mshc",
 		.data = &rockchip_drv_data },
 		.data = &rockchip_drv_data },
+	{ .compatible = "altr,socfpga-dw-mshc",
+		.data = &socfpga_drv_data },
 	{},
 	{},
 };
 };
 MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
 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,
 	.remove		= dw_mci_pltfm_remove,
 	.driver		= {
 	.driver		= {
 		.name		= "dw_mmc",
 		.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,
 		.pm		= &dw_mci_pltfm_pmops,
 	},
 	},
 };
 };

+ 0 - 138
drivers/mmc/host/dw_mmc-socfpga.c

@@ -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");

+ 1 - 1
drivers/mmc/host/dw_mmc.c

@@ -1345,7 +1345,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
 
 
 			if (!err) {
 			if (!err) {
 				if (!data->stop || mrq->sbc) {
 				if (!data->stop || mrq->sbc) {
-					if (mrq->sbc)
+					if (mrq->sbc && data->stop)
 						data->stop->error = 0;
 						data->stop->error = 0;
 					dw_mci_request_end(host, mrq);
 					dw_mci_request_end(host, mrq);
 					goto unlock;
 					goto unlock;

+ 2 - 1
drivers/mmc/host/dw_mmc.h

@@ -185,7 +185,7 @@
 
 
 extern int dw_mci_probe(struct dw_mci *host);
 extern int dw_mci_probe(struct dw_mci *host);
 extern void dw_mci_remove(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_suspend(struct dw_mci *host);
 extern int dw_mci_resume(struct dw_mci *host);
 extern int dw_mci_resume(struct dw_mci *host);
 #endif
 #endif
@@ -244,6 +244,7 @@ struct dw_mci_tuning_data {
  * @prepare_command: handle CMD register extensions.
  * @prepare_command: handle CMD register extensions.
  * @set_ios: handle bus specific extensions.
  * @set_ios: handle bus specific extensions.
  * @parse_dt: parse implementation specific device tree properties.
  * @parse_dt: parse implementation specific device tree properties.
+ * @execute_tuning: implementation specific tuning procedure.
  *
  *
  * Provide controller implementation specific extensions. The usage of this
  * Provide controller implementation specific extensions. The usage of this
  * data structure is fully optional and usage of each member in this structure
  * data structure is fully optional and usage of each member in this structure

+ 45 - 9
drivers/mmc/host/mmci.c

@@ -921,6 +921,29 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
 {
 {
 	void __iomem *base = host->base;
 	void __iomem *base = host->base;
 	bool sbc = (cmd == host->mrq->sbc);
 	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;
 	host->cmd = NULL;
 
 
@@ -1139,20 +1162,30 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
 			status &= ~MCI_IRQ1MASK;
 			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);
 		status &= readl(host->base + MMCIMASK0);
 		writel(status, host->base + MMCICLEAR);
 		writel(status, host->base + MMCICLEAR);
 
 
 		dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status);
 		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;
 		data = host->data;
 		if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR|
 		if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR|
 			      MCI_TXUNDERRUN|MCI_RXOVERRUN|MCI_DATAEND|
 			      MCI_TXUNDERRUN|MCI_RXOVERRUN|MCI_DATAEND|
 			      MCI_DATABLOCKEND) && data)
 			      MCI_DATABLOCKEND) && data)
 			mmci_data_irq(host, data, status);
 			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;
 		ret = 1;
 	} while (status);
 	} while (status);
@@ -1503,12 +1536,6 @@ static int mmci_probe(struct amba_device *dev,
 		goto clk_disable;
 		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
 	 * The ARM and ST versions of the block have slightly different
 	 * clock divider equations which means that the minimum divider
 	 * clock divider equations which means that the minimum divider
@@ -1542,6 +1569,15 @@ static int mmci_probe(struct amba_device *dev,
 	mmc->caps = plat->capabilities;
 	mmc->caps = plat->capabilities;
 	mmc->caps2 = plat->capabilities2;
 	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. */
 	/* We support these PM capabilities. */
 	mmc->pm_caps = MMC_PM_KEEP_POWER;
 	mmc->pm_caps = MMC_PM_KEEP_POWER;
 
 

+ 2 - 0
drivers/mmc/host/mmci.h

@@ -140,6 +140,7 @@
 /* Extended status bits for the ST Micro variants */
 /* Extended status bits for the ST Micro variants */
 #define MCI_ST_SDIOITMASK	(1 << 22)
 #define MCI_ST_SDIOITMASK	(1 << 22)
 #define MCI_ST_CEATAENDMASK	(1 << 23)
 #define MCI_ST_CEATAENDMASK	(1 << 23)
+#define MCI_ST_BUSYEND		(1 << 24)
 
 
 #define MMCIMASK1		0x040
 #define MMCIMASK1		0x040
 #define MMCIFIFOCNT		0x048
 #define MMCIFIFOCNT		0x048
@@ -187,6 +188,7 @@ struct mmci_host {
 	u32			pwr_reg;
 	u32			pwr_reg;
 	u32			clk_reg;
 	u32			clk_reg;
 	u32			datactrl_reg;
 	u32			datactrl_reg;
+	u32			busy_status;
 	bool			vqmmc_enabled;
 	bool			vqmmc_enabled;
 	struct mmci_platform_data *plat;
 	struct mmci_platform_data *plat;
 	struct variant_data	*variant;
 	struct variant_data	*variant;

+ 36 - 57
drivers/mmc/host/omap.c

@@ -26,6 +26,7 @@
 #include <linux/omap-dma.h>
 #include <linux/omap-dma.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
 #include <linux/clk.h>
 #include <linux/clk.h>
 #include <linux/scatterlist.h>
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
@@ -130,7 +131,6 @@ struct mmc_omap_host {
 	u32			dma_rx_burst;
 	u32			dma_rx_burst;
 	struct dma_chan		*dma_tx;
 	struct dma_chan		*dma_tx;
 	u32			dma_tx_burst;
 	u32			dma_tx_burst;
-	struct resource		*mem_res;
 	void __iomem		*virt_base;
 	void __iomem		*virt_base;
 	unsigned int		phys_base;
 	unsigned int		phys_base;
 	int			irq;
 	int			irq;
@@ -153,7 +153,6 @@ struct mmc_omap_host {
 	u32			total_bytes_left;
 	u32			total_bytes_left;
 
 
 	unsigned		features;
 	unsigned		features;
-	unsigned		use_dma:1;
 	unsigned		brs_received:1, dma_done:1;
 	unsigned		brs_received:1, dma_done:1;
 	unsigned		dma_in_use:1;
 	unsigned		dma_in_use:1;
 	spinlock_t		dma_lock;
 	spinlock_t		dma_lock;
@@ -338,6 +337,7 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
 	u32 cmdreg;
 	u32 cmdreg;
 	u32 resptype;
 	u32 resptype;
 	u32 cmdtype;
 	u32 cmdtype;
+	u16 irq_mask;
 
 
 	host->cmd = cmd;
 	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, CTO, 200);
 	OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff);
 	OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff);
 	OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16);
 	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);
 	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)
 mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
 {
 {
 	struct mmc_data *data = req->data;
 	struct mmc_data *data = req->data;
-	int i, use_dma, block_size;
+	int i, use_dma = 1, block_size;
 	unsigned sg_len;
 	unsigned sg_len;
 
 
 	host->data = data;
 	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;
 	sg_len = (data->blocks == 1) ? 1 : data->sg_len;
 
 
 	/* Only do DMA for entire blocks */
 	/* 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;
 	mmc->caps = 0;
 	if (host->pdata->slots[id].wires >= 4)
 	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->ops = &mmc_omap_ops;
 	mmc->f_min = 400000;
 	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_req_size = mmc->max_blk_size * mmc->max_blk_count;
 	mmc->max_seg_size = mmc->max_req_size;
 	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);
 	r = mmc_add_host(mmc);
 	if (r < 0)
 	if (r < 0)
 		goto err_remove_host;
 		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);
 					&dev_attr_cover_switch);
 		if (r < 0)
 		if (r < 0)
 			goto err_remove_slot_name;
 			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);
 		tasklet_schedule(&slot->cover_tasklet);
 	}
 	}
 
 
@@ -1333,21 +1334,19 @@ static int mmc_omap_probe(struct platform_device *pdev)
 		return -EPROBE_DEFER;
 		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);
 	irq = platform_get_irq(pdev, 0);
-	if (res == NULL || irq < 0)
+	if (irq < 0)
 		return -ENXIO;
 		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->slot_release_work, mmc_omap_slot_release_work);
 	INIT_WORK(&host->send_stop_work, mmc_omap_send_stop_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);
 	platform_set_drvdata(pdev, host);
 
 
 	host->id = pdev->id;
 	host->id = pdev->id;
-	host->mem_res = res;
-	host->irq = irq;
-	host->use_dma = 1;
 	host->irq = irq;
 	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");
 	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);
 	clk_enable(host->iclk);
 
 
 	host->fclk = clk_get(&pdev->dev, "fck");
 	host->fclk = clk_get(&pdev->dev, "fck");
@@ -1460,12 +1450,6 @@ err_free_dma:
 err_free_iclk:
 err_free_iclk:
 	clk_disable(host->iclk);
 	clk_disable(host->iclk);
 	clk_put(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;
 	return ret;
 }
 }
 
 
@@ -1493,13 +1477,8 @@ static int mmc_omap_remove(struct platform_device *pdev)
 	if (host->dma_rx)
 	if (host->dma_rx)
 		dma_release_channel(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);
 	destroy_workqueue(host->mmc_omap_wq);
 
 
-	kfree(host);
-
 	return 0;
 	return 0;
 }
 }
 
 

+ 166 - 76
drivers/mmc/host/omap_hsmmc.c

@@ -45,6 +45,7 @@
 /* OMAP HSMMC Host Controller Registers */
 /* OMAP HSMMC Host Controller Registers */
 #define OMAP_HSMMC_SYSSTATUS	0x0014
 #define OMAP_HSMMC_SYSSTATUS	0x0014
 #define OMAP_HSMMC_CON		0x002C
 #define OMAP_HSMMC_CON		0x002C
+#define OMAP_HSMMC_SDMASA	0x0100
 #define OMAP_HSMMC_BLK		0x0104
 #define OMAP_HSMMC_BLK		0x0104
 #define OMAP_HSMMC_ARG		0x0108
 #define OMAP_HSMMC_ARG		0x0108
 #define OMAP_HSMMC_CMD		0x010C
 #define OMAP_HSMMC_CMD		0x010C
@@ -58,6 +59,7 @@
 #define OMAP_HSMMC_STAT		0x0130
 #define OMAP_HSMMC_STAT		0x0130
 #define OMAP_HSMMC_IE		0x0134
 #define OMAP_HSMMC_IE		0x0134
 #define OMAP_HSMMC_ISE		0x0138
 #define OMAP_HSMMC_ISE		0x0138
+#define OMAP_HSMMC_AC12		0x013C
 #define OMAP_HSMMC_CAPA		0x0140
 #define OMAP_HSMMC_CAPA		0x0140
 
 
 #define VS18			(1 << 26)
 #define VS18			(1 << 26)
@@ -81,6 +83,7 @@
 #define DTO_MASK		0x000F0000
 #define DTO_MASK		0x000F0000
 #define DTO_SHIFT		16
 #define DTO_SHIFT		16
 #define INIT_STREAM		(1 << 1)
 #define INIT_STREAM		(1 << 1)
+#define ACEN_ACMD23		(2 << 2)
 #define DP_SELECT		(1 << 21)
 #define DP_SELECT		(1 << 21)
 #define DDIR			(1 << 4)
 #define DDIR			(1 << 4)
 #define DMAE			0x1
 #define DMAE			0x1
@@ -97,7 +100,6 @@
 #define SRC			(1 << 25)
 #define SRC			(1 << 25)
 #define SRD			(1 << 26)
 #define SRD			(1 << 26)
 #define SOFTRESET		(1 << 1)
 #define SOFTRESET		(1 << 1)
-#define RESETDONE		(1 << 0)
 
 
 /* Interrupt masks for IE and ISE register */
 /* Interrupt masks for IE and ISE register */
 #define CC_EN			(1 << 0)
 #define CC_EN			(1 << 0)
@@ -112,13 +114,21 @@
 #define DTO_EN			(1 << 20)
 #define DTO_EN			(1 << 20)
 #define DCRC_EN			(1 << 21)
 #define DCRC_EN			(1 << 21)
 #define DEB_EN			(1 << 22)
 #define DEB_EN			(1 << 22)
+#define ACE_EN			(1 << 24)
 #define CERR_EN			(1 << 28)
 #define CERR_EN			(1 << 28)
 #define BADA_EN			(1 << 29)
 #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 | \
 		DTO_EN | CIE_EN | CEB_EN | CCRC_EN | CTO_EN | \
 		BRR_EN | BWR_EN | TC_EN | CC_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_AUTOSUSPEND_DELAY	100
 #define MMC_TIMEOUT_MS		20		/* 20 mSec */
 #define MMC_TIMEOUT_MS		20		/* 20 mSec */
 #define MMC_TIMEOUT_US		20000		/* 20000 micro Sec */
 #define MMC_TIMEOUT_US		20000		/* 20000 micro Sec */
@@ -126,6 +136,11 @@
 #define OMAP_MMC_MAX_CLOCK	52000000
 #define OMAP_MMC_MAX_CLOCK	52000000
 #define DRIVER_NAME		"omap_hsmmc"
 #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
  * 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
  * 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;
 	struct	regulator	*vcc_aux;
 	struct	regulator	*vcc_aux;
-	int			pbias_disable;
+	struct	regulator	*pbias;
+	bool			pbias_enabled;
 	void	__iomem		*base;
 	void	__iomem		*base;
 	resource_size_t		mapbase;
 	resource_size_t		mapbase;
 	spinlock_t		irq_lock; /* Prevent races with irq handler */
 	spinlock_t		irq_lock; /* Prevent races with irq handler */
@@ -188,10 +204,19 @@ struct omap_hsmmc_host {
 	int			reqs_blocked;
 	int			reqs_blocked;
 	int			use_reg;
 	int			use_reg;
 	int			req_in_progress;
 	int			req_in_progress;
+	unsigned long		clk_rate;
+	unsigned int		flags;
 	struct omap_hsmmc_next	next_data;
 	struct omap_hsmmc_next	next_data;
 	struct	omap_mmc_platform_data	*pdata;
 	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)
 static int omap_hsmmc_card_detect(struct device *dev, int slot)
 {
 {
 	struct omap_hsmmc_host *host = dev_get_drvdata(dev);
 	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)
 	if (!host->vcc)
 		return 0;
 		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)
 	if (mmc_slot(host).before_set_reg)
 		mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
 		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
 	 * Assume Vcc regulator is used only to power the card ... OMAP
 	 * VDDS is used to power the pins, optionally with a transceiver to
 	 * 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.
 	 * chips/cards need an interface voltage rail too.
 	 */
 	 */
 	if (power_on) {
 	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 */
 		/* Enable interface voltage rail, if needed */
 		if (ret == 0 && host->vcc_aux) {
 		if (ret == 0 && host->vcc_aux) {
 			ret = regulator_enable(host->vcc_aux);
 			ret = regulator_enable(host->vcc_aux);
-			if (ret < 0)
+			if (ret < 0 && host->vcc)
 				ret = mmc_regulator_set_ocr(host->mmc,
 				ret = mmc_regulator_set_ocr(host->mmc,
 							host->vcc, 0);
 							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 */
 		/* Shut down the rail */
 		if (host->vcc_aux)
 		if (host->vcc_aux)
 			ret = regulator_disable(host->vcc_aux);
 			ret = regulator_disable(host->vcc_aux);
-		if (!ret) {
+		if (host->vcc) {
 			/* Then proceed to shut down the local regulator */
 			/* Then proceed to shut down the local regulator */
 			ret = mmc_regulator_set_ocr(host->mmc,
 			ret = mmc_regulator_set_ocr(host->mmc,
 						host->vcc, 0);
 						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)
 	if (mmc_slot(host).after_set_reg)
 		mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
 		mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
 
 
+error_set_power:
 	return ret;
 	return ret;
 }
 }
 
 
@@ -316,12 +362,12 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
 	struct regulator *reg;
 	struct regulator *reg;
 	int ocr_value = 0;
 	int ocr_value = 0;
 
 
-	reg = regulator_get(host->dev, "vmmc");
+	reg = devm_regulator_get(host->dev, "vmmc");
 	if (IS_ERR(reg)) {
 	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);
 		return PTR_ERR(reg);
 	} else {
 	} else {
-		mmc_slot(host).set_power = omap_hsmmc_set_power;
 		host->vcc = reg;
 		host->vcc = reg;
 		ocr_value = mmc_regulator_get_ocrmask(reg);
 		ocr_value = mmc_regulator_get_ocrmask(reg);
 		if (!mmc_slot(host).ocr_mask) {
 		if (!mmc_slot(host).ocr_mask) {
@@ -334,31 +380,29 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
 				return -EINVAL;
 				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;
 	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)
 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;
 	mmc_slot(host).set_power = NULL;
 }
 }
 
 
@@ -605,9 +647,6 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
 	u32 hctl, capa;
 	u32 hctl, capa;
 	unsigned long timeout;
 	unsigned long timeout;
 
 
-	if (!OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE)
-		return 1;
-
 	if (host->con == OMAP_HSMMC_READ(host->base, CON) &&
 	if (host->con == OMAP_HSMMC_READ(host->base, CON) &&
 	    host->hctl == OMAP_HSMMC_READ(host->base, HCTL) &&
 	    host->hctl == OMAP_HSMMC_READ(host->base, HCTL) &&
 	    host->sysctl == OMAP_HSMMC_READ(host->base, SYSCTL) &&
 	    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);
 	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) {
 	if (data) {
 		cmdreg |= DP_SELECT | MSBS | BCE;
 		cmdreg |= DP_SELECT | MSBS | BCE;
 		if (data->flags & MMC_DATA_READ)
 		if (data->flags & MMC_DATA_READ)
@@ -864,11 +908,10 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
 	else
 	else
 		data->bytes_xfered = 0;
 		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);
 		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;
 	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_PRESENT) {
 		if (cmd->flags & MMC_RSP_136) {
 		if (cmd->flags & MMC_RSP_136) {
 			/* response type 2 */
 			/* 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)
 	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;
 	struct mmc_data *data;
 	int end_cmd = 0, end_trans = 0;
 	int end_cmd = 0, end_trans = 0;
+	int error = 0;
 
 
 	data = host->data;
 	data = host->data;
 	dev_vdbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
 	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))
 		else if (status & (CCRC_EN | DCRC_EN))
 			hsmmc_command_incomplete(host, -EILSEQ, end_cmd);
 			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) {
 		if (host->data || host->response_busy) {
 			end_trans = !end_cmd;
 			end_trans = !end_cmd;
 			host->response_busy = 0;
 			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 */
 	/* 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,
 		dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len,
 				     omap_hsmmc_get_dma_dir(host, data));
 				     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
  * 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 mmc_request *req)
 {
 {
 	struct dma_slave_config cfg;
 	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;
 	host->dma_ch = 1;
 
 
-	dma_async_issue_pending(chan);
-
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1338,7 +1401,7 @@ static void set_data_timeout(struct omap_hsmmc_host *host,
 	if (clkd == 0)
 	if (clkd == 0)
 		clkd = 1;
 		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_ns / cycle_ns;
 	timeout += timeout_clks;
 	timeout += timeout_clks;
 	if (timeout) {
 	if (timeout) {
@@ -1363,6 +1426,21 @@ static void set_data_timeout(struct omap_hsmmc_host *host,
 	OMAP_HSMMC_WRITE(host->base, SYSCTL, reg);
 	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.
  * 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;
 		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) {
 	if (host->use_dma) {
-		ret = omap_hsmmc_start_dma_transfer(host, req);
+		ret = omap_hsmmc_setup_dma_transfer(host, req);
 		if (ret != 0) {
 		if (ret != 0) {
 			dev_err(mmc_dev(host->mmc), "MMC start dma failure\n");
 			dev_err(mmc_dev(host->mmc), "MMC start dma failure\n");
 			return ret;
 			return ret;
@@ -1462,6 +1536,7 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
 		host->reqs_blocked = 0;
 		host->reqs_blocked = 0;
 	WARN_ON(host->mrq != NULL);
 	WARN_ON(host->mrq != NULL);
 	host->mrq = req;
 	host->mrq = req;
+	host->clk_rate = clk_get_rate(host->fclk);
 	err = omap_hsmmc_prepare_data(host, req);
 	err = omap_hsmmc_prepare_data(host, req);
 	if (err) {
 	if (err) {
 		req->cmd->error = 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);
 		mmc_request_done(mmc, req);
 		return;
 		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);
 	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.
 		 * of external transceiver; but they all handle 1.8V.
 		 */
 		 */
 		if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
 		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
 				 * The mmc_select_voltage fn of the core does
 				 * not seem to set the power_mode to
 				 * not seem to set the power_mode to
@@ -1678,18 +1752,29 @@ static void omap_hsmmc_debugfs(struct mmc_host *mmc)
 #endif
 #endif
 
 
 #ifdef CONFIG_OF
 #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[] = {
 static const struct of_device_id omap_mmc_of_match[] = {
 	{
 	{
 		.compatible = "ti,omap2-hsmmc",
 		.compatible = "ti,omap2-hsmmc",
 	},
 	},
+	{
+		.compatible = "ti,omap3-pre-es3-hsmmc",
+		.data = &omap3_pre_es3_mmc_of_data,
+	},
 	{
 	{
 		.compatible = "ti,omap3-hsmmc",
 		.compatible = "ti,omap3-hsmmc",
 	},
 	},
 	{
 	{
 		.compatible = "ti,omap4-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);
 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata)
 	if (!pdata)
-		return NULL; /* out of memory */
+		return ERR_PTR(-ENOMEM); /* out of memory */
 
 
 	if (of_find_property(np, "ti,dual-volt", NULL))
 	if (of_find_property(np, "ti,dual-volt", NULL))
 		pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
 		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))
 	if (of_find_property(np, "ti,needs-special-hs-handling", NULL))
 		pdata->slots[0].features |= HSMMC_HAS_HSPE_SUPPORT;
 		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;
 	return pdata;
 }
 }
 #else
 #else
 static inline struct omap_mmc_platform_data
 static inline struct omap_mmc_platform_data
 			*of_get_hsmmc_pdata(struct device *dev)
 			*of_get_hsmmc_pdata(struct device *dev)
 {
 {
-	return NULL;
+	return ERR_PTR(-EINVAL);
 }
 }
 #endif
 #endif
 
 
@@ -1759,6 +1850,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
 	dma_cap_mask_t mask;
 	dma_cap_mask_t mask;
 	unsigned tx_req, rx_req;
 	unsigned tx_req, rx_req;
 	struct pinctrl *pinctrl;
 	struct pinctrl *pinctrl;
+	const struct omap_mmc_of_data *data;
 
 
 	match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
 	match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
 	if (match) {
 	if (match) {
@@ -1768,8 +1860,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
 			return PTR_ERR(pdata);
 			return PTR_ERR(pdata);
 
 
 		if (match->data) {
 		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->base	= ioremap(host->mapbase, SZ_4K);
 	host->power_mode = MMC_POWER_OFF;
 	host->power_mode = MMC_POWER_OFF;
 	host->next_data.cookie = 1;
 	host->next_data.cookie = 1;
+	host->pbias_enabled = 0;
 
 
 	platform_set_drvdata(pdev, host);
 	platform_set_drvdata(pdev, host);
 
 
@@ -1847,10 +1941,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
 
 
 	omap_hsmmc_context_save(host);
 	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");
 	host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
 	/*
 	/*
 	 * MMC can still work without debounce clock.
 	 * MMC can still work without debounce clock.

+ 382 - 147
drivers/mmc/host/rtsx_pci_sdmmc.c

@@ -31,14 +31,9 @@
 #include <linux/mfd/rtsx_pci.h>
 #include <linux/mfd/rtsx_pci.h>
 #include <asm/unaligned.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 {
 struct realtek_pci_sdmmc {
@@ -46,9 +41,18 @@ struct realtek_pci_sdmmc {
 	struct rtsx_pcr		*pcr;
 	struct rtsx_pcr		*pcr;
 	struct mmc_host		*mmc;
 	struct mmc_host		*mmc;
 	struct mmc_request	*mrq;
 	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;
 	u8			ssc_depth;
 	unsigned int		clock;
 	unsigned int		clock;
 	bool			vpclk;
 	bool			vpclk;
@@ -58,8 +62,13 @@ struct realtek_pci_sdmmc {
 	int			power_state;
 	int			power_state;
 #define SDMMC_POWER_ON		1
 #define SDMMC_POWER_ON		1
 #define SDMMC_POWER_OFF		0
 #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)
 static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host)
 {
 {
 	return &(host->pdev->dev);
 	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)
 #define sd_print_debug_regs(host)
 #endif /* DEBUG */
 #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,
 static int sd_read_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt,
 		u8 *buf, int buf_len, int timeout)
 		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;
 	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;
 	struct rtsx_pcr *pcr = host->pcr;
 	u8 cmd_idx = (u8)cmd->opcode;
 	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 err = 0;
 	int timeout = 100;
 	int timeout = 100;
 	int i;
 	int i;
-	u8 *ptr;
-	int stat_idx = 0;
 	u8 rsp_type;
 	u8 rsp_type;
 	int rsp_len = 5;
 	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",
 	dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n",
 			__func__, cmd_idx, arg);
 			__func__, cmd_idx, arg);
@@ -261,6 +361,8 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
 		err = -EINVAL;
 		err = -EINVAL;
 		goto out;
 		goto out;
 	}
 	}
+	host->rsp_type = rsp_type;
+	host->rsp_len = rsp_len;
 
 
 	if (rsp_type == SD_RSP_TYPE_R1b)
 	if (rsp_type == SD_RSP_TYPE_R1b)
 		timeout = 3000;
 		timeout = 3000;
@@ -270,8 +372,6 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
 				0xFF, SD_CLK_TOGGLE_EN);
 				0xFF, SD_CLK_TOGGLE_EN);
 		if (err < 0)
 		if (err < 0)
 			goto out;
 			goto out;
-
-		clock_toggled = true;
 	}
 	}
 
 
 	rtsx_pci_init_cmd(pcr);
 	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 */
 		/* Read data from ping-pong buffer */
 		for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++)
 		for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++)
 			rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0);
 			rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0);
-		stat_idx = 16;
 	} else if (rsp_type != SD_RSP_TYPE_R0) {
 	} else if (rsp_type != SD_RSP_TYPE_R0) {
 		/* Read data from SD_CMDx registers */
 		/* Read data from SD_CMDx registers */
 		for (i = SD_CMD0; i <= SD_CMD4; i++)
 		for (i = SD_CMD0; i <= SD_CMD4; i++)
 			rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0);
 			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);
 	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;
 		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) {
 	if (rsp_type == SD_RSP_TYPE_R0) {
 		err = 0;
 		err = 0;
 		goto out;
 		goto out;
@@ -350,26 +485,106 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
 				cmd->resp[0]);
 				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:
 out:
 	cmd->error = err;
 	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 rtsx_pcr *pcr = host->pcr;
 	struct mmc_host *mmc = host->mmc;
 	struct mmc_host *mmc = host->mmc;
 	struct mmc_card *card = mmc->card;
 	struct mmc_card *card = mmc->card;
 	struct mmc_data *data = mrq->data;
 	struct mmc_data *data = mrq->data;
 	int uhs = mmc_card_uhs(card);
 	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;
 	u8 cfg2, trans_mode;
 	int err;
 	int err;
 	size_t data_len = data->blksz * data->blocks;
 	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) {
 	if (read) {
 		cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
 		cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
 			SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0;
 			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,
 	rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER,
 			SD_TRANSFER_END, SD_TRANSFER_END);
 			SD_TRANSFER_END, SD_TRANSFER_END);
 
 
+	mod_timer(&host->timer, jiffies + 10 * HZ);
 	rtsx_pci_send_cmd_no_wait(pcr);
 	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) {
 	if (err < 0) {
-		sd_clear_error(host);
-		return err;
+		data->error = err;
+		tasklet_schedule(&host->finish_tasklet);
 	}
 	}
-
 	return 0;
 	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)
 static inline void sd_enable_initial_mode(struct realtek_pci_sdmmc *host)
 {
 {
 	rtsx_pci_write_register(host->pcr, SD_CFG1,
 	rtsx_pci_write_register(host->pcr, SD_CFG1,
@@ -511,85 +765,47 @@ static int sd_change_phase(struct realtek_pci_sdmmc *host,
 	return 0;
 	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;
 	return final_phase;
 }
 }
 
 
@@ -635,7 +851,7 @@ static int sd_tuning_phase(struct realtek_pci_sdmmc *host,
 	int err, i;
 	int err, i;
 	u32 raw_phase_map = 0;
 	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);
 		err = sd_tuning_rx_cmd(host, opcode, (u8)i);
 		if (err == 0)
 		if (err == 0)
 			raw_phase_map |= 1 << i;
 			raw_phase_map |= 1 << i;
@@ -685,6 +901,13 @@ static int sd_tuning_rx(struct realtek_pci_sdmmc *host, u8 opcode)
 	return 0;
 	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)
 static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
 {
 {
 	struct realtek_pci_sdmmc *host = mmc_priv(mmc);
 	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;
 	struct mmc_data *data = mrq->data;
 	unsigned int data_size = 0;
 	unsigned int data_size = 0;
 	int err;
 	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) {
 	if (host->eject) {
 		cmd->error = -ENOMEDIUM;
 		cmd->error = -ENOMEDIUM;
@@ -705,8 +936,6 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
 		goto finish;
 		goto finish;
 	}
 	}
 
 
-	mutex_lock(&pcr->pcr_mutex);
-
 	rtsx_pci_start_run(pcr);
 	rtsx_pci_start_run(pcr);
 
 
 	rtsx_pci_switch_clock(pcr, host->clock, host->ssc_depth,
 	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,
 	rtsx_pci_write_register(pcr, CARD_SHARE_MODE,
 			CARD_SHARE_MASK, CARD_SHARE_48_SD);
 			CARD_SHARE_MASK, CARD_SHARE_48_SD);
 
 
-	mutex_lock(&host->host_mutex);
-	host->mrq = mrq;
-	mutex_unlock(&host->host_mutex);
-
 	if (mrq->data)
 	if (mrq->data)
 		data_size = data->blocks * data->blksz;
 		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 {
 	} else {
+		spin_unlock_irqrestore(&host->lock, flags);
 		sd_normal_rw(host, mrq);
 		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:
 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,
 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 = {
 static const struct mmc_host_ops realtek_pci_sdmmc_ops = {
+	.pre_req = sdmmc_pre_req,
+	.post_req = sdmmc_post_req,
 	.request = sdmmc_request,
 	.request = sdmmc_request,
 	.set_ios = sdmmc_set_ios,
 	.set_ios = sdmmc_set_ios,
 	.get_ro = sdmmc_get_ro,
 	.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 realtek_pci_sdmmc *host;
 	struct rtsx_pcr *pcr;
 	struct rtsx_pcr *pcr;
 	struct pcr_handle *handle = pdev->dev.platform_data;
 	struct pcr_handle *handle = pdev->dev.platform_data;
+	unsigned long host_addr;
 
 
 	if (!handle)
 	if (!handle)
 		return -ENXIO;
 		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].p_dev = pdev;
 	pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event;
 	pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event;
 
 
-	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);
 	realtek_init_host(host);
 
 
 	mmc_add_host(mmc);
 	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 realtek_pci_sdmmc *host = platform_get_drvdata(pdev);
 	struct rtsx_pcr *pcr;
 	struct rtsx_pcr *pcr;
 	struct mmc_host *mmc;
 	struct mmc_host *mmc;
+	struct mmc_request *mrq;
+	unsigned long flags;
 
 
 	if (!host)
 	if (!host)
 		return 0;
 		return 0;
@@ -1296,25 +1519,37 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
 	pcr = host->pcr;
 	pcr = host->pcr;
 	pcr->slots[RTSX_SD_CARD].p_dev = NULL;
 	pcr->slots[RTSX_SD_CARD].p_dev = NULL;
 	pcr->slots[RTSX_SD_CARD].card_event = NULL;
 	pcr->slots[RTSX_SD_CARD].card_event = NULL;
+	pcr->slots[RTSX_SD_CARD].done_transfer = NULL;
 	mmc = host->mmc;
 	mmc = host->mmc;
-	host->eject = true;
+	mrq = host->mrq;
 
 
-	mutex_lock(&host->host_mutex);
+	spin_lock_irqsave(&host->lock, flags);
 	if (host->mrq) {
 	if (host->mrq) {
 		dev_dbg(&(pdev->dev),
 		dev_dbg(&(pdev->dev),
 			"%s: Controller removed during transfer\n",
 			"%s: Controller removed during transfer\n",
 			mmc_hostname(mmc));
 			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);
 	mmc_remove_host(mmc);
+	host->eject = true;
+
 	mmc_free_host(mmc);
 	mmc_free_host(mmc);
 
 
 	dev_dbg(&(pdev->dev),
 	dev_dbg(&(pdev->dev),

+ 18 - 62
drivers/mmc/host/sdhci-acpi.c

@@ -31,7 +31,6 @@
 #include <linux/bitops.h>
 #include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/types.h>
 #include <linux/err.h>
 #include <linux/err.h>
-#include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/acpi.h>
 #include <linux/acpi.h>
 #include <linux/pm.h>
 #include <linux/pm.h>
@@ -40,13 +39,15 @@
 
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/pm.h>
 #include <linux/mmc/pm.h>
+#include <linux/mmc/slot-gpio.h>
 #include <linux/mmc/sdhci.h>
 #include <linux/mmc/sdhci.h>
 
 
 #include "sdhci.h"
 #include "sdhci.h"
 
 
 enum {
 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 {
 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 = {
 static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
+	.quirks  = SDHCI_QUIRK_BROKEN_CARD_DETECTION,
 	.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
 	.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
 	.caps    = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD,
 	.caps    = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD,
 	.flags   = SDHCI_ACPI_RUNTIME_PM,
 	.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 = {
 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,
 	.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[] = {
 static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = {
 	{ "80860F14" , "1" , &sdhci_acpi_slot_int_emmc },
 	{ "80860F14" , "1" , &sdhci_acpi_slot_int_emmc },
 	{ "80860F14" , "3" , &sdhci_acpi_slot_int_sd   },
 	{ "80860F14" , "3" , &sdhci_acpi_slot_int_sd   },
+	{ "80860F16" , NULL, &sdhci_acpi_slot_int_sd   },
 	{ "INT33BB"  , "2" , &sdhci_acpi_slot_int_sdio },
 	{ "INT33BB"  , "2" , &sdhci_acpi_slot_int_sdio },
 	{ "INT33C6"  , NULL, &sdhci_acpi_slot_int_sdio },
 	{ "INT33C6"  , NULL, &sdhci_acpi_slot_int_sdio },
 	{ "INT3436"  , 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[] = {
 static const struct acpi_device_id sdhci_acpi_ids[] = {
 	{ "80860F14" },
 	{ "80860F14" },
+	{ "80860F16" },
 	{ "INT33BB"  },
 	{ "INT33BB"  },
 	{ "INT33C6"  },
 	{ "INT33C6"  },
 	{ "INT3436"  },
 	{ "INT3436"  },
@@ -192,59 +197,6 @@ static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(acpi_handle handle,
 	return slot;
 	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)
 static int sdhci_acpi_probe(struct platform_device *pdev)
 {
 {
 	struct device *dev = &pdev->dev;
 	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;
 	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_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;
 			c->use_runtime_pm = false;
+		}
 	}
 	}
 
 
+	err = sdhci_add_host(host);
+	if (err)
+		goto err_free;
+
 	if (c->use_runtime_pm) {
 	if (c->use_runtime_pm) {
 		pm_runtime_set_active(dev);
 		pm_runtime_set_active(dev);
 		pm_suspend_ignore_children(dev, 1);
 		pm_suspend_ignore_children(dev, 1);

+ 36 - 3
drivers/mmc/host/sdhci-bcm-kona.c

@@ -54,6 +54,7 @@
 
 
 struct sdhci_bcm_kona_dev {
 struct sdhci_bcm_kona_dev {
 	struct mutex	write_lock; /* protect back to back writes */
 	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;
 		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",
 	dev_dbg(dev, "non-removable=%c\n",
 		(host->mmc->caps & MMC_CAP_NONREMOVABLE) ? 'Y' : 'N');
 		(host->mmc->caps & MMC_CAP_NONREMOVABLE) ? 'Y' : 'N');
 	dev_dbg(dev, "cd_gpio %c, wp_gpio %c\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);
 	ret = sdhci_bcm_kona_sd_reset(host);
 	if (ret)
 	if (ret)
-		goto err_pltfm_free;
+		goto err_clk_disable;
 
 
 	sdhci_bcm_kona_sd_init(host);
 	sdhci_bcm_kona_sd_init(host);
 
 
@@ -307,6 +326,9 @@ err_remove_host:
 err_reset:
 err_reset:
 	sdhci_bcm_kona_sd_reset(host);
 	sdhci_bcm_kona_sd_reset(host);
 
 
+err_clk_disable:
+	clk_disable_unprepare(kona_dev->external_clk);
+
 err_pltfm_free:
 err_pltfm_free:
 	sdhci_pltfm_free(pdev);
 	sdhci_pltfm_free(pdev);
 
 
@@ -314,9 +336,20 @@ err_pltfm_free:
 	return ret;
 	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 = {
 static struct platform_driver sdhci_bcm_kona_driver = {

+ 1 - 1
drivers/mmc/host/sdhci-dove.c

@@ -208,7 +208,7 @@ static struct platform_driver sdhci_dove_driver = {
 		.name	= "sdhci-dove",
 		.name	= "sdhci-dove",
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
 		.pm	= SDHCI_PLTFM_PMOPS,
 		.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,
 	.probe		= sdhci_dove_probe,
 	.remove		= sdhci_dove_remove,
 	.remove		= sdhci_dove_remove,

+ 618 - 0
drivers/mmc/host/sdhci-msm.c

@@ -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");

+ 20 - 0
drivers/mmc/host/sdhci-pci.c

@@ -610,6 +610,18 @@ static const struct sdhci_pci_fixes sdhci_via = {
 	.probe		= via_probe,
 	.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[] = {
 static const struct pci_device_id pci_ids[] = {
 	{
 	{
 		.vendor		= PCI_VENDOR_ID_RICOH,
 		.vendor		= PCI_VENDOR_ID_RICOH,
@@ -731,6 +743,14 @@ static const struct pci_device_id pci_ids[] = {
 		.driver_data	= (kernel_ulong_t)&sdhci_via,
 		.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,
 		.vendor		= PCI_VENDOR_ID_INTEL,
 		.device		= PCI_DEVICE_ID_INTEL_MRST_SD0,
 		.device		= PCI_DEVICE_ID_INTEL_MRST_SD0,

+ 68 - 0
drivers/mmc/host/sdhci-pxav3.c

@@ -34,6 +34,7 @@
 #include <linux/of_gpio.h>
 #include <linux/of_gpio.h>
 #include <linux/pm.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/pm_runtime.h>
+#include <linux/mbus.h>
 
 
 #include "sdhci.h"
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
 #include "sdhci-pltfm.h"
@@ -57,6 +58,60 @@
 #define SDCE_MISC_INT		(1<<2)
 #define SDCE_MISC_INT		(1<<2)
 #define SDCE_MISC_INT_EN	(1<<1)
 #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)
 static void pxav3_set_private_registers(struct sdhci_host *host, u8 mask)
 {
 {
 	struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
 	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 = "mrvl,pxav3-mmc",
 	},
 	},
+	{
+		.compatible = "marvell,armada-380-sdhci",
+	},
 	{},
 	{},
 };
 };
 MODULE_DEVICE_TABLE(of, sdhci_pxav3_of_match);
 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_pltfm_host *pltfm_host;
 	struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
 	struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
 	struct device *dev = &pdev->dev;
 	struct device *dev = &pdev->dev;
+	struct device_node *np = pdev->dev.of_node;
 	struct sdhci_host *host = NULL;
 	struct sdhci_host *host = NULL;
 	struct sdhci_pxa *pxa = NULL;
 	struct sdhci_pxa *pxa = NULL;
 	const struct of_device_id *match;
 	const struct of_device_id *match;
@@ -235,6 +294,14 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
 		kfree(pxa);
 		kfree(pxa);
 		return PTR_ERR(host);
 		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 = sdhci_priv(host);
 	pltfm_host->priv = pxa;
 	pltfm_host->priv = pxa;
 
 
@@ -321,6 +388,7 @@ err_add_host:
 	clk_disable_unprepare(clk);
 	clk_disable_unprepare(clk);
 	clk_put(clk);
 	clk_put(clk);
 err_clk_get:
 err_clk_get:
+err_mbus_win:
 	sdhci_pltfm_free(pdev);
 	sdhci_pltfm_free(pdev);
 	kfree(pxa);
 	kfree(pxa);
 	return ret;
 	return ret;

+ 77 - 93
drivers/mmc/host/sdhci-s3c.c

@@ -51,12 +51,13 @@ struct sdhci_s3c {
 	struct platform_device	*pdev;
 	struct platform_device	*pdev;
 	struct resource		*ioarea;
 	struct resource		*ioarea;
 	struct s3c_sdhci_platdata *pdata;
 	struct s3c_sdhci_platdata *pdata;
-	unsigned int		cur_clk;
+	int			cur_clk;
 	int			ext_cd_irq;
 	int			ext_cd_irq;
 	int			ext_cd_gpio;
 	int			ext_cd_gpio;
 
 
 	struct clk		*clk_io;
 	struct clk		*clk_io;
 	struct clk		*clk_bus[MAX_BUS_CLK];
 	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);
 	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.
  * sdhci_s3c_get_max_clk - callback to get maximum clock frequency.
  * @host: The SDHCI host instance.
  * @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)
 static unsigned int sdhci_s3c_get_max_clk(struct sdhci_host *host)
 {
 {
 	struct sdhci_s3c *ourhost = to_s3c(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)
 		if (rate > max)
 			max = rate;
 			max = rate;
 	}
 	}
@@ -144,9 +110,9 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,
 {
 {
 	unsigned long rate;
 	unsigned long rate;
 	struct clk *clksrc = ourhost->clk_bus[src];
 	struct clk *clksrc = ourhost->clk_bus[src];
-	int div;
+	int shift;
 
 
-	if (!clksrc)
+	if (IS_ERR(clksrc))
 		return UINT_MAX;
 		return UINT_MAX;
 
 
 	/*
 	/*
@@ -158,17 +124,24 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,
 		return wanted - rate;
 		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;
 			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",
 	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];
 		struct clk *clk = ourhost->clk_bus[best_src];
 
 
 		clk_prepare_enable(clk);
 		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;
 		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 */
 	/* reprogram default hardware configuration */
 	writel(S3C64XX_SDHCI_CONTROL4_DRIVE_9mA,
 	writel(S3C64XX_SDHCI_CONTROL4_DRIVE_9mA,
 		host->ioaddr + S3C64XX_SDHCI_CONTROL4);
 		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)
 static unsigned int sdhci_s3c_get_min_clock(struct sdhci_host *host)
 {
 {
 	struct sdhci_s3c *ourhost = to_s3c(host);
 	struct sdhci_s3c *ourhost = to_s3c(host);
-	unsigned int delta, min = UINT_MAX;
+	unsigned long rate, min = ULONG_MAX;
 	int src;
 	int src;
 
 
 	for (src = 0; src < MAX_BUS_CLK; 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;
 			continue;
-		/* delta is a negative value in this case */
-		if (-delta < min)
-			min = -delta;
+		if (rate < min)
+			min = rate;
 	}
 	}
+
 	return min;
 	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)
 static unsigned int sdhci_cmu_get_max_clock(struct sdhci_host *host)
 {
 {
 	struct sdhci_s3c *ourhost = to_s3c(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. */
 /* sdhci_cmu_get_min_clock - callback to get minimal supported clock value. */
 static unsigned int sdhci_cmu_get_min_clock(struct sdhci_host *host)
 static unsigned int sdhci_cmu_get_min_clock(struct sdhci_host *host)
 {
 {
 	struct sdhci_s3c *ourhost = to_s3c(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.*/
 /* 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->host = host;
 	sc->pdev = pdev;
 	sc->pdev = pdev;
 	sc->pdata = pdata;
 	sc->pdata = pdata;
+	sc->cur_clk = -1;
 
 
 	platform_set_drvdata(pdev, host);
 	platform_set_drvdata(pdev, host);
 
 
@@ -566,25 +566,18 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
 	clk_prepare_enable(sc->clk_io);
 	clk_prepare_enable(sc->clk_io);
 
 
 	for (clks = 0, ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
 	for (clks = 0, ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
-		struct clk *clk;
 		char name[14];
 		char name[14];
 
 
 		snprintf(name, 14, "mmc_busclk.%d", ptr);
 		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;
 			continue;
 
 
 		clks++;
 		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",
 		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) {
 	if (clks == 0) {
@@ -593,10 +586,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
 		goto err_no_busclks;
 		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);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	host->ioaddr = devm_ioremap_resource(&pdev->dev, res);
 	host->ioaddr = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(host->ioaddr)) {
 	if (IS_ERR(host->ioaddr)) {
@@ -709,10 +698,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
 	return 0;
 	return 0;
 
 
  err_req_regs:
  err_req_regs:
-#ifndef CONFIG_PM_RUNTIME
-	clk_disable_unprepare(sc->clk_bus[sc->cur_clk]);
-#endif
-
  err_no_busclks:
  err_no_busclks:
 	clk_disable_unprepare(sc->clk_io);
 	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_dont_use_autosuspend(&pdev->dev);
 	pm_runtime_disable(&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);
 	clk_disable_unprepare(sc->clk_io);
 
 
 	sdhci_free_host(host);
 	sdhci_free_host(host);
@@ -779,7 +761,8 @@ static int sdhci_s3c_runtime_suspend(struct device *dev)
 
 
 	ret = sdhci_runtime_suspend_host(host);
 	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);
 	clk_disable_unprepare(busclk);
 	return ret;
 	return ret;
 }
 }
@@ -792,7 +775,8 @@ static int sdhci_s3c_runtime_resume(struct device *dev)
 	int ret;
 	int ret;
 
 
 	clk_prepare_enable(busclk);
 	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);
 	ret = sdhci_runtime_resume_host(host);
 	return ret;
 	return ret;
 }
 }

+ 47 - 152
drivers/mmc/host/sdhci-spear.c

@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/sdhci-spear.h>
 #include <linux/mmc/sdhci-spear.h>
+#include <linux/mmc/slot-gpio.h>
 #include <linux/io.h>
 #include <linux/io.h>
 #include "sdhci.h"
 #include "sdhci.h"
 
 
@@ -40,36 +41,6 @@ static const struct sdhci_ops sdhci_pltfm_ops = {
 	/* Nothing to do for now. */
 	/* 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
 #ifdef CONFIG_OF
 static struct sdhci_plat_data *sdhci_probe_config_dt(struct platform_device *pdev)
 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 pdata is required */
 	if (cd_gpio != -1) {
 	if (cd_gpio != -1) {
 		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-		if (!pdata) {
+		if (!pdata)
 			dev_err(&pdev->dev, "DT: kzalloc failed\n");
 			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;
 	return pdata;
 }
 }
 #else
 #else
@@ -107,41 +76,44 @@ static int sdhci_probe(struct platform_device *pdev)
 	struct sdhci_host *host;
 	struct sdhci_host *host;
 	struct resource *iomem;
 	struct resource *iomem;
 	struct spear_sdhci *sdhci;
 	struct spear_sdhci *sdhci;
+	struct device *dev;
 	int ret;
 	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;
 		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 */
 	/* clk enable */
-	sdhci->clk = clk_get(&pdev->dev, NULL);
+	sdhci->clk = devm_clk_get(&pdev->dev, NULL);
 	if (IS_ERR(sdhci->clk)) {
 	if (IS_ERR(sdhci->clk)) {
 		ret = PTR_ERR(sdhci->clk);
 		ret = PTR_ERR(sdhci->clk);
 		dev_dbg(&pdev->dev, "Error getting clock\n");
 		dev_dbg(&pdev->dev, "Error getting clock\n");
-		goto err;
+		goto err_host;
 	}
 	}
 
 
 	ret = clk_prepare_enable(sdhci->clk);
 	ret = clk_prepare_enable(sdhci->clk);
 	if (ret) {
 	if (ret) {
 		dev_dbg(&pdev->dev, "Error enabling clock\n");
 		dev_dbg(&pdev->dev, "Error enabling clock\n");
-		goto put_clk;
+		goto err_host;
 	}
 	}
 
 
 	ret = clk_set_rate(sdhci->clk, 50000000);
 	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);
 		sdhci->data = sdhci_probe_config_dt(pdev);
 		if (IS_ERR(sdhci->data)) {
 		if (IS_ERR(sdhci->data)) {
 			dev_err(&pdev->dev, "DT: Failed to get pdata\n");
 			dev_err(&pdev->dev, "DT: Failed to get pdata\n");
-			return -ENODEV;
+			goto disable_clk;
 		}
 		}
 	} else {
 	} else {
 		sdhci->data = dev_get_platdata(&pdev->dev);
 		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);
 	ret = sdhci_add_host(host);
 	if (ret) {
 	if (ret) {
 		dev_dbg(&pdev->dev, "error adding host\n");
 		dev_dbg(&pdev->dev, "error adding host\n");
-		goto free_host;
+		goto disable_clk;
 	}
 	}
 
 
 	platform_set_drvdata(pdev, host);
 	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;
 	return 0;
 
 
-set_drvdata:
-	sdhci_remove_host(host, 1);
-free_host:
-	sdhci_free_host(host);
 disable_clk:
 disable_clk:
 	clk_disable_unprepare(sdhci->clk);
 	clk_disable_unprepare(sdhci->clk);
-put_clk:
-	clk_put(sdhci->clk);
+err_host:
+	sdhci_free_host(host);
 err:
 err:
 	dev_err(&pdev->dev, "spear-sdhci probe failed: %d\n", ret);
 	dev_err(&pdev->dev, "spear-sdhci probe failed: %d\n", ret);
 	return ret;
 	return ret;
@@ -273,7 +169,7 @@ err:
 static int sdhci_remove(struct platform_device *pdev)
 static int sdhci_remove(struct platform_device *pdev)
 {
 {
 	struct sdhci_host *host = platform_get_drvdata(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;
 	int dead = 0;
 	u32 scratch;
 	u32 scratch;
 
 
@@ -282,9 +178,8 @@ static int sdhci_remove(struct platform_device *pdev)
 		dead = 1;
 		dead = 1;
 
 
 	sdhci_remove_host(host, dead);
 	sdhci_remove_host(host, dead);
-	sdhci_free_host(host);
 	clk_disable_unprepare(sdhci->clk);
 	clk_disable_unprepare(sdhci->clk);
-	clk_put(sdhci->clk);
+	sdhci_free_host(host);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -293,7 +188,7 @@ static int sdhci_remove(struct platform_device *pdev)
 static int sdhci_suspend(struct device *dev)
 static int sdhci_suspend(struct device *dev)
 {
 {
 	struct sdhci_host *host = dev_get_drvdata(dev);
 	struct sdhci_host *host = dev_get_drvdata(dev);
-	struct spear_sdhci *sdhci = dev_get_platdata(dev);
+	struct spear_sdhci *sdhci = sdhci_priv(host);
 	int ret;
 	int ret;
 
 
 	ret = sdhci_suspend_host(host);
 	ret = sdhci_suspend_host(host);
@@ -306,7 +201,7 @@ static int sdhci_suspend(struct device *dev)
 static int sdhci_resume(struct device *dev)
 static int sdhci_resume(struct device *dev)
 {
 {
 	struct sdhci_host *host = dev_get_drvdata(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;
 	int ret;
 
 
 	ret = clk_enable(sdhci->clk);
 	ret = clk_enable(sdhci->clk);

+ 11 - 13
drivers/mmc/host/sdhci.c

@@ -675,12 +675,12 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
 		return 0xE;
 		return 0xE;
 
 
 	/* Unspecified timeout, assume max */
 	/* Unspecified timeout, assume max */
-	if (!data && !cmd->cmd_timeout_ms)
+	if (!data && !cmd->busy_timeout)
 		return 0xE;
 		return 0xE;
 
 
 	/* timeout in us */
 	/* timeout in us */
 	if (!data)
 	if (!data)
-		target_timeout = cmd->cmd_timeout_ms * 1000;
+		target_timeout = cmd->busy_timeout * 1000;
 	else {
 	else {
 		target_timeout = data->timeout_ns / 1000;
 		target_timeout = data->timeout_ns / 1000;
 		if (host->clock)
 		if (host->clock)
@@ -1019,8 +1019,8 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 	}
 	}
 
 
 	timeout = jiffies;
 	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
 	else
 		timeout += 10 * HZ;
 		timeout += 10 * HZ;
 	mod_timer(&host->timer, timeout);
 	mod_timer(&host->timer, timeout);
@@ -2026,12 +2026,11 @@ out:
 			host->tuning_count * HZ);
 			host->tuning_count * HZ);
 		/* Tuning mode 1 limits the maximum data length to 4MB */
 		/* Tuning mode 1 limits the maximum data length to 4MB */
 		mmc->max_blk_count = (4 * 1024 * 1024) / mmc->max_blk_size;
 		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;
 		host->flags &= ~SDHCI_NEEDS_RETUNING;
 		/* Reload the new initial value for timer */
 		/* 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) {
 	if (host->runtime_suspended) {
 		spin_unlock(&host->lock);
 		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);
 	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)
 	if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
 		host->timeout_clk = mmc->f_max / 1000;
 		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;
 	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)
 	} else if (caps[1] & SDHCI_SUPPORT_SDR50)
 		mmc->caps |= MMC_CAP_UHS_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;
 		mmc->caps |= MMC_CAP_UHS_DDR50;
 
 
 	/* Does the host need tuning for SDR50? */
 	/* Does the host need tuning for SDR50? */

+ 33 - 17
drivers/mmc/host/sh_mobile_sdhi.c

@@ -37,6 +37,8 @@
 
 
 struct sh_mobile_sdhi_of_data {
 struct sh_mobile_sdhi_of_data {
 	unsigned long tmio_flags;
 	unsigned long tmio_flags;
+	unsigned long capabilities;
+	unsigned long capabilities2;
 };
 };
 
 
 static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = {
 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 sh_mobile_sdhi {
 	struct clk *clk;
 	struct clk *clk;
 	struct tmio_mmc_data mmc_data;
 	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,
 	.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)
 static int sh_mobile_sdhi_probe(struct platform_device *pdev)
 {
 {
 	const struct of_device_id *of_id =
 	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) {
 	if (of_id && of_id->data) {
 		const struct sh_mobile_sdhi_of_data *of_data = of_id->data;
 		const struct sh_mobile_sdhi_of_data *of_data = of_id->data;
 		mmc_data->flags |= of_data->tmio_flags;
 		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 */
 	/* 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 = {
 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 = {
 static struct platform_driver sh_mobile_sdhi_driver = {

+ 16 - 14
drivers/mmc/host/tmio_mmc.c

@@ -23,38 +23,37 @@
 
 
 #include "tmio_mmc.h"
 #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;
 	int ret;
 
 
-	ret = tmio_mmc_host_suspend(&dev->dev);
+	ret = tmio_mmc_host_suspend(dev);
 
 
 	/* Tell MFD core it can disable us now.*/
 	/* Tell MFD core it can disable us now.*/
 	if (!ret && cell->disable)
 	if (!ret && cell->disable)
-		cell->disable(dev);
+		cell->disable(pdev);
 
 
 	return ret;
 	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;
 	int ret = 0;
 
 
 	/* Tell the MFD core we are ready to be enabled */
 	/* Tell the MFD core we are ready to be enabled */
 	if (cell->resume)
 	if (cell->resume)
-		ret = cell->resume(dev);
+		ret = cell->resume(pdev);
 
 
 	if (!ret)
 	if (!ret)
-		ret = tmio_mmc_host_resume(&dev->dev);
+		ret = tmio_mmc_host_resume(dev);
 
 
 	return ret;
 	return ret;
 }
 }
-#else
-#define tmio_mmc_suspend NULL
-#define tmio_mmc_resume NULL
 #endif
 #endif
 
 
 static int tmio_mmc_probe(struct platform_device *pdev)
 static int tmio_mmc_probe(struct platform_device *pdev)
@@ -134,15 +133,18 @@ static int tmio_mmc_remove(struct platform_device *pdev)
 
 
 /* ------------------- device registration ----------------------- */
 /* ------------------- 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 = {
 static struct platform_driver tmio_mmc_driver = {
 	.driver = {
 	.driver = {
 		.name = "tmio-mmc",
 		.name = "tmio-mmc",
 		.owner = THIS_MODULE,
 		.owner = THIS_MODULE,
+		.pm = &tmio_mmc_dev_pm_ops,
 	},
 	},
 	.probe = tmio_mmc_probe,
 	.probe = tmio_mmc_probe,
 	.remove = tmio_mmc_remove,
 	.remove = tmio_mmc_remove,
-	.suspend = tmio_mmc_suspend,
-	.resume = tmio_mmc_resume,
 };
 };
 
 
 module_platform_driver(tmio_mmc_driver);
 module_platform_driver(tmio_mmc_driver);

+ 3 - 4
drivers/mmc/host/tmio_mmc.h

@@ -162,16 +162,15 @@ static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
 }
 }
 #endif
 #endif
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 int tmio_mmc_host_suspend(struct device *dev);
 int tmio_mmc_host_suspend(struct device *dev);
 int tmio_mmc_host_resume(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
 #endif
 
 
+#ifdef CONFIG_PM_RUNTIME
 int tmio_mmc_host_runtime_suspend(struct device *dev);
 int tmio_mmc_host_runtime_suspend(struct device *dev);
 int tmio_mmc_host_runtime_resume(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)
 static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr)
 {
 {

+ 4 - 3
drivers/mmc/host/tmio_mmc_pio.c

@@ -1142,7 +1142,7 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
 }
 }
 EXPORT_SYMBOL(tmio_mmc_host_remove);
 EXPORT_SYMBOL(tmio_mmc_host_remove);
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 int tmio_mmc_host_suspend(struct device *dev)
 int tmio_mmc_host_suspend(struct device *dev)
 {
 {
 	struct mmc_host *mmc = dev_get_drvdata(dev);
 	struct mmc_host *mmc = dev_get_drvdata(dev);
@@ -1165,9 +1165,9 @@ int tmio_mmc_host_resume(struct device *dev)
 	return 0;
 	return 0;
 }
 }
 EXPORT_SYMBOL(tmio_mmc_host_resume);
 EXPORT_SYMBOL(tmio_mmc_host_resume);
+#endif
 
 
-#endif	/* CONFIG_PM */
-
+#ifdef CONFIG_PM_RUNTIME
 int tmio_mmc_host_runtime_suspend(struct device *dev)
 int tmio_mmc_host_runtime_suspend(struct device *dev)
 {
 {
 	return 0;
 	return 0;
@@ -1184,5 +1184,6 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
 	return 0;
 	return 0;
 }
 }
 EXPORT_SYMBOL(tmio_mmc_host_runtime_resume);
 EXPORT_SYMBOL(tmio_mmc_host_runtime_resume);
+#endif
 
 
 MODULE_LICENSE("GPL v2");
 MODULE_LICENSE("GPL v2");

+ 1 - 1
drivers/mmc/host/ushc.c

@@ -504,7 +504,7 @@ static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id
 		ret = -ENOMEM;
 		ret = -ENOMEM;
 		goto err;
 		goto err;
 	}
 	}
-	ushc->csw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL);
+	ushc->csw = kzalloc(sizeof(struct ushc_csw), GFP_KERNEL);
 	if (ushc->csw == NULL) {
 	if (ushc->csw == NULL) {
 		ret = -ENOMEM;
 		ret = -ENOMEM;
 		goto err;
 		goto err;

+ 3 - 1
drivers/mmc/host/wmt-sdmmc.c

@@ -757,7 +757,7 @@ static int wmt_mci_probe(struct platform_device *pdev)
 	struct device_node *np = pdev->dev.of_node;
 	struct device_node *np = pdev->dev.of_node;
 	const struct of_device_id *of_id =
 	const struct of_device_id *of_id =
 		of_match_device(wmt_mci_dt_ids, &pdev->dev);
 		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 ret;
 	int regular_irq, dma_irq;
 	int regular_irq, dma_irq;
 
 
@@ -766,6 +766,8 @@ static int wmt_mci_probe(struct platform_device *pdev)
 		return -EFAULT;
 		return -EFAULT;
 	}
 	}
 
 
+	wmt_caps = of_id->data;
+
 	if (!np) {
 	if (!np) {
 		dev_err(&pdev->dev, "Missing SDMMC description in devicetree\n");
 		dev_err(&pdev->dev, "Missing SDMMC description in devicetree\n");
 		return -EFAULT;
 		return -EFAULT;

+ 9 - 0
drivers/regulator/Kconfig

@@ -392,6 +392,15 @@ config REGULATOR_PALMAS
 	  on the muxing. This is handled automatically in the driver by
 	  on the muxing. This is handled automatically in the driver by
 	  reading the mux info from OTP.
 	  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
 config REGULATOR_PCAP
 	tristate "Motorola PCAP2 regulator driver"
 	tristate "Motorola PCAP2 regulator driver"
 	depends on EZX_PCAP
 	depends on EZX_PCAP

+ 1 - 0
drivers/regulator/Makefile

@@ -55,6 +55,7 @@ obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
 obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
 obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
 obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
 obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
 obj-$(CONFIG_REGULATOR_TPS51632) += tps51632-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_PCAP) += pcap-regulator.o
 obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
 obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
 obj-$(CONFIG_REGULATOR_RC5T583)  += rc5t583-regulator.o
 obj-$(CONFIG_REGULATOR_RC5T583)  += rc5t583-regulator.o

+ 255 - 0
drivers/regulator/pbias-regulator.c

@@ -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");

+ 1 - 0
include/linux/mfd/rtsx_common.h

@@ -45,6 +45,7 @@ struct platform_device;
 struct rtsx_slot {
 struct rtsx_slot {
 	struct platform_device	*p_dev;
 	struct platform_device	*p_dev;
 	void			(*card_event)(struct platform_device *p_dev);
 	void			(*card_event)(struct platform_device *p_dev);
+	void			(*done_transfer)(struct platform_device *p_dev);
 };
 };
 
 
 #endif
 #endif

+ 7 - 1
include/linux/mfd/rtsx_pci.h

@@ -144,7 +144,7 @@
 #define HOST_TO_DEVICE		0
 #define HOST_TO_DEVICE		0
 #define DEVICE_TO_HOST		1
 #define DEVICE_TO_HOST		1
 
 
-#define MAX_PHASE		31
+#define RTSX_PHASE_MAX		32
 #define RX_TUNING_CNT		3
 #define RX_TUNING_CNT		3
 
 
 /* SG descriptor */
 /* 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_send_cmd(struct rtsx_pcr *pcr, int timeout);
 int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
 int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
 		int num_sg, bool read, int timeout);
 		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_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_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len);
 int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card);
 int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card);

+ 2 - 2
include/linux/mmc/core.h

@@ -95,7 +95,7 @@ struct mmc_command {
  *              actively failing requests
  *              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 */
 	/* Set this flag only for blocking sanitize request */
 	bool			sanitize_busy;
 	bool			sanitize_busy;
 
 
@@ -152,7 +152,7 @@ extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
 	struct mmc_command *, int);
 	struct mmc_command *, int);
 extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
 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,
 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_switch(struct mmc_card *, u8, u8, u8, unsigned int);
 extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
 extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
 
 

+ 2 - 11
include/linux/mmc/host.h

@@ -264,15 +264,12 @@ struct mmc_host {
 	u32			caps2;		/* More host capabilities */
 	u32			caps2;		/* More host capabilities */
 
 
 #define MMC_CAP2_BOOTPART_NOACC	(1 << 0)	/* Boot partition no access */
 #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_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_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_8V_SDR	(1 << 5)        /* can support */
 #define MMC_CAP2_HS200_1_2V_SDR	(1 << 6)        /* can support */
 #define MMC_CAP2_HS200_1_2V_SDR	(1 << 6)        /* can support */
 #define MMC_CAP2_HS200		(MMC_CAP2_HS200_1_8V_SDR | \
 #define MMC_CAP2_HS200		(MMC_CAP2_HS200_1_8V_SDR | \
 				 MMC_CAP2_HS200_1_2V_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_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_CD_ACTIVE_HIGH	(1 << 10)	/* Card-detect signal active high */
 #define MMC_CAP2_RO_ACTIVE_HIGH	(1 << 11)	/* Write-protect 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 | \
 #define MMC_CAP2_PACKED_CMD	(MMC_CAP2_PACKED_RD | \
 				 MMC_CAP2_PACKED_WR)
 				 MMC_CAP2_PACKED_WR)
 #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)	/* Don't power up before scan */
 #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 */
 	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_req_size;	/* maximum number of bytes in one req */
 	unsigned int		max_blk_size;	/* maximum size of one mmc block */
 	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_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 */
 	/* private data */
 	spinlock_t		lock;		/* lock for claim and bus ops */
 	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_detect_change(struct mmc_host *, unsigned long delay);
 void mmc_request_done(struct mmc_host *, struct mmc_request *);
 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)
 static inline void mmc_signal_sdio_irq(struct mmc_host *host)
 {
 {
 	host->ops->enable_sdio_irq(host, 0);
 	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 *);
 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)
 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)
 static inline int mmc_card_keep_power(struct mmc_host *host)

+ 0 - 8
include/linux/mmc/sdhci-spear.h

@@ -18,17 +18,9 @@
 /*
 /*
  * struct sdhci_plat_data: spear sdhci platform data structure
  * 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
  * card_int_gpio: gpio pin used for card detection
  */
  */
 struct sdhci_plat_data {
 struct sdhci_plat_data {
-	int card_power_gpio;
-	int power_active_high;
-	int power_always_enb;
 	int card_int_gpio;
 	int card_int_gpio;
 };
 };
 
 

+ 2 - 0
include/linux/mmc/sdhci.h

@@ -100,6 +100,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_BROKEN_HOST_CONTROL		(1<<5)
 #define SDHCI_QUIRK2_BROKEN_HOST_CONTROL		(1<<5)
 /* Controller does not support HS200 */
 /* Controller does not support HS200 */
 #define SDHCI_QUIRK2_BROKEN_HS200			(1<<6)
 #define SDHCI_QUIRK2_BROKEN_HS200			(1<<6)
+/* Controller does not support DDR50 */
+#define SDHCI_QUIRK2_BROKEN_DDR50			(1<<7)
 
 
 	int irq;		/* Device IRQ */
 	int irq;		/* Device IRQ */
 	void __iomem *ioaddr;	/* Mapped address */
 	void __iomem *ioaddr;	/* Mapped address */

+ 6 - 0
include/linux/mmc/slot-gpio.h

@@ -22,4 +22,10 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio,
 			unsigned int debounce);
 			unsigned int debounce);
 void mmc_gpio_free_cd(struct mmc_host *host);
 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
 #endif

+ 2 - 5
include/linux/platform_data/mmc-msm_sdcc.h

@@ -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/host.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/card.h>

+ 2 - 4
include/linux/platform_data/mmc-mvsdio.h

@@ -1,13 +1,11 @@
 /*
 /*
- * arch/arm/plat-orion/include/plat/mvsdio.h
- *
  * This file is licensed under the terms of the GNU General Public
  * This file is licensed under the terms of the GNU General Public
  * License version 2.  This program is licensed "as is" without any
  * License version 2.  This program is licensed "as is" without any
  * warranty of any kind, whether express or implied.
  * 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>
 #include <linux/mbus.h>