Merge tag 'mmc-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 29 Dec 2018 00:52:18 +0000 (16:52 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 29 Dec 2018 00:52:18 +0000 (16:52 -0800)
Pull MMC updates from Ulf Hansson:
 "This time, this pull request contains changes crossing subsystems and
  archs/platforms, which is mainly because of a bigger modernization of
  moving from legacy GPIO to GPIO descriptors for MMC (by Linus
  Walleij).

  Additionally, once again, I am funneling changes to
  drivers/misc/cardreader/* and drivers/memstick/* through my MMC tree,
  mostly due to that we lack a maintainer for these.

  Summary:

  MMC core:
   - Cleanup BKOPS support
   - Introduce MMC_CAP_SYNC_RUNTIME_PM
   - slot-gpio: Delete legacy slot GPIO handling

  MMC host:
   - alcor: Add new mmc host driver for Alcor Micro PCI based cardreader
   - bcm2835: Several improvements to better recover from errors
   - jz4740: Rework and fixup pre|post_req support
   - mediatek: Add support for SDIO IRQs
   - meson-gx: Improve clock phase management
   - meson-gx: Stop descriptor on errors
   - mmci: Complete the sbc error path by sending a stop command
   - renesas_sdhi/tmio: Fixup reset/resume operations
   - renesas_sdhi: Add support for r8a774c0 and R7S9210
   - renesas_sdhi: Whitelist R8A77990 SDHI
   - renesas_sdhi: Fixup eMMC HS400 compatibility issues for H3 and M3-W
   - rtsx_usb_sdmmc: Re-work card detection/removal support
   - rtsx_usb_sdmmc: Re-work runtime PM support
   - sdhci: Fix timeout loops for some variant drivers
   - sdhci: Improve support for error handling due to failing commands
   - sdhci-acpi/pci: Disable LED control for Intel BYT-based controllers
   - sdhci_am654: Add new SDHCI variant driver to support TI's AM654 SOCs
   - sdhci-of-esdhc: Add support for eMMC HS400 mode
   - sdhci-omap: Fixup reset support
   - sdhci-omap: Workaround errata regarding SDR104/HS200 tuning failures
   - sdhci-msm: Fixup sporadic write transfers issues for SDR104/HS200
   - sdhci-msm: Fixup dynamical clock gating issues
   - various: Complete converting all hosts into using slot GPIO descriptors

  Other:
   - Move GPIO mmc platform data for mips/sh/arm to GPIO descriptors
   - Add new Alcor Micro cardreader PCI driver
   - Support runtime power management for memstick rtsx_usb_ms driver
   - Use USB remote wakeups for card detection for rtsx_usb misc driver"

* tag 'mmc-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (99 commits)
  mmc: mediatek: Add MMC_CAP_SDIO_IRQ support
  mmc: renesas_sdhi_internal_dmac: Whitelist r8a774c0
  dt-bindings: mmc: renesas_sdhi: Add r8a774c0 support
  mmc: core: Cleanup BKOPS support
  mmc: core: Drop redundant check in mmc_send_hpi_cmd()
  mmc: sdhci-omap: Workaround errata regarding SDR104/HS200 tuning failures (i929)
  dt-bindings: sdhci-omap: Add note for cpu_thermal
  mmc: sdhci-acpi: Disable LED control for Intel BYT-based controllers
  mmc: sdhci-pci: Disable LED control for Intel BYT-based controllers
  mmc: sdhci: Add quirk to disable LED control
  mmc: mmci: add variant property to set command stop bit
  misc: alcor_pci: fix spelling mistake "invailid" -> "invalid"
  mmc: meson-gx: add signal resampling
  mmc: meson-gx: align default phase on soc vendor tree
  mmc: meson-gx: remove useless lock
  mmc: meson-gx: make sure the descriptor is stopped on errors
  mmc: sdhci_am654: Add Initial Support for AM654 SDHCI driver
  dt-bindings: mmc: sdhci-of-arasan: Add deprecated message for AM65
  dt-bindings: mmc: sdhci-am654: Document bindings for the host controllers on TI's AM654 SOCs
  mmc: sdhci-msm: avoid unused function warning
  ...

117 files changed:
Documentation/devicetree/bindings/mmc/arasan,sdhci.txt
Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
Documentation/devicetree/bindings/mmc/sdhci-am654.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/sdhci-msm.txt
Documentation/devicetree/bindings/mmc/sdhci-omap.txt
Documentation/devicetree/bindings/mmc/tmio_mmc.txt
arch/arm/mach-ep93xx/simone.c
arch/arm/mach-ep93xx/vision_ep9307.c
arch/arm/mach-imx/mach-pcm043.c
arch/arm/mach-pxa/balloon3.c
arch/arm/mach-pxa/cm-x270.c
arch/arm/mach-pxa/cm-x300.c
arch/arm/mach-pxa/colibri-evalboard.c
arch/arm/mach-pxa/colibri-pxa270-income.c
arch/arm/mach-pxa/corgi.c
arch/arm/mach-pxa/csb726.c
arch/arm/mach-pxa/em-x270.c
arch/arm/mach-pxa/gumstix.c
arch/arm/mach-pxa/idp.c
arch/arm/mach-pxa/littleton.c
arch/arm/mach-pxa/lubbock.c
arch/arm/mach-pxa/magician.c
arch/arm/mach-pxa/mainstone.c
arch/arm/mach-pxa/mioa701.c
arch/arm/mach-pxa/mxm8x10.c
arch/arm/mach-pxa/palm27x.c
arch/arm/mach-pxa/palm27x.h
arch/arm/mach-pxa/palmld.c
arch/arm/mach-pxa/palmt5.c
arch/arm/mach-pxa/palmtc.c
arch/arm/mach-pxa/palmte2.c
arch/arm/mach-pxa/palmtreo.c
arch/arm/mach-pxa/palmtx.c
arch/arm/mach-pxa/palmz72.c
arch/arm/mach-pxa/pcm990-baseboard.c
arch/arm/mach-pxa/poodle.c
arch/arm/mach-pxa/raumfeld.c
arch/arm/mach-pxa/spitz.c
arch/arm/mach-pxa/stargate2.c
arch/arm/mach-pxa/tosa.c
arch/arm/mach-pxa/trizeps4.c
arch/arm/mach-pxa/vpac270.c
arch/arm/mach-pxa/z2.c
arch/arm/mach-pxa/zeus.c
arch/arm/mach-pxa/zylonite.c
arch/arm/mach-pxa/zylonite_pxa300.c
arch/arm/mach-s3c24xx/mach-at2440evb.c
arch/arm/mach-s3c24xx/mach-h1940.c
arch/arm/mach-s3c24xx/mach-mini2440.c
arch/arm/mach-s3c24xx/mach-n30.c
arch/arm/mach-s3c24xx/mach-rx1950.c
arch/mips/include/asm/mach-jz4740/jz4740_mmc.h
arch/mips/jz4740/board-qi_lb60.c
arch/sh/boards/mach-ecovec24/setup.c
drivers/gpio/gpio-pca953x.c
drivers/memstick/core/memstick.c
drivers/memstick/host/rtsx_usb_ms.c
drivers/misc/Makefile
drivers/misc/cardreader/Kconfig
drivers/misc/cardreader/Makefile
drivers/misc/cardreader/alcor_pci.c [new file with mode: 0644]
drivers/misc/cardreader/rtsx_usb.c
drivers/mmc/core/block.c
drivers/mmc/core/card.h
drivers/mmc/core/core.c
drivers/mmc/core/core.h
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/mmc_ops.h
drivers/mmc/core/mmc_test.c
drivers/mmc/core/slot-gpio.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/alcor.c [new file with mode: 0644]
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/bcm2835.c
drivers/mmc/host/dw_mmc-bluefield.c
drivers/mmc/host/jz4740_mmc.c
drivers/mmc/host/meson-gx-mmc.c
drivers/mmc/host/meson-mx-sdio.c
drivers/mmc/host/mmc_spi.c
drivers/mmc/host/mmci.c
drivers/mmc/host/mmci.h
drivers/mmc/host/mtk-sd.c
drivers/mmc/host/of_mmc_spi.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/pxamci.c
drivers/mmc/host/renesas_sdhi_core.c
drivers/mmc/host/renesas_sdhi_internal_dmac.c
drivers/mmc/host/renesas_sdhi_sys_dmac.c
drivers/mmc/host/rtsx_usb_sdmmc.c
drivers/mmc/host/s3cmci.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci-cadence.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-esdhc.h
drivers/mmc/host/sdhci-msm.c
drivers/mmc/host/sdhci-of-arasan.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-omap.c
drivers/mmc/host/sdhci-pci-core.c
drivers/mmc/host/sdhci-xenon-phy.c
drivers/mmc/host/sdhci-xenon.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sdhci_am654.c [new file with mode: 0644]
drivers/mmc/host/tmio_mmc.h
drivers/mmc/host/tmio_mmc_core.c
include/linux/alcor_pci.h [new file with mode: 0644]
include/linux/mfd/tmio.h
include/linux/mmc/host.h
include/linux/mmc/slot-gpio.h
include/linux/platform_data/mmc-esdhc-imx.h
include/linux/platform_data/mmc-pxamci.h
include/linux/platform_data/mmc-s3cmci.h
include/linux/spi/mmc_spi.h
include/uapi/linux/mmc/ioctl.h

index e2effe17f05ed36a7149c65895b308f9505d3145..1edbb049cccb10cead46f0c969ccd08de684b11f 100644 (file)
@@ -16,6 +16,10 @@ Required Properties:
     - "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1": rk3399 eMMC PHY
       For this device it is strongly suggested to include arasan,soc-ctl-syscon.
     - "ti,am654-sdhci-5.1", "arasan,sdhci-5.1": TI AM654 MMC PHY
+       Note: This binding has been deprecated and moved to [5].
+
+  [5] Documentation/devicetree/bindings/mmc/sdhci-am654.txt
+
   - reg: From mmc bindings: Register location and length.
   - clocks: From clock bindings: Handles to clock inputs.
   - clock-names: From clock bindings: Tuple including "clk_xin" and "clk_ahb"
index 3e29050ec769653e54c7631c96e8dc698a2eb150..9201a7d8d7b02e9fb98281a1edcae4e9859757db 100644 (file)
@@ -16,6 +16,7 @@ Required properties:
               "fsl,imx6sl-usdhc"
               "fsl,imx6sx-usdhc"
               "fsl,imx7d-usdhc"
+              "fsl,imx8qxp-usdhc"
 
 Optional properties:
 - fsl,wp-controller : Indicate to use controller internal write protection
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-am654.txt b/Documentation/devicetree/bindings/mmc/sdhci-am654.txt
new file mode 100644 (file)
index 0000000..15dbbba
--- /dev/null
@@ -0,0 +1,36 @@
+Device Tree Bindings for the SDHCI Controllers present on TI's AM654 SOCs
+
+The bindings follow the mmc[1], clock[2] and interrupt[3] bindings.
+Only deviations are documented here.
+
+  [1] Documentation/devicetree/bindings/mmc/mmc.txt
+  [2] Documentation/devicetree/bindings/clock/clock-bindings.txt
+  [3] Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
+
+Required Properties:
+       - compatible: should be "ti,am654-sdhci-5.1"
+       - reg: Must be two entries.
+               - The first should be the sdhci register space
+               - The second should the subsystem/phy register space
+       - clocks: Handles to the clock inputs.
+       - clock-names: Tuple including "clk_xin" and "clk_ahb"
+       - interrupts: Interrupt specifiers
+       - ti,otap-del-sel: Output Tap Delay select
+       - ti,trm-icp: DLL trim select
+       - ti,driver-strength-ohm: driver strength in ohms.
+                                 Valid values are 33, 40, 50, 66 and 100 ohms.
+
+Example:
+
+       sdhci0: sdhci@4f80000 {
+               compatible = "ti,am654-sdhci-5.1";
+               reg = <0x0 0x4f80000 0x0 0x260>, <0x0 0x4f90000 0x0 0x134>;
+               power-domains = <&k3_pds 47>;
+               clocks = <&k3_clks 47 0>, <&k3_clks 47 1>;
+               clock-names = "clk_ahb", "clk_xin";
+               interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
+               sdhci-caps-mask = <0x80000007 0x0>;
+               mmc-ddr-1_8v;
+               ti,otap-del-sel = <0x2>;
+               ti,trm-icp = <0x8>;
+       };
index 502b3b851ebbeb326f12a2741cbd6ded52016319..da4edb146a983f432ca02f739e2483dd900098a1 100644 (file)
@@ -4,15 +4,28 @@ 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:
+- compatible: Should contain a SoC-specific string and a IP version string:
+       version strings:
                "qcom,sdhci-msm-v4" for sdcc versions less than 5.0
-               "qcom,sdhci-msm-v5" for sdcc versions >= 5.0
+               "qcom,sdhci-msm-v5" for sdcc version 5.0
                For SDCC version 5.0.0, MCI registers are removed from SDCC
                interface and some registers are moved to HC. New compatible
                string is added to support this change - "qcom,sdhci-msm-v5".
+       full compatible strings with SoC and version:
+               "qcom,apq8084-sdhci", "qcom,sdhci-msm-v4"
+               "qcom,msm8974-sdhci", "qcom,sdhci-msm-v4"
+               "qcom,msm8916-sdhci", "qcom,sdhci-msm-v4"
+               "qcom,msm8992-sdhci", "qcom,sdhci-msm-v4"
+               "qcom,msm8996-sdhci", "qcom,sdhci-msm-v4"
+               "qcom,sdm845-sdhci", "qcom,sdhci-msm-v5"
+               "qcom,qcs404-sdhci", "qcom,sdhci-msm-v5"
+       NOTE that some old device tree files may be floating around that only
+       have the string "qcom,sdhci-msm-v4" without the SoC compatible string
+       but doing that should be considered a deprecated practice.
+
 - reg: Base address and length of the register in the following order:
        - Host controller register map (required)
-       - SD Core register map (required)
+       - SD Core register map (required for msm-v4 and below)
 - interrupts: Should contain an interrupt-specifiers for the interrupts:
        - Host controller interrupt (required)
 - pinctrl-names: Should contain only one value - "default".
@@ -29,7 +42,7 @@ Required properties:
 Example:
 
        sdhc_1: sdhci@f9824900 {
-               compatible = "qcom,sdhci-msm-v4";
+               compatible = "qcom,msm8974-sdhci", "qcom,sdhci-msm-v4";
                reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
                interrupts = <0 123 0>;
                bus-width = <8>;
@@ -46,7 +59,7 @@ Example:
        };
 
        sdhc_2: sdhci@f98a4900 {
-               compatible = "qcom,sdhci-msm-v4";
+               compatible = "qcom,msm8974-sdhci", "qcom,sdhci-msm-v4";
                reg = <0xf98a4900 0x11c>, <0xf98a4000 0x800>;
                interrupts = <0 125 0>;
                bus-width = <4>;
index 393848c2138e86f5cc026f1fd04cc68e85916c79..72c4dec7e1db391244bf4ec3da1a7e2bcc43cd86 100644 (file)
@@ -2,6 +2,8 @@
 
 Refer to mmc.txt for standard MMC bindings.
 
+For UHS devices which require tuning, the device tree should have a "cpu_thermal" node which maps to the appropriate thermal zone. This is used to get the temperature of the zone during tuning.
+
 Required properties:
 - compatible: Should be "ti,dra7-sdhci" for DRA7 and DRA72 controllers
              Should be "ti,k2g-sdhci" for K2G
index 27f2eab2981d428c3345ebb7242983477ea78df6..2b4f17ca90876a752ae689c376e613c4a79e4736 100644 (file)
@@ -13,12 +13,14 @@ Required properties:
 - compatible: should contain one or more of the following:
                "renesas,sdhi-sh73a0" - SDHI IP on SH73A0 SoC
                "renesas,sdhi-r7s72100" - SDHI IP on R7S72100 SoC
+               "renesas,sdhi-r7s9210" - SDHI IP on R7S9210 SoC
                "renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC
                "renesas,sdhi-r8a7740" - SDHI IP on R8A7740 SoC
                "renesas,sdhi-r8a7743" - SDHI IP on R8A7743 SoC
                "renesas,sdhi-r8a7744" - SDHI IP on R8A7744 SoC
                "renesas,sdhi-r8a7745" - SDHI IP on R8A7745 SoC
                "renesas,sdhi-r8a774a1" - SDHI IP on R8A774A1 SoC
+               "renesas,sdhi-r8a774c0" - SDHI IP on R8A774C0 SoC
                "renesas,sdhi-r8a77470" - SDHI IP on R8A77470 SoC
                "renesas,sdhi-mmc-r8a77470" - SDHI/MMC IP on R8A77470 SoC
                "renesas,sdhi-r8a7778" - SDHI IP on R8A7778 SoC
@@ -56,7 +58,7 @@ Required properties:
          "core" and "cd". If the controller only has 1 clock, naming is not
          required.
          Devices which have more than 1 clock are listed below:
-         2: R7S72100
+         2: R7S72100, R7S9210
 
 Optional properties:
 - pinctrl-names: should be "default", "state_uhs"
index 41aa5758135665a53e73387509ace6eb76d03ecb..80ccb984d521eccc7cff0e491cba65b67afbd522 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/platform_data/video-ep93xx.h>
 #include <linux/platform_data/spi-ep93xx.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 
 #include <mach/hardware.h>
 #include <mach/gpio-ep93xx.h>
@@ -45,9 +46,15 @@ static struct ep93xxfb_mach_info __initdata simone_fb_info = {
 static struct mmc_spi_platform_data simone_mmc_spi_data = {
        .detect_delay   = 500,
        .ocr_mask       = MMC_VDD_32_33 | MMC_VDD_33_34,
-       .flags          = MMC_SPI_USE_CD_GPIO,
-       .cd_gpio        = EP93XX_GPIO_LINE_EGPIO0,
-       .cd_debounce    = 1,
+};
+
+static struct gpiod_lookup_table simone_mmc_spi_gpio_table = {
+       .dev_id = "mmc_spi.0", /* "mmc_spi" @ CS0 */
+       .table = {
+               /* Card detect */
+               GPIO_LOOKUP_IDX("A", 0, NULL, 0, GPIO_ACTIVE_LOW),
+               { },
+       },
 };
 
 static struct spi_board_info simone_spi_devices[] __initdata = {
@@ -105,6 +112,7 @@ static void __init simone_init_machine(void)
        ep93xx_register_fb(&simone_fb_info);
        ep93xx_register_i2c(simone_i2c_board_info,
                            ARRAY_SIZE(simone_i2c_board_info));
+       gpiod_add_lookup_table(&simone_mmc_spi_gpio_table);
        ep93xx_register_spi(&simone_spi_info, simone_spi_devices,
                            ARRAY_SIZE(simone_spi_devices));
        simone_register_audio();
index 5a0b6187990a9b56497e5d58a0aa9247676b29bf..767ee64628dc352e3b6df6175a2a41918ad9ac04 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/platform_device.h>
 #include <linux/irq.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/fb.h>
 #include <linux/io.h>
 #include <linux/mtd/partitions.h>
@@ -202,13 +203,20 @@ static struct mmc_spi_platform_data vision_spi_mmc_data = {
        .detect_delay   = 100,
        .powerup_msecs  = 100,
        .ocr_mask       = MMC_VDD_32_33 | MMC_VDD_33_34,
-       .flags          = MMC_SPI_USE_CD_GPIO | MMC_SPI_USE_RO_GPIO,
-       .cd_gpio        = EP93XX_GPIO_LINE_EGPIO15,
-       .cd_debounce    = 1,
-       .ro_gpio        = EP93XX_GPIO_LINE_F(0),
        .caps2          = MMC_CAP2_RO_ACTIVE_HIGH,
 };
 
+static struct gpiod_lookup_table vision_spi_mmc_gpio_table = {
+       .dev_id = "mmc_spi.2", /* "mmc_spi @ CS2 */
+       .table = {
+               /* Card detect */
+               GPIO_LOOKUP_IDX("B", 7, NULL, 0, GPIO_ACTIVE_LOW),
+               /* Write protect */
+               GPIO_LOOKUP_IDX("F", 0, NULL, 1, GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 /*************************************************************************
  * SPI Bus
  *************************************************************************/
@@ -286,6 +294,7 @@ static void __init vision_init_machine(void)
 
        ep93xx_register_i2c(vision_i2c_info,
                                ARRAY_SIZE(vision_i2c_info));
+       gpiod_add_lookup_table(&vision_spi_mmc_gpio_table);
        ep93xx_register_spi(&vision_spi_master, vision_spi_board_info,
                                ARRAY_SIZE(vision_spi_board_info));
        vision_register_i2s();
index e595e5368676de1f5f219c74ed8ea37cc217266b..46ba3348e8f0d1cbafa27a22c69b450bd8fae1b0 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/mtd/plat-ram.h>
 #include <linux/memory.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/smc911x.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
@@ -214,8 +215,6 @@ static const iomux_v3_cfg_t pcm043_pads[] __initconst = {
 #define AC97_GPIO_TXFS IMX_GPIO_NR(2, 31)
 #define AC97_GPIO_TXD  IMX_GPIO_NR(2, 28)
 #define AC97_GPIO_RESET        IMX_GPIO_NR(2, 0)
-#define SD1_GPIO_WP    IMX_GPIO_NR(2, 23)
-#define SD1_GPIO_CD    IMX_GPIO_NR(2, 24)
 
 static void pcm043_ac97_warm_reset(struct snd_ac97 *ac97)
 {
@@ -341,12 +340,21 @@ static int __init pcm043_otg_mode(char *options)
 __setup("otg_mode=", pcm043_otg_mode);
 
 static struct esdhc_platform_data sd1_pdata = {
-       .wp_gpio = SD1_GPIO_WP,
-       .cd_gpio = SD1_GPIO_CD,
        .wp_type = ESDHC_WP_GPIO,
        .cd_type = ESDHC_CD_GPIO,
 };
 
+static struct gpiod_lookup_table sd1_gpio_table = {
+       .dev_id = "sdhci-esdhc-imx35.0",
+       .table = {
+               /* Card detect: bank 2 offset 24 */
+               GPIO_LOOKUP("imx35-gpio.2", 24, "cd", GPIO_ACTIVE_LOW),
+               /* Write protect: bank 2 offset 23 */
+               GPIO_LOOKUP("imx35-gpio.2", 23, "wp", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
 /*
  * Board specific initialization.
  */
@@ -391,6 +399,7 @@ static void __init pcm043_late_init(void)
 {
        imx35_add_imx_ssi(0, &pcm043_ssi_pdata);
 
+       gpiod_add_lookup_table(&sd1_gpio_table);
        imx35_add_sdhci_esdhc_imx(0, &sd1_pdata);
 }
 
index c52c081eb6d9dcbc8db7f49df5ce4f8b59f05b3b..4bcbd3d55b367108a372a4fcd95d6ff199473f1c 100644 (file)
@@ -290,9 +290,6 @@ static unsigned long balloon3_mmc_pin_config[] __initdata = {
 
 static struct pxamci_platform_data balloon3_mci_platform_data = {
        .ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
-       .gpio_card_detect       = -1,
-       .gpio_card_ro           = -1,
-       .gpio_power             = -1,
        .detect_delay_ms        = 200,
 };
 
index be4a66166d6196b2838605db2857e8b5cd012f97..f7081a50dc67052ba27364847eaade6b919fa8c7 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/platform_device.h>
 #include <linux/irq.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/delay.h>
 
 #include <linux/platform_data/rtc-v3020.h>
@@ -288,14 +289,23 @@ static inline void cmx270_init_ohci(void) {}
 #if defined(CONFIG_MMC) || defined(CONFIG_MMC_MODULE)
 static struct pxamci_platform_data cmx270_mci_platform_data = {
        .ocr_mask               = MMC_VDD_32_33|MMC_VDD_33_34,
-       .gpio_card_detect       = GPIO83_MMC_IRQ,
-       .gpio_card_ro           = -1,
-       .gpio_power             = GPIO105_MMC_POWER,
-       .gpio_power_invert      = 1,
+};
+
+static struct gpiod_lookup_table cmx270_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               /* Card detect on GPIO 83 */
+               GPIO_LOOKUP("gpio-pxa", GPIO83_MMC_IRQ, "cd", GPIO_ACTIVE_LOW),
+               /* Power on GPIO 105 */
+               GPIO_LOOKUP("gpio-pxa", GPIO105_MMC_POWER,
+                           "power", GPIO_ACTIVE_LOW),
+               { },
+       },
 };
 
 static void __init cmx270_init_mmc(void)
 {
+       gpiod_add_lookup_table(&cmx270_mci_gpio_table);
        pxa_set_mci_info(&cmx270_mci_platform_data);
 }
 #else
index c5c0ab8ac9f91991a0cf6791ebb065cd7e055395..109fab292f946070d30163a14a1bbcf21a1f25df 100644 (file)
@@ -459,9 +459,17 @@ static inline void cm_x300_init_nand(void) {}
 static struct pxamci_platform_data cm_x300_mci_platform_data = {
        .detect_delay_ms        = 200,
        .ocr_mask               = MMC_VDD_32_33|MMC_VDD_33_34,
-       .gpio_card_detect       = GPIO82_MMC_IRQ,
-       .gpio_card_ro           = GPIO85_MMC_WP,
-       .gpio_power             = -1,
+};
+
+static struct gpiod_lookup_table cm_x300_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               /* Card detect on GPIO 82 */
+               GPIO_LOOKUP("gpio-pxa", GPIO82_MMC_IRQ, "cd", GPIO_ACTIVE_LOW),
+               /* Write protect on GPIO 85 */
+               GPIO_LOOKUP("gpio-pxa", GPIO85_MMC_WP, "wp", GPIO_ACTIVE_LOW),
+               { },
+       },
 };
 
 /* The second MMC slot of CM-X300 is hardwired to Libertas card and has
@@ -482,13 +490,11 @@ static struct pxamci_platform_data cm_x300_mci2_platform_data = {
        .ocr_mask               = MMC_VDD_32_33|MMC_VDD_33_34,
        .init                   = cm_x300_mci2_init,
        .exit                   = cm_x300_mci2_exit,
-       .gpio_card_detect       = -1,
-       .gpio_card_ro           = -1,
-       .gpio_power             = -1,
 };
 
 static void __init cm_x300_init_mmc(void)
 {
+       gpiod_add_lookup_table(&cm_x300_mci_gpio_table);
        pxa_set_mci_info(&cm_x300_mci_platform_data);
        pxa3xx_set_mci2_info(&cm_x300_mci2_platform_data);
 }
index 10e2278b7a28874d1acf17972075abfd898186b7..2ccdef5de138770e70ebcdf156c68486d603a29f 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
-#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <asm/mach/arch.h>
 #if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE)
 static struct pxamci_platform_data colibri_mci_platform_data = {
        .ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
-       .gpio_power             = -1,
-       .gpio_card_ro           = -1,
        .detect_delay_ms        = 200,
 };
 
+static struct gpiod_lookup_table colibri_pxa270_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", GPIO0_COLIBRI_PXA270_SD_DETECT,
+                           "cd", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
+static struct gpiod_lookup_table colibri_pxa300_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", GPIO13_COLIBRI_PXA300_SD_DETECT,
+                           "cd", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
+static struct gpiod_lookup_table colibri_pxa320_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", GPIO28_COLIBRI_PXA320_SD_DETECT,
+                           "cd", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
 static void __init colibri_mmc_init(void)
 {
        if (machine_is_colibri())       /* PXA270 Colibri */
-               colibri_mci_platform_data.gpio_card_detect =
-                       GPIO0_COLIBRI_PXA270_SD_DETECT;
+               gpiod_add_lookup_table(&colibri_pxa270_mci_gpio_table);
        if (machine_is_colibri300())    /* PXA300 Colibri */
-               colibri_mci_platform_data.gpio_card_detect =
-                       GPIO13_COLIBRI_PXA300_SD_DETECT;
+               gpiod_add_lookup_table(&colibri_pxa300_mci_gpio_table);
        else                            /* PXA320 Colibri */
-               colibri_mci_platform_data.gpio_card_detect =
-                       GPIO28_COLIBRI_PXA320_SD_DETECT;
+               gpiod_add_lookup_table(&colibri_pxa320_mci_gpio_table);
 
        pxa_set_mci_info(&colibri_mci_platform_data);
 }
index 3ccf2a95569bcceeec3afffd262abf7679ae6a4e..d203dd30cdd0121e35606e6d0fe67a9e5df85916 100644 (file)
@@ -14,7 +14,7 @@
 
 #include <linux/bitops.h>
 #include <linux/delay.h>
-#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/leds.h>
 #if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE)
 static struct pxamci_platform_data income_mci_platform_data = {
        .ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
-       .gpio_power             = -1,
-       .gpio_card_detect       = GPIO0_INCOME_SD_DETECT,
-       .gpio_card_ro           = GPIO0_INCOME_SD_RO,
        .detect_delay_ms        = 200,
 };
 
+static struct gpiod_lookup_table income_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               /* Card detect on GPIO 0 */
+               GPIO_LOOKUP("gpio-pxa", GPIO0_INCOME_SD_DETECT,
+                           "cd", GPIO_ACTIVE_LOW),
+               /* Write protect on GPIO 1 */
+               GPIO_LOOKUP("gpio-pxa", GPIO0_INCOME_SD_RO,
+                           "wp", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
 static void __init income_mmc_init(void)
 {
+       gpiod_add_lookup_table(&income_mci_gpio_table);
        pxa_set_mci_info(&income_mci_platform_data);
 }
 #else
index 9a5a35e907690ae708537a7eba93aa3dbfce4cb9..c9732cace5e3e236b1c6108d673250c1f33e100c 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/mtd/physmap.h>
 #include <linux/pm.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/backlight.h>
 #include <linux/i2c.h>
 #include <linux/platform_data/i2c-pxa.h>
@@ -493,11 +494,23 @@ static struct platform_device corgi_audio_device = {
 static struct pxamci_platform_data corgi_mci_platform_data = {
        .detect_delay_ms        = 250,
        .ocr_mask               = MMC_VDD_32_33|MMC_VDD_33_34,
-       .gpio_card_detect       = CORGI_GPIO_nSD_DETECT,
-       .gpio_card_ro           = CORGI_GPIO_nSD_WP,
-       .gpio_power             = CORGI_GPIO_SD_PWR,
 };
 
+static struct gpiod_lookup_table corgi_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               /* Card detect on GPIO 9 */
+               GPIO_LOOKUP("gpio-pxa", CORGI_GPIO_nSD_DETECT,
+                           "cd", GPIO_ACTIVE_LOW),
+               /* Write protect on GPIO 7 */
+               GPIO_LOOKUP("gpio-pxa", CORGI_GPIO_nSD_WP,
+                           "wp", GPIO_ACTIVE_LOW),
+               /* Power on GPIO 33 */
+               GPIO_LOOKUP("gpio-pxa", CORGI_GPIO_SD_PWR,
+                           "power", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
 
 /*
  * Irda
@@ -731,6 +744,7 @@ static void __init corgi_init(void)
        corgi_init_spi();
 
        pxa_set_udc_info(&udc_info);
+       gpiod_add_lookup_table(&corgi_mci_gpio_table);
        pxa_set_mci_info(&corgi_mci_platform_data);
        pxa_set_ficp_info(&corgi_ficp_platform_data);
        pxa_set_i2c_info(NULL);
index 271aedae754209511f5ea96dea482a4a31c648e5..e26e7e60a169a91261acc86b52fe42cf4a1aaf82 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
-#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/physmap.h>
 #include <linux/mtd/partitions.h>
@@ -129,9 +129,19 @@ static struct pxamci_platform_data csb726_mci = {
        .detect_delay_ms        = 500,
        .ocr_mask               = MMC_VDD_32_33|MMC_VDD_33_34,
        /* FIXME setpower */
-       .gpio_card_detect       = CSB726_GPIO_MMC_DETECT,
-       .gpio_card_ro           = CSB726_GPIO_MMC_RO,
-       .gpio_power             = -1,
+};
+
+static struct gpiod_lookup_table csb726_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               /* Card detect on GPIO 100 */
+               GPIO_LOOKUP("gpio-pxa", CSB726_GPIO_MMC_DETECT,
+                           "cd", GPIO_ACTIVE_LOW),
+               /* Write protect on GPIO 101 */
+               GPIO_LOOKUP("gpio-pxa", CSB726_GPIO_MMC_RO,
+                           "wp", GPIO_ACTIVE_LOW),
+               { },
+       },
 };
 
 static struct pxaohci_platform_data csb726_ohci_platform_data = {
@@ -264,6 +274,7 @@ static void __init csb726_init(void)
        pxa_set_stuart_info(NULL);
        pxa_set_i2c_info(NULL);
        pxa27x_set_i2c_power_info(NULL);
+       gpiod_add_lookup_table(&csb726_mci_gpio_table);
        pxa_set_mci_info(&csb726_mci);
        pxa_set_ohci_info(&csb726_ohci_platform_data);
        pxa_set_ac97_info(NULL);
index 67e37df637f5ca23e7038d1c866d26ab50a40746..32c1edeb3f1423ca5eeb7177c5e40a7a25d40f0a 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/input.h>
 #include <linux/gpio_keys.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/mfd/da903x.h>
 #include <linux/regulator/machine.h>
 #include <linux/regulator/fixed.h>
@@ -546,6 +547,15 @@ static inline void em_x270_init_ohci(void) {}
 #if defined(CONFIG_MMC) || defined(CONFIG_MMC_MODULE)
 static struct regulator *em_x270_sdio_ldo;
 
+static struct gpiod_lookup_table em_x270_mci_wp_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               /* Write protect on GPIO 95 */
+               GPIO_LOOKUP("gpio-pxa", GPIO95_MMC_WP, "wp", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
 static int em_x270_mci_init(struct device *dev,
                            irq_handler_t em_x270_detect_int,
                            void *data)
@@ -567,15 +577,7 @@ static int em_x270_mci_init(struct device *dev,
                goto err_irq;
        }
 
-       if (machine_is_em_x270()) {
-               err = gpio_request(GPIO95_MMC_WP, "MMC WP");
-               if (err) {
-                       dev_err(dev, "can't request MMC write protect: %d\n",
-                               err);
-                       goto err_gpio_wp;
-               }
-               gpio_direction_input(GPIO95_MMC_WP);
-       } else {
+       if (!machine_is_em_x270()) {
                err = gpio_request(GPIO38_SD_PWEN, "sdio power");
                if (err) {
                        dev_err(dev, "can't request MMC power control : %d\n",
@@ -615,17 +617,10 @@ static void em_x270_mci_exit(struct device *dev, void *data)
        free_irq(gpio_to_irq(mmc_cd), data);
        regulator_put(em_x270_sdio_ldo);
 
-       if (machine_is_em_x270())
-               gpio_free(GPIO95_MMC_WP);
-       else
+       if (!machine_is_em_x270())
                gpio_free(GPIO38_SD_PWEN);
 }
 
-static int em_x270_mci_get_ro(struct device *dev)
-{
-       return gpio_get_value(GPIO95_MMC_WP);
-}
-
 static struct pxamci_platform_data em_x270_mci_platform_data = {
        .detect_delay_ms        = 250,
        .ocr_mask               = MMC_VDD_20_21|MMC_VDD_21_22|MMC_VDD_22_23|
@@ -635,15 +630,12 @@ static struct pxamci_platform_data em_x270_mci_platform_data = {
        .init                   = em_x270_mci_init,
        .setpower               = em_x270_mci_setpower,
        .exit                   = em_x270_mci_exit,
-       .gpio_card_detect       = -1,
-       .gpio_card_ro           = -1,
-       .gpio_power             = -1,
 };
 
 static void __init em_x270_init_mmc(void)
 {
        if (machine_is_em_x270())
-               em_x270_mci_platform_data.get_ro = em_x270_mci_get_ro;
+               gpiod_add_lookup_table(&em_x270_mci_wp_gpio_table);
 
        pxa_set_mci_info(&em_x270_mci_platform_data);
 }
index 9c5b2fb054f96f1ff527079623597b9325d0bf1a..4764acca548007bb3944cc8dc27d8496cd7f5cc3 100644 (file)
@@ -90,9 +90,6 @@ static struct platform_device *devices[] __initdata = {
 #ifdef CONFIG_MMC_PXA
 static struct pxamci_platform_data gumstix_mci_platform_data = {
        .ocr_mask               = MMC_VDD_32_33|MMC_VDD_33_34,
-       .gpio_card_detect       = -1,
-       .gpio_card_ro           = -1,
-       .gpio_power             = -1,
 };
 
 static void __init gumstix_mmc_init(void)
index 88e0068f92a81c8c1f637809e0af16a493be0c35..7bfc246a1d75201d070ea907a291d69a005f70c0 100644 (file)
@@ -160,9 +160,6 @@ static struct pxafb_mach_info sharp_lm8v31 = {
 
 static struct pxamci_platform_data idp_mci_platform_data = {
        .ocr_mask               = MMC_VDD_32_33|MMC_VDD_33_34,
-       .gpio_card_detect       = -1,
-       .gpio_card_ro           = -1,
-       .gpio_power             = -1,
 };
 
 static void __init idp_init(void)
index 9e132b3e48c68ef767ef7055b8d37cddc9d6453c..8e0b60a33026964efe6849166f104d79a4d4d5ab 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
-#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/pxa2xx_spi.h>
 #include <linux/smc91x.h>
@@ -51,8 +51,6 @@
 
 #include "generic.h"
 
-#define GPIO_MMC1_CARD_DETECT  mfp_to_gpio(MFP_PIN_GPIO15)
-
 /* Littleton MFP configurations */
 static mfp_cfg_t littleton_mfp_cfg[] __initdata = {
        /* LCD */
@@ -278,13 +276,21 @@ static inline void littleton_init_keypad(void) {}
 static struct pxamci_platform_data littleton_mci_platform_data = {
        .detect_delay_ms        = 200,
        .ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
-       .gpio_card_detect       = GPIO_MMC1_CARD_DETECT,
-       .gpio_card_ro           = -1,
-       .gpio_power             = -1,
+};
+
+static struct gpiod_lookup_table littleton_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               /* Card detect on MFP (gpio-pxa) GPIO 15 */
+               GPIO_LOOKUP("gpio-pxa", MFP_PIN_GPIO15,
+                           "cd", GPIO_ACTIVE_LOW),
+               { },
+       },
 };
 
 static void __init littleton_init_mmc(void)
 {
+       gpiod_add_lookup_table(&littleton_mci_gpio_table);
        pxa_set_mci_info(&littleton_mci_platform_data);
 }
 #else
index fe2ef9b78602043efd124b9de80cd96e36754daf..c576e8462043c998009095b6e169b0a3f30641a7 100644 (file)
@@ -440,9 +440,6 @@ static struct pxamci_platform_data lubbock_mci_platform_data = {
        .init                   = lubbock_mci_init,
        .get_ro                 = lubbock_mci_get_ro,
        .exit                   = lubbock_mci_exit,
-       .gpio_card_detect       = -1,
-       .gpio_card_ro           = -1,
-       .gpio_power             = -1,
 };
 
 static void lubbock_irda_transceiver_mode(struct device *dev, int mode)
index 14c0f80bc9e7cf1c7d00e73e65c8eb20e71760f7..08b079653c3f9017c621047af79f836a06a9c430 100644 (file)
@@ -775,12 +775,31 @@ static struct pxamci_platform_data magician_mci_info = {
        .ocr_mask               = MMC_VDD_32_33|MMC_VDD_33_34,
        .init                   = magician_mci_init,
        .exit                   = magician_mci_exit,
-       .gpio_card_detect       = -1,
-       .gpio_card_ro           = EGPIO_MAGICIAN_nSD_READONLY,
        .gpio_card_ro_invert    = 1,
-       .gpio_power             = EGPIO_MAGICIAN_SD_POWER,
 };
 
+/*
+ * Write protect on EGPIO register 5 index 4, this is on the second HTC
+ * EGPIO chip which starts at register 4, so we need offset 8+4=12 on that
+ * particular chip.
+ */
+#define EGPIO_MAGICIAN_nSD_READONLY_OFFSET 12
+/*
+ * Power on EGPIO register 2 index 0, so this is on the first HTC EGPIO chip
+ * starting at register 0 so we need offset 2*8+0 = 16 on that chip.
+ */
+#define EGPIO_MAGICIAN_nSD_POWER_OFFSET 16
+
+static struct gpiod_lookup_table magician_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               GPIO_LOOKUP("htc-egpio-1", EGPIO_MAGICIAN_nSD_READONLY_OFFSET,
+                           "wp", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("htc-egpio-0", EGPIO_MAGICIAN_nSD_POWER_OFFSET,
+                           "power", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
 
 /*
  * USB OHCI
@@ -979,6 +998,7 @@ static void __init magician_init(void)
        i2c_register_board_info(1,
                ARRAY_AND_SIZE(magician_pwr_i2c_board_info));
 
+       gpiod_add_lookup_table(&magician_mci_gpio_table);
        pxa_set_mci_info(&magician_mci_info);
        pxa_set_ohci_info(&magician_ohci_info);
        pxa_set_udc_info(&magician_udc_info);
index afd62a94fdbf2d65d1a009782e9fe267132626ab..9e39fc2ad2d97c6188aeda052067fdfda1329d49 100644 (file)
@@ -361,9 +361,6 @@ static struct pxamci_platform_data mainstone_mci_platform_data = {
        .init                   = mainstone_mci_init,
        .setpower               = mainstone_mci_setpower,
        .exit                   = mainstone_mci_exit,
-       .gpio_card_detect       = -1,
-       .gpio_card_ro           = -1,
-       .gpio_power             = -1,
 };
 
 static void mainstone_irda_transceiver_mode(struct device *dev, int mode)
index 04dc78d0809f820dfcc642185cd81a7a88ed271d..d0fa5c72622d60beb15255332b5bce272abb1bb7 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/rtc.h>
 #include <linux/leds.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/pda_power.h>
@@ -397,9 +398,22 @@ struct gpio_vbus_mach_info gpio_vbus_data = {
 static struct pxamci_platform_data mioa701_mci_info = {
        .detect_delay_ms        = 250,
        .ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
-       .gpio_card_detect       = GPIO15_SDIO_INSERT,
-       .gpio_card_ro           = GPIO78_SDIO_RO,
-       .gpio_power             = GPIO91_SDIO_EN,
+};
+
+static struct gpiod_lookup_table mioa701_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               /* Card detect on GPIO 15 */
+               GPIO_LOOKUP("gpio-pxa", GPIO15_SDIO_INSERT,
+                           "cd", GPIO_ACTIVE_LOW),
+               /* Write protect on GPIO 78 */
+               GPIO_LOOKUP("gpio-pxa", GPIO78_SDIO_RO,
+                           "wp", GPIO_ACTIVE_LOW),
+               /* Power on GPIO 91 */
+               GPIO_LOOKUP("gpio-pxa", GPIO91_SDIO_EN,
+                           "power", GPIO_ACTIVE_HIGH),
+               { },
+       },
 };
 
 /* FlashRAM */
@@ -743,6 +757,7 @@ static void __init mioa701_machine_init(void)
                pr_err("MioA701: Failed to request GPIOs: %d", rc);
        bootstrap_init();
        pxa_set_fb_info(NULL, &mioa701_pxafb_info);
+       gpiod_add_lookup_table(&mioa701_mci_gpio_table);
        pxa_set_mci_info(&mioa701_mci_info);
        pxa_set_keypad_info(&mioa701_keypad_info);
        pxa_set_udc_info(&mioa701_udc_info);
index 616b22397d7351a74e814f9e00f2d9853bc5839d..e4248a3a8dfc193e36a849c501d299e9bbce85f6 100644 (file)
@@ -21,7 +21,7 @@
 
 #include <linux/serial_8250.h>
 #include <linux/dm9000.h>
-#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/platform_data/i2c-pxa.h>
 
 #include <linux/platform_data/mtd-nand-pxa3xx.h>
@@ -326,13 +326,24 @@ static mfp_cfg_t mfp_cfg[] __initdata = {
 static struct pxamci_platform_data mxm_8x10_mci_platform_data = {
        .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
        .detect_delay_ms = 10,
-       .gpio_card_detect = MXM_8X10_SD_nCD,
-       .gpio_card_ro = MXM_8X10_SD_WP,
-       .gpio_power = -1
+};
+
+static struct gpiod_lookup_table mxm_8x10_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               /* Card detect on GPIO 72 */
+               GPIO_LOOKUP("gpio-pxa", MXM_8X10_SD_nCD,
+                           "cd", GPIO_ACTIVE_LOW),
+               /* Write protect on GPIO 84 */
+               GPIO_LOOKUP("gpio-pxa", MXM_8X10_SD_WP,
+                           "wp", GPIO_ACTIVE_LOW),
+               { },
+       },
 };
 
 void __init mxm_8x10_mmc_init(void)
 {
+       gpiod_add_lookup_table(&mxm_8x10_mci_gpio_table);
        pxa_set_mci_info(&mxm_8x10_mci_platform_data);
 }
 #endif
index 1efe9bcf07faa1cdc98373468cb201414b584b05..b94c45f652156604564497172e9014dd7d203077 100644 (file)
@@ -49,14 +49,10 @@ static struct pxamci_platform_data palm27x_mci_platform_data = {
        .detect_delay_ms        = 200,
 };
 
-void __init palm27x_mmc_init(int detect, int ro, int power,
-                                       int power_inverted)
+void __init palm27x_mmc_init(struct gpiod_lookup_table *gtable)
 {
-       palm27x_mci_platform_data.gpio_card_detect      = detect;
-       palm27x_mci_platform_data.gpio_card_ro          = ro;
-       palm27x_mci_platform_data.gpio_power            = power;
-       palm27x_mci_platform_data.gpio_power_invert     = power_inverted;
-
+       if (gtable)
+               gpiod_add_lookup_table(gtable);
        pxa_set_mci_info(&palm27x_mci_platform_data);
 }
 #endif
index 3316ed2016f3c3650e68996976ad798dc481a9de..cd071f87613255faca179a909dcd3806c9aa778a 100644 (file)
 #include <linux/gpio/machine.h>
 
 #if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE)
-extern void __init palm27x_mmc_init(int detect, int ro, int power,
-                                       int power_inverted);
+extern void __init palm27x_mmc_init(struct gpiod_lookup_table *gtable);
 #else
-static inline void palm27x_mmc_init(int detect, int ro, int power,
-                                       int power_inverted)
+static inline void palm27x_mmc_init(struct gpiod_lookup_table *gtable)
 {}
 #endif
 
index a37ceec2290361b65a788eff9c385a6567afde01..bf2b0cfc86df2f13ebcc9fb986c0544df6d33311 100644 (file)
@@ -332,6 +332,19 @@ static void __init palmld_map_io(void)
        iotable_init(palmld_io_desc, ARRAY_SIZE(palmld_io_desc));
 }
 
+static struct gpiod_lookup_table palmld_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMLD_SD_DETECT_N,
+                           "cd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMLD_SD_READONLY,
+                           "wp", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMLD_SD_POWER,
+                           "power", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static void __init palmld_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(palmld_pin_config));
@@ -339,8 +352,7 @@ static void __init palmld_init(void)
        pxa_set_btuart_info(NULL);
        pxa_set_stuart_info(NULL);
 
-       palm27x_mmc_init(GPIO_NR_PALMLD_SD_DETECT_N, GPIO_NR_PALMLD_SD_READONLY,
-                       GPIO_NR_PALMLD_SD_POWER, 0);
+       palm27x_mmc_init(&palmld_mci_gpio_table);
        palm27x_pm_init(PALMLD_STR_BASE);
        palm27x_lcd_init(-1, &palm_320x480_lcd_mode);
        palm27x_irda_init(GPIO_NR_PALMLD_IR_DISABLE);
index 876144aa35648d56d889eee5a696a6e6278a2be7..8811f11f670ea82052c0863c08030b6ce361a46a 100644 (file)
@@ -182,6 +182,19 @@ static void __init palmt5_reserve(void)
        memblock_reserve(0xa0200000, 0x1000);
 }
 
+static struct gpiod_lookup_table palmt5_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMT5_SD_DETECT_N,
+                           "cd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMT5_SD_READONLY,
+                           "wp", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMT5_SD_POWER,
+                           "power", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static void __init palmt5_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(palmt5_pin_config));
@@ -189,8 +202,7 @@ static void __init palmt5_init(void)
        pxa_set_btuart_info(NULL);
        pxa_set_stuart_info(NULL);
 
-       palm27x_mmc_init(GPIO_NR_PALMT5_SD_DETECT_N, GPIO_NR_PALMT5_SD_READONLY,
-                       GPIO_NR_PALMT5_SD_POWER, 0);
+       palm27x_mmc_init(&palmt5_mci_gpio_table);
        palm27x_pm_init(PALMT5_STR_BASE);
        palm27x_lcd_init(-1, &palm_320x480_lcd_mode);
        palm27x_udc_init(GPIO_NR_PALMT5_USB_DETECT_N,
index 18946594a7c85ef720c54901ccdc1075a4c050af..7ce4fc287115aa44c92e6f127d6f5d63264ab76a 100644 (file)
@@ -20,7 +20,7 @@
 #include <linux/input.h>
 #include <linux/pwm.h>
 #include <linux/pwm_backlight.h>
-#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/input/matrix_keypad.h>
 #include <linux/ucb1400.h>
 #include <linux/power_supply.h>
@@ -120,14 +120,25 @@ static unsigned long palmtc_pin_config[] __initdata = {
 #if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE)
 static struct pxamci_platform_data palmtc_mci_platform_data = {
        .ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
-       .gpio_power             = GPIO_NR_PALMTC_SD_POWER,
-       .gpio_card_ro           = GPIO_NR_PALMTC_SD_READONLY,
-       .gpio_card_detect       = GPIO_NR_PALMTC_SD_DETECT_N,
        .detect_delay_ms        = 200,
 };
 
+static struct gpiod_lookup_table palmtc_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMTC_SD_DETECT_N,
+                           "cd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMTC_SD_READONLY,
+                           "wp", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMTC_SD_POWER,
+                           "power", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static void __init palmtc_mmc_init(void)
 {
+       gpiod_add_lookup_table(&palmtc_mci_gpio_table);
        pxa_set_mci_info(&palmtc_mci_platform_data);
 }
 #else
index 36b46141a28b09e30331335019f098fd1c2643a9..e830005af8d0c6089908baa3052f900562f90eb8 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/gpio_keys.h>
+#include <linux/gpio/machine.h>
 #include <linux/input.h>
 #include <linux/pda_power.h>
 #include <linux/pwm.h>
@@ -101,9 +102,19 @@ static unsigned long palmte2_pin_config[] __initdata = {
  ******************************************************************************/
 static struct pxamci_platform_data palmte2_mci_platform_data = {
        .ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
-       .gpio_card_detect       = GPIO_NR_PALMTE2_SD_DETECT_N,
-       .gpio_card_ro           = GPIO_NR_PALMTE2_SD_READONLY,
-       .gpio_power             = GPIO_NR_PALMTE2_SD_POWER,
+};
+
+static struct gpiod_lookup_table palmte2_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMTE2_SD_DETECT_N,
+                           "cd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMTE2_SD_READONLY,
+                           "wp", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMTE2_SD_POWER,
+                           "power", GPIO_ACTIVE_HIGH),
+               { },
+       },
 };
 
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
@@ -354,6 +365,7 @@ static void __init palmte2_init(void)
        pxa_set_stuart_info(NULL);
 
        pxa_set_fb_info(NULL, &palmte2_lcd_screen);
+       gpiod_add_lookup_table(&palmte2_mci_gpio_table);
        pxa_set_mci_info(&palmte2_mci_platform_data);
        palmte2_udc_init();
        pxa_set_ac97_info(&palmte2_ac97_pdata);
index b66b0b11d7172f4ad0e3db9e4a3fc80f0775f04d..70f1a8a3aa9427b26da6934edaa550425020c8fa 100644 (file)
@@ -480,23 +480,46 @@ void __init treo680_gpio_init(void)
        gpio_free(GPIO_NR_TREO680_LCD_EN_N);
 }
 
+static struct gpiod_lookup_table treo680_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_TREO_SD_DETECT_N,
+                           "cd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_TREO680_SD_READONLY,
+                           "wp", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_TREO680_SD_POWER,
+                           "power", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static void __init treo680_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(treo680_pin_config));
        palmphone_common_init();
        treo680_gpio_init();
-       palm27x_mmc_init(GPIO_NR_TREO_SD_DETECT_N, GPIO_NR_TREO680_SD_READONLY,
-                       GPIO_NR_TREO680_SD_POWER, 0);
+       palm27x_mmc_init(&treo680_mci_gpio_table);
 }
 #endif
 
 #ifdef CONFIG_MACH_CENTRO
+
+static struct gpiod_lookup_table centro685_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_TREO_SD_DETECT_N,
+                           "cd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_CENTRO_SD_POWER,
+                           "power", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
 static void __init centro_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(centro685_pin_config));
        palmphone_common_init();
-       palm27x_mmc_init(GPIO_NR_TREO_SD_DETECT_N, -1,
-                       GPIO_NR_CENTRO_SD_POWER, 1);
+       palm27x_mmc_init(&centro685_mci_gpio_table);
 }
 #endif
 
index 1d06a8e91d8f9376b4a88a93b8dc4f58c9e4911b..ef71bf2abb4761bea3591b618eee1f17b3d40141 100644 (file)
@@ -337,6 +337,19 @@ static void __init palmtx_map_io(void)
        iotable_init(palmtx_io_desc, ARRAY_SIZE(palmtx_io_desc));
 }
 
+static struct gpiod_lookup_table palmtx_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMTX_SD_DETECT_N,
+                           "cd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMTX_SD_READONLY,
+                           "wp", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMTX_SD_POWER,
+                           "power", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 static void __init palmtx_init(void)
 {
        pxa2xx_mfp_config(ARRAY_AND_SIZE(palmtx_pin_config));
@@ -344,8 +357,7 @@ static void __init palmtx_init(void)
        pxa_set_btuart_info(NULL);
        pxa_set_stuart_info(NULL);
 
-       palm27x_mmc_init(GPIO_NR_PALMTX_SD_DETECT_N, GPIO_NR_PALMTX_SD_READONLY,
-                       GPIO_NR_PALMTX_SD_POWER, 0);
+       palm27x_mmc_init(&palmtx_mci_gpio_table);
        palm27x_pm_init(PALMTX_STR_BASE);
        palm27x_lcd_init(-1, &palm_320x480_lcd_mode);
        palm27x_udc_init(GPIO_NR_PALMTX_USB_DETECT_N,
index 4d475f6f4a777081d2e0c9c695ad7ceb26ab399f..ea1c7b2ed8d45c82b683e57b2b8f431fd3042607 100644 (file)
@@ -386,6 +386,19 @@ static void __init palmz72_camera_init(void)
 static inline void palmz72_camera_init(void) {}
 #endif
 
+static struct gpiod_lookup_table palmz72_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMZ72_SD_DETECT_N,
+                           "cd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMZ72_SD_RO,
+                           "wp", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", GPIO_NR_PALMZ72_SD_POWER_N,
+                           "power", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
 /******************************************************************************
  * Machine init
  ******************************************************************************/
@@ -396,8 +409,7 @@ static void __init palmz72_init(void)
        pxa_set_btuart_info(NULL);
        pxa_set_stuart_info(NULL);
 
-       palm27x_mmc_init(GPIO_NR_PALMZ72_SD_DETECT_N, GPIO_NR_PALMZ72_SD_RO,
-                       GPIO_NR_PALMZ72_SD_POWER_N, 1);
+       palm27x_mmc_init(&palmz72_mci_gpio_table);
        palm27x_lcd_init(-1, &palm_320x320_lcd_mode);
        palm27x_udc_init(GPIO_NR_PALMZ72_USB_DETECT_N,
                        GPIO_NR_PALMZ72_USB_PULLUP, 0);
index 973568d4b9ec2d70788083750862df16e2a9e230..be19e3a4eaccc448849b492e4bc0a0acd78861dc 100644 (file)
@@ -370,9 +370,6 @@ static struct pxamci_platform_data pcm990_mci_platform_data = {
        .init                   = pcm990_mci_init,
        .setpower               = pcm990_mci_setpower,
        .exit                   = pcm990_mci_exit,
-       .gpio_card_detect       = -1,
-       .gpio_card_ro           = -1,
-       .gpio_power             = -1,
 };
 
 static struct pxaohci_platform_data pcm990_ohci_platform_data = {
index 1adde1251e2b5bd4b91e8585ff7d8fd2a101ff41..c2a43d4cfd3efb3069d3f1e3b733a119d007b39e 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/delay.h>
 #include <linux/mtd/physmap.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/i2c.h>
 #include <linux/platform_data/i2c-pxa.h>
 #include <linux/regulator/machine.h>
@@ -288,11 +289,18 @@ static struct pxamci_platform_data poodle_mci_platform_data = {
        .init                   = poodle_mci_init,
        .setpower               = poodle_mci_setpower,
        .exit                   = poodle_mci_exit,
-       .gpio_card_detect       = POODLE_GPIO_nSD_DETECT,
-       .gpio_card_ro           = POODLE_GPIO_nSD_WP,
-       .gpio_power             = -1,
 };
 
+static struct gpiod_lookup_table poodle_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", POODLE_GPIO_nSD_DETECT,
+                           "cd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", POODLE_GPIO_nSD_WP,
+                           "wp", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
 
 /*
  * Irda
@@ -439,6 +447,7 @@ static void __init poodle_init(void)
 
        pxa_set_fb_info(&poodle_locomo_device.dev, &poodle_fb_info);
        pxa_set_udc_info(&udc_info);
+       gpiod_add_lookup_table(&poodle_mci_gpio_table);
        pxa_set_mci_info(&poodle_mci_platform_data);
        pxa_set_ficp_info(&poodle_ficp_platform_data);
        pxa_set_i2c_info(NULL);
index bd3c23ad6ce60cb5be94d9548830b2e931eb86a3..e1db072756f255dd79bc7d54226fa5bb9ad11e8d 100644 (file)
@@ -749,9 +749,6 @@ static struct pxamci_platform_data raumfeld_mci_platform_data = {
        .init                   = raumfeld_mci_init,
        .exit                   = raumfeld_mci_exit,
        .detect_delay_ms        = 200,
-       .gpio_card_detect       = -1,
-       .gpio_card_ro           = -1,
-       .gpio_power             = -1,
 };
 
 /*
index 5d50025492b7f2a435f1fc3cc60e88a4e015f49f..306818e2cf545fdba9ab1c990cf2802211180b29 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/gpio_keys.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/leds.h>
 #include <linux/i2c.h>
 #include <linux/platform_data/i2c-pxa.h>
@@ -615,13 +616,22 @@ static struct pxamci_platform_data spitz_mci_platform_data = {
        .detect_delay_ms        = 250,
        .ocr_mask               = MMC_VDD_32_33|MMC_VDD_33_34,
        .setpower               = spitz_mci_setpower,
-       .gpio_card_detect       = SPITZ_GPIO_nSD_DETECT,
-       .gpio_card_ro           = SPITZ_GPIO_nSD_WP,
-       .gpio_power             = -1,
+};
+
+static struct gpiod_lookup_table spitz_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", SPITZ_GPIO_nSD_DETECT,
+                           "cd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", SPITZ_GPIO_nSD_WP,
+                           "wp", GPIO_ACTIVE_LOW),
+               { },
+       },
 };
 
 static void __init spitz_mmc_init(void)
 {
+       gpiod_add_lookup_table(&spitz_mci_gpio_table);
        pxa_set_mci_info(&spitz_mci_platform_data);
 }
 #else
index bbea5fa9a140110fbb6970594b2985c604246c59..e0d6c872270af0d36a199c776962903010531e00 100644 (file)
@@ -436,9 +436,6 @@ static int imote2_mci_get_ro(struct device *dev)
 static struct pxamci_platform_data imote2_mci_platform_data = {
        .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, /* default anyway */
        .get_ro = imote2_mci_get_ro,
-       .gpio_card_detect = -1,
-       .gpio_card_ro   = -1,
-       .gpio_power = -1,
 };
 
 static struct gpio_led imote2_led_pins[] = {
index cb5cd8e78c9400ced4b775e5fbb3b4fa81966315..e8a93c088c35e684eb5db7c58230fba3a2b5e1ac 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/power/gpio-charger.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/pxa2xx_spi.h>
@@ -291,9 +292,19 @@ static struct pxamci_platform_data tosa_mci_platform_data = {
        .ocr_mask               = MMC_VDD_32_33|MMC_VDD_33_34,
        .init                   = tosa_mci_init,
        .exit                   = tosa_mci_exit,
-       .gpio_card_detect       = TOSA_GPIO_nSD_DETECT,
-       .gpio_card_ro           = TOSA_GPIO_SD_WP,
-       .gpio_power             = TOSA_GPIO_PWR_ON,
+};
+
+static struct gpiod_lookup_table tosa_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_nSD_DETECT,
+                           "cd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_SD_WP,
+                           "wp", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", TOSA_GPIO_PWR_ON,
+                           "power", GPIO_ACTIVE_HIGH),
+               { },
+       },
 };
 
 /*
@@ -908,6 +919,7 @@ static void __init tosa_init(void)
        /* enable batt_fault */
        PMCR = 0x01;
 
+       gpiod_add_lookup_table(&tosa_mci_gpio_table);
        pxa_set_mci_info(&tosa_mci_platform_data);
        pxa_set_ficp_info(&tosa_ficp_platform_data);
        pxa_set_i2c_info(NULL);
index 55b8c501b6fc09567771842dd3f01d2c66b08588..c76f1daecfc95209c824bd39294451751485ddf3 100644 (file)
@@ -355,9 +355,6 @@ static struct pxamci_platform_data trizeps4_mci_platform_data = {
        .exit           = trizeps4_mci_exit,
        .get_ro         = NULL, /* write-protection not supported */
        .setpower       = NULL, /* power-switching not supported */
-       .gpio_card_detect = -1,
-       .gpio_card_ro   = -1,
-       .gpio_power     = -1,
 };
 
 /****************************************************************************
index f65dfb6e20e2d0f3e9c1e50f49c6fe2b36a61805..829284406fa3f64dda2c727339fb27341e9120c3 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/input.h>
 #include <linux/leds.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/usb/gpio_vbus.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
@@ -240,14 +241,23 @@ static void __init vpac270_onenand_init(void) {}
 #if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE)
 static struct pxamci_platform_data vpac270_mci_platform_data = {
        .ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
-       .gpio_power             = -1,
-       .gpio_card_detect       = GPIO53_VPAC270_SD_DETECT_N,
-       .gpio_card_ro           = GPIO52_VPAC270_SD_READONLY,
        .detect_delay_ms        = 200,
 };
 
+static struct gpiod_lookup_table vpac270_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", GPIO53_VPAC270_SD_DETECT_N,
+                           "cd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", GPIO52_VPAC270_SD_READONLY,
+                           "wp", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
 static void __init vpac270_mmc_init(void)
 {
+       gpiod_add_lookup_table(&vpac270_mci_gpio_table);
        pxa_set_mci_info(&vpac270_mci_platform_data);
 }
 #else
index 6fffcfc4621e1ac7c78f42640ca735ae7a9d196d..e2353e75bb283291bc7cad821e6b62f479820921 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/power_supply.h>
 #include <linux/mtd/physmap.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/gpio_keys.h>
 #include <linux/delay.h>
 #include <linux/regulator/machine.h>
@@ -290,14 +291,21 @@ static inline void z2_lcd_init(void) {}
 #if defined(CONFIG_MMC_PXA) || defined(CONFIG_MMC_PXA_MODULE)
 static struct pxamci_platform_data z2_mci_platform_data = {
        .ocr_mask               = MMC_VDD_32_33 | MMC_VDD_33_34,
-       .gpio_card_detect       = GPIO96_ZIPITZ2_SD_DETECT,
-       .gpio_power             = -1,
-       .gpio_card_ro           = -1,
        .detect_delay_ms        = 200,
 };
 
+static struct gpiod_lookup_table z2_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", GPIO96_ZIPITZ2_SD_DETECT,
+                           "cd", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
 static void __init z2_mmc_init(void)
 {
+       gpiod_add_lookup_table(&z2_mci_gpio_table);
        pxa_set_mci_info(&z2_mci_platform_data);
 }
 #else
index d53ea12fc76662cad69d5184472f9cfad3e5bf07..897ef59fbe0ca4cbab37c2d57b2d080ccc4248a1 100644 (file)
@@ -663,10 +663,18 @@ static struct pxafb_mach_info zeus_fb_info = {
 static struct pxamci_platform_data zeus_mci_platform_data = {
        .ocr_mask               = MMC_VDD_32_33|MMC_VDD_33_34,
        .detect_delay_ms        = 250,
-       .gpio_card_detect       = ZEUS_MMC_CD_GPIO,
-       .gpio_card_ro           = ZEUS_MMC_WP_GPIO,
        .gpio_card_ro_invert    = 1,
-       .gpio_power             = -1
+};
+
+static struct gpiod_lookup_table zeus_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               GPIO_LOOKUP("gpio-pxa", ZEUS_MMC_CD_GPIO,
+                           "cd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("gpio-pxa", ZEUS_MMC_WP_GPIO,
+                           "wp", GPIO_ACTIVE_HIGH),
+               { },
+       },
 };
 
 /*
@@ -883,6 +891,7 @@ static void __init zeus_init(void)
        else
                pxa_set_fb_info(NULL, &zeus_fb_info);
 
+       gpiod_add_lookup_table(&zeus_mci_gpio_table);
        pxa_set_mci_info(&zeus_mci_platform_data);
        pxa_set_udc_info(&zeus_udc_info);
        pxa_set_ac97_info(&zeus_ac97_info);
index 52e70a5c1281d95b936cd6f4c38704f2432887f8..1f88d7bae84947f10581c937ec9474972a2a4496 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/leds.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
-#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/pwm.h>
 #include <linux/pwm_backlight.h>
 #include <linux/smc91x.h>
@@ -227,33 +227,68 @@ static inline void zylonite_init_lcd(void) {}
 static struct pxamci_platform_data zylonite_mci_platform_data = {
        .detect_delay_ms= 200,
        .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
-       .gpio_card_detect = EXT_GPIO(0),
-       .gpio_card_ro   = EXT_GPIO(2),
-       .gpio_power     = -1,
+};
+
+#define PCA9539A_MCI_CD 0
+#define PCA9539A_MCI1_CD 1
+#define PCA9539A_MCI_WP 2
+#define PCA9539A_MCI1_WP 3
+#define PCA9539A_MCI3_CD 30
+#define PCA9539A_MCI3_WP 31
+
+static struct gpiod_lookup_table zylonite_mci_gpio_table = {
+       .dev_id = "pxa2xx-mci.0",
+       .table = {
+               GPIO_LOOKUP("i2c-pca9539-a", PCA9539A_MCI_CD,
+                           "cd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("i2c-pca9539-a", PCA9539A_MCI_WP,
+                           "wp", GPIO_ACTIVE_LOW),
+               { },
+       },
 };
 
 static struct pxamci_platform_data zylonite_mci2_platform_data = {
        .detect_delay_ms= 200,
        .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
-       .gpio_card_detect = EXT_GPIO(1),
-       .gpio_card_ro   = EXT_GPIO(3),
-       .gpio_power     = -1,
+};
+
+static struct gpiod_lookup_table zylonite_mci2_gpio_table = {
+       .dev_id = "pxa2xx-mci.1",
+       .table = {
+               GPIO_LOOKUP("i2c-pca9539-a", PCA9539A_MCI1_CD,
+                           "cd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("i2c-pca9539-a", PCA9539A_MCI1_WP,
+                           "wp", GPIO_ACTIVE_LOW),
+               { },
+       },
 };
 
 static struct pxamci_platform_data zylonite_mci3_platform_data = {
        .detect_delay_ms= 200,
        .ocr_mask       = MMC_VDD_32_33|MMC_VDD_33_34,
-       .gpio_card_detect = EXT_GPIO(30),
-       .gpio_card_ro   = EXT_GPIO(31),
-       .gpio_power     = -1,
+};
+
+static struct gpiod_lookup_table zylonite_mci3_gpio_table = {
+       .dev_id = "pxa2xx-mci.2",
+       .table = {
+               GPIO_LOOKUP("i2c-pca9539-a", PCA9539A_MCI3_CD,
+                           "cd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("i2c-pca9539-a", PCA9539A_MCI3_WP,
+                           "wp", GPIO_ACTIVE_LOW),
+               { },
+       },
 };
 
 static void __init zylonite_init_mmc(void)
 {
+       gpiod_add_lookup_table(&zylonite_mci_gpio_table);
        pxa_set_mci_info(&zylonite_mci_platform_data);
+       gpiod_add_lookup_table(&zylonite_mci2_gpio_table);
        pxa3xx_set_mci2_info(&zylonite_mci2_platform_data);
-       if (cpu_is_pxa310())
+       if (cpu_is_pxa310()) {
+               gpiod_add_lookup_table(&zylonite_mci3_gpio_table);
                pxa3xx_set_mci3_info(&zylonite_mci3_platform_data);
+       }
 }
 #else
 static inline void zylonite_init_mmc(void) {}
index 0ff4e218080f18f13582193f5e03a811260194eb..8f930a9dd0fd20d0d44f81e2eebbd6e8d436cdc7 100644 (file)
@@ -230,11 +230,13 @@ static struct pca953x_platform_data gpio_exp[] = {
 static struct i2c_board_info zylonite_i2c_board_info[] = {
        {
                .type           = "pca9539",
+               .dev_name       = "pca9539-a",
                .addr           = 0x74,
                .platform_data  = &gpio_exp[0],
                .irq            = PXA_GPIO_TO_IRQ(18),
        }, {
                .type           = "pca9539",
+               .dev_name       = "pca9539-b",
                .addr           = 0x75,
                .platform_data  = &gpio_exp[1],
                .irq            = PXA_GPIO_TO_IRQ(19),
index 68a4fa94257a221aa2e733395e343bb21f8d7c4e..58c5ef3cf1d7e583a4bb49172aad1e7938e318eb 100644 (file)
@@ -9,7 +9,7 @@
 
 #include <linux/kernel.h>
 #include <linux/types.h>
-#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/timer.h>
@@ -136,7 +136,16 @@ static struct platform_device at2440evb_device_eth = {
 };
 
 static struct s3c24xx_mci_pdata at2440evb_mci_pdata __initdata = {
-       .gpio_detect    = S3C2410_GPG(10),
+       /* Intentionally left blank */
+};
+
+static struct gpiod_lookup_table at2440evb_mci_gpio_table = {
+       .dev_id = "s3c2410-sdi",
+       .table = {
+               /* Card detect S3C2410_GPG(10) */
+               GPIO_LOOKUP("GPG", 10, "cd", GPIO_ACTIVE_LOW),
+               { },
+       },
 };
 
 /* 7" LCD panel */
@@ -200,6 +209,7 @@ static void __init at2440evb_init_time(void)
 static void __init at2440evb_init(void)
 {
        s3c24xx_fb_set_platdata(&at2440evb_fb_info);
+       gpiod_add_lookup_table(&at2440evb_mci_gpio_table);
        s3c24xx_mci_set_platdata(&at2440evb_mci_pdata);
        s3c_nand_set_platdata(&at2440evb_nand_info);
        s3c_i2c0_set_platdata(NULL);
index e064c73a57d3a7be05e5575568fd7ce8849ad38e..74d6b68e91c7437aa756cdf453644968818d883e 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/input.h>
 #include <linux/gpio_keys.h>
 #include <linux/pwm.h>
@@ -459,12 +460,21 @@ static void h1940_set_mmc_power(unsigned char power_mode, unsigned short vdd)
 }
 
 static struct s3c24xx_mci_pdata h1940_mmc_cfg __initdata = {
-       .gpio_detect   = S3C2410_GPF(5),
-       .gpio_wprotect = S3C2410_GPH(8),
        .set_power     = h1940_set_mmc_power,
        .ocr_avail     = MMC_VDD_32_33,
 };
 
+static struct gpiod_lookup_table h1940_mmc_gpio_table = {
+       .dev_id = "s3c2410-sdi",
+       .table = {
+               /* Card detect S3C2410_GPF(5) */
+               GPIO_LOOKUP("GPF", 5, "cd", GPIO_ACTIVE_LOW),
+               /* Write protect S3C2410_GPH(8) */
+               GPIO_LOOKUP("GPH", 8, "wp", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
 static struct pwm_lookup h1940_pwm_lookup[] = {
        PWM_LOOKUP("samsung-pwm", 0, "pwm-backlight", NULL, 36296,
                   PWM_POLARITY_NORMAL),
@@ -680,6 +690,7 @@ static void __init h1940_init(void)
        u32 tmp;
 
        s3c24xx_fb_set_platdata(&h1940_fb_info);
+       gpiod_add_lookup_table(&h1940_mmc_gpio_table);
        s3c24xx_mci_set_platdata(&h1940_mmc_cfg);
        s3c24xx_udc_set_platdata(&h1940_udc_cfg);
        s3c24xx_ts_set_platdata(&h1940_ts_cfg);
index 50d67d760efdeef7f3878e00f63195df67336fbf..9035f868fb34e9e70ea656e1e0514dd9dcccde5b 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/input.h>
 #include <linux/io.h>
 #include <linux/serial_core.h>
@@ -234,13 +235,22 @@ static struct s3c2410fb_mach_info mini2440_fb_info __initdata = {
 /* MMC/SD  */
 
 static struct s3c24xx_mci_pdata mini2440_mmc_cfg __initdata = {
-       .gpio_detect            = S3C2410_GPG(8),
-       .gpio_wprotect          = S3C2410_GPH(8),
        .wprotect_invert        = 1,
        .set_power              = NULL,
        .ocr_avail              = MMC_VDD_32_33|MMC_VDD_33_34,
 };
 
+static struct gpiod_lookup_table mini2440_mmc_gpio_table = {
+       .dev_id = "s3c2410-sdi",
+       .table = {
+               /* Card detect S3C2410_GPG(8) */
+               GPIO_LOOKUP("GPG", 8, "cd", GPIO_ACTIVE_LOW),
+               /* Write protect S3C2410_GPH(8) */
+               GPIO_LOOKUP("GPH", 8, "wp", GPIO_ACTIVE_HIGH),
+               { },
+       },
+};
+
 /* NAND Flash on MINI2440 board */
 
 static struct mtd_partition mini2440_default_nand_part[] __initdata = {
@@ -696,6 +706,7 @@ static void __init mini2440_init(void)
        }
 
        s3c24xx_udc_set_platdata(&mini2440_udc_cfg);
+       gpiod_add_lookup_table(&mini2440_mmc_gpio_table);
        s3c24xx_mci_set_platdata(&mini2440_mmc_cfg);
        s3c_nand_set_platdata(&mini2440_nand_info);
        s3c_i2c0_set_platdata(NULL);
index eec51fadb14a3429e012dd19649162ce52ad78e2..d856f23939affd8acc5611f246be722b7d39ff75 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/gpio_keys.h>
 #include <linux/init.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
@@ -350,12 +351,21 @@ static void n30_sdi_set_power(unsigned char power_mode, unsigned short vdd)
 }
 
 static struct s3c24xx_mci_pdata n30_mci_cfg __initdata = {
-       .gpio_detect    = S3C2410_GPF(1),
-       .gpio_wprotect  = S3C2410_GPG(10),
        .ocr_avail      = MMC_VDD_32_33,
        .set_power      = n30_sdi_set_power,
 };
 
+static struct gpiod_lookup_table n30_mci_gpio_table = {
+       .dev_id = "s3c2410-sdi",
+       .table = {
+               /* Card detect S3C2410_GPF(1) */
+               GPIO_LOOKUP("GPF", 1, "cd", GPIO_ACTIVE_LOW),
+               /* Write protect S3C2410_GPG(10) */
+               GPIO_LOOKUP("GPG", 10, "wp", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
 static struct platform_device *n30_devices[] __initdata = {
        &s3c_device_lcd,
        &s3c_device_wdt,
@@ -549,6 +559,7 @@ static void __init n30_init(void)
 
        s3c24xx_fb_set_platdata(&n30_fb_info);
        s3c24xx_udc_set_platdata(&n30_udc_cfg);
+       gpiod_add_lookup_table(&n30_mci_gpio_table);
        s3c24xx_mci_set_platdata(&n30_mci_cfg);
        s3c_i2c0_set_platdata(&n30_i2ccfg);
 
index 7f5a18fa305b9bb60a659234f2b5a210492cf589..29f9b345a5311ffe8879b98f15e1c401a7adf203 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/timer.h>
 #include <linux/init.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/platform_device.h>
 #include <linux/serial_core.h>
 #include <linux/serial_s3c.h>
@@ -558,12 +559,21 @@ static void rx1950_set_mmc_power(unsigned char power_mode, unsigned short vdd)
 }
 
 static struct s3c24xx_mci_pdata rx1950_mmc_cfg __initdata = {
-       .gpio_detect = S3C2410_GPF(5),
-       .gpio_wprotect = S3C2410_GPH(8),
        .set_power = rx1950_set_mmc_power,
        .ocr_avail = MMC_VDD_32_33,
 };
 
+static struct gpiod_lookup_table rx1950_mmc_gpio_table = {
+       .dev_id = "s3c2410-sdi",
+       .table = {
+               /* Card detect S3C2410_GPF(5) */
+               GPIO_LOOKUP("GPF", 5, "cd", GPIO_ACTIVE_LOW),
+               /* Write protect S3C2410_GPH(8) */
+               GPIO_LOOKUP("GPH", 8, "wp", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
 static struct mtd_partition rx1950_nand_part[] = {
        [0] = {
                        .name = "Boot0",
@@ -762,6 +772,7 @@ static void __init rx1950_init_machine(void)
        s3c24xx_fb_set_platdata(&rx1950_lcd_cfg);
        s3c24xx_udc_set_platdata(&rx1950_udc_cfg);
        s3c24xx_ts_set_platdata(&rx1950_ts_cfg);
+       gpiod_add_lookup_table(&rx1950_mmc_gpio_table);
        s3c24xx_mci_set_platdata(&rx1950_mmc_cfg);
        s3c_i2c0_set_platdata(NULL);
        s3c_nand_set_platdata(&rx1950_nand_info);
index e9cc62cfac99d8520ccf9f992c32608199ef17e6..9a7de47c7c79cf8237db9cbe211f5957f474abec 100644 (file)
@@ -3,12 +3,8 @@
 #define __LINUX_MMC_JZ4740_MMC
 
 struct jz4740_mmc_platform_data {
-       int gpio_power;
-       int gpio_card_detect;
-       int gpio_read_only;
        unsigned card_detect_active_low:1;
        unsigned read_only_active_low:1;
-       unsigned power_active_low:1;
 
        unsigned data_1bit:1;
 };
index af0c8ace0141667337e39b615220da512ebc8586..6718efb400f43145974a0a545eeb486d8a58d25b 100644 (file)
@@ -43,9 +43,6 @@
 #include "clock.h"
 
 /* GPIOs */
-#define QI_LB60_GPIO_SD_CD             JZ_GPIO_PORTD(0)
-#define QI_LB60_GPIO_SD_VCC_EN_N       JZ_GPIO_PORTD(2)
-
 #define QI_LB60_GPIO_KEYOUT(x)         (JZ_GPIO_PORTC(10) + (x))
 #define QI_LB60_GPIO_KEYIN(x)          (JZ_GPIO_PORTD(18) + (x))
 #define QI_LB60_GPIO_KEYIN8            JZ_GPIO_PORTD(26)
@@ -386,10 +383,16 @@ static struct platform_device qi_lb60_gpio_keys = {
 };
 
 static struct jz4740_mmc_platform_data qi_lb60_mmc_pdata = {
-       .gpio_card_detect       = QI_LB60_GPIO_SD_CD,
-       .gpio_read_only         = -1,
-       .gpio_power             = QI_LB60_GPIO_SD_VCC_EN_N,
-       .power_active_low       = 1,
+       /* Intentionally left blank */
+};
+
+static struct gpiod_lookup_table qi_lb60_mmc_gpio_table = {
+       .dev_id = "jz4740-mmc.0",
+       .table = {
+               GPIO_LOOKUP("GPIOD", 0, "cd", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("GPIOD", 2, "power", GPIO_ACTIVE_LOW),
+               { },
+       },
 };
 
 /* beeper */
@@ -500,6 +503,7 @@ static int __init qi_lb60_init_platform_devices(void)
        gpiod_add_lookup_table(&qi_lb60_audio_gpio_table);
        gpiod_add_lookup_table(&qi_lb60_nand_gpio_table);
        gpiod_add_lookup_table(&qi_lb60_spigpio_gpio_table);
+       gpiod_add_lookup_table(&qi_lb60_mmc_gpio_table);
 
        spi_register_board_info(qi_lb60_spi_board_info,
                                ARRAY_SIZE(qi_lb60_spi_board_info));
index 06a894526a0b55fd972281ce43a973cdf8c9eea3..058b168bdf26a664d922486569225dd50de73b3e 100644 (file)
@@ -696,13 +696,20 @@ static struct gpiod_lookup_table sdhi0_power_gpiod_table = {
        },
 };
 
+static struct gpiod_lookup_table sdhi0_gpio_table = {
+       .dev_id = "sh_mobile_sdhi.0",
+       .table = {
+               /* Card detect */
+               GPIO_LOOKUP("sh7724_pfc", GPIO_PTY7, "cd", GPIO_ACTIVE_LOW),
+               { },
+       },
+};
+
 static struct tmio_mmc_data sdhi0_info = {
        .chan_priv_tx   = (void *)SHDMA_SLAVE_SDHI0_TX,
        .chan_priv_rx   = (void *)SHDMA_SLAVE_SDHI0_RX,
        .capabilities   = MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD |
                          MMC_CAP_NEEDS_POLL,
-       .flags          = TMIO_MMC_USE_GPIO_CD,
-       .cd_gpio        = GPIO_PTY7,
 };
 
 static struct resource sdhi0_resources[] = {
@@ -735,8 +742,15 @@ static struct tmio_mmc_data sdhi1_info = {
        .chan_priv_rx   = (void *)SHDMA_SLAVE_SDHI1_RX,
        .capabilities   = MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD |
                          MMC_CAP_NEEDS_POLL,
-       .flags          = TMIO_MMC_USE_GPIO_CD,
-       .cd_gpio        = GPIO_PTW7,
+};
+
+static struct gpiod_lookup_table sdhi1_gpio_table = {
+       .dev_id = "sh_mobile_sdhi.1",
+       .table = {
+               /* Card detect */
+               GPIO_LOOKUP("sh7724_pfc", GPIO_PTW7, "cd", GPIO_ACTIVE_LOW),
+               { },
+       },
 };
 
 static struct resource sdhi1_resources[] = {
@@ -776,9 +790,19 @@ static struct mmc_spi_platform_data mmc_spi_info = {
        .caps2 = MMC_CAP2_RO_ACTIVE_HIGH,
        .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, /* 3.3V only */
        .setpower = mmc_spi_setpower,
-       .flags = MMC_SPI_USE_CD_GPIO | MMC_SPI_USE_RO_GPIO,
-       .cd_gpio = GPIO_PTY7,
-       .ro_gpio = GPIO_PTY6,
+};
+
+static struct gpiod_lookup_table mmc_spi_gpio_table = {
+       .dev_id = "mmc_spi.0", /* device "mmc_spi" @ CS0 */
+       .table = {
+               /* Card detect */
+               GPIO_LOOKUP_IDX("sh7724_pfc", GPIO_PTY7, NULL, 0,
+                               GPIO_ACTIVE_LOW),
+               /* Write protect */
+               GPIO_LOOKUP_IDX("sh7724_pfc", GPIO_PTY6, NULL, 1,
+                               GPIO_ACTIVE_HIGH),
+               { },
+       },
 };
 
 static struct spi_board_info spi_bus[] = {
@@ -1282,6 +1306,7 @@ static int __init arch_setup(void)
        gpio_request(GPIO_PTB6, NULL); /* 3.3V power control */
        gpio_direction_output(GPIO_PTB6, 0); /* disable power by default */
 
+       gpiod_add_lookup_table(&mmc_spi_gpio_table);
        spi_register_board_info(spi_bus, ARRAY_SIZE(spi_bus));
 #endif
 
@@ -1434,6 +1459,10 @@ static int __init arch_setup(void)
        gpiod_add_lookup_table(&cn12_power_gpiod_table);
 #if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
        gpiod_add_lookup_table(&sdhi0_power_gpiod_table);
+       gpiod_add_lookup_table(&sdhi0_gpio_table);
+#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
+       gpiod_add_lookup_table(&sdhi1_gpio_table);
+#endif
 #endif
 
        return platform_add_devices(ecovec_devices,
index 023a32cfac42da79789af9026f394eb1fe4a5d5c..540166443c34d07a80c498622ab7425b5e0ee17e 100644 (file)
@@ -449,7 +449,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
 
        gc->base = chip->gpio_start;
        gc->ngpio = gpios;
-       gc->label = chip->client->name;
+       gc->label = dev_name(&chip->client->dev);
        gc->parent = &chip->client->dev;
        gc->owner = THIS_MODULE;
        gc->names = chip->names;
index 76382c858c35435b98e061a7dda49d5dacad9585..1246d69ba187422610fd65f68fba60a2dbd181dd 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 
 #define DRIVER_NAME "memstick"
 
@@ -436,6 +437,7 @@ static void memstick_check(struct work_struct *work)
        struct memstick_dev *card;
 
        dev_dbg(&host->dev, "memstick_check started\n");
+       pm_runtime_get_noresume(host->dev.parent);
        mutex_lock(&host->lock);
        if (!host->card) {
                if (memstick_power_on(host))
@@ -479,6 +481,7 @@ out_power_off:
                host->set_param(host, MEMSTICK_POWER, MEMSTICK_POWER_OFF);
 
        mutex_unlock(&host->lock);
+       pm_runtime_put(host->dev.parent);
        dev_dbg(&host->dev, "memstick_check finished\n");
 }
 
index 4f64563df7ded29f387cc0b32d2e147eb27e6848..97308dc28ccf6c278004250b122b3270df51b2d7 100644 (file)
@@ -40,15 +40,14 @@ struct rtsx_usb_ms {
 
        struct mutex            host_mutex;
        struct work_struct      handle_req;
-
-       struct task_struct      *detect_ms;
-       struct completion       detect_ms_exit;
+       struct delayed_work     poll_card;
 
        u8                      ssc_depth;
        unsigned int            clock;
        int                     power_mode;
        unsigned char           ifmode;
        bool                    eject;
+       bool                    system_suspending;
 };
 
 static inline struct device *ms_dev(struct rtsx_usb_ms *host)
@@ -545,7 +544,7 @@ static void rtsx_usb_ms_handle_req(struct work_struct *work)
                                                host->req->error);
                        }
                } while (!rc);
-               pm_runtime_put(ms_dev(host));
+               pm_runtime_put_sync(ms_dev(host));
        }
 
 }
@@ -585,14 +584,14 @@ static int rtsx_usb_ms_set_param(struct memstick_host *msh,
                        break;
 
                if (value == MEMSTICK_POWER_ON) {
-                       pm_runtime_get_sync(ms_dev(host));
+                       pm_runtime_get_noresume(ms_dev(host));
                        err = ms_power_on(host);
+                       if (err)
+                               pm_runtime_put_noidle(ms_dev(host));
                } else if (value == MEMSTICK_POWER_OFF) {
                        err = ms_power_off(host);
-                       if (host->msh->card)
+                       if (!err)
                                pm_runtime_put_noidle(ms_dev(host));
-                       else
-                               pm_runtime_put(ms_dev(host));
                } else
                        err = -EINVAL;
                if (!err)
@@ -638,12 +637,16 @@ static int rtsx_usb_ms_set_param(struct memstick_host *msh,
        }
 out:
        mutex_unlock(&ucr->dev_mutex);
-       pm_runtime_put(ms_dev(host));
+       pm_runtime_put_sync(ms_dev(host));
 
        /* power-on delay */
-       if (param == MEMSTICK_POWER && value == MEMSTICK_POWER_ON)
+       if (param == MEMSTICK_POWER && value == MEMSTICK_POWER_ON) {
                usleep_range(10000, 12000);
 
+               if (!host->eject)
+                       schedule_delayed_work(&host->poll_card, 100);
+       }
+
        dev_dbg(ms_dev(host), "%s: return = %d\n", __func__, err);
        return err;
 }
@@ -654,9 +657,24 @@ static int rtsx_usb_ms_suspend(struct device *dev)
        struct rtsx_usb_ms *host = dev_get_drvdata(dev);
        struct memstick_host *msh = host->msh;
 
-       dev_dbg(ms_dev(host), "--> %s\n", __func__);
+       /* Since we use rtsx_usb's resume callback to runtime resume its
+        * children to implement remote wakeup signaling, this causes
+        * rtsx_usb_ms' runtime resume callback runs after its suspend
+        * callback:
+        * rtsx_usb_ms_suspend()
+        * rtsx_usb_resume()
+        *   -> rtsx_usb_ms_runtime_resume()
+        *     -> memstick_detect_change()
+        *
+        * rtsx_usb_suspend()
+        *
+        * To avoid this, skip runtime resume/suspend if system suspend is
+        * underway.
+        */
 
+       host->system_suspending = true;
        memstick_suspend_host(msh);
+
        return 0;
 }
 
@@ -665,58 +683,85 @@ static int rtsx_usb_ms_resume(struct device *dev)
        struct rtsx_usb_ms *host = dev_get_drvdata(dev);
        struct memstick_host *msh = host->msh;
 
-       dev_dbg(ms_dev(host), "--> %s\n", __func__);
-
        memstick_resume_host(msh);
+       host->system_suspending = false;
+
        return 0;
 }
 #endif /* CONFIG_PM_SLEEP */
 
-/*
- * Thread function of ms card slot detection. The thread starts right after
- * successful host addition. It stops while the driver removal function sets
- * host->eject true.
- */
-static int rtsx_usb_detect_ms_card(void *__host)
+#ifdef CONFIG_PM
+static int rtsx_usb_ms_runtime_suspend(struct device *dev)
 {
-       struct rtsx_usb_ms *host = (struct rtsx_usb_ms *)__host;
+       struct rtsx_usb_ms *host = dev_get_drvdata(dev);
+
+       if (host->system_suspending)
+               return 0;
+
+       if (host->msh->card || host->power_mode != MEMSTICK_POWER_OFF)
+               return -EAGAIN;
+
+       return 0;
+}
+
+static int rtsx_usb_ms_runtime_resume(struct device *dev)
+{
+       struct rtsx_usb_ms *host = dev_get_drvdata(dev);
+
+
+       if (host->system_suspending)
+               return 0;
+
+       memstick_detect_change(host->msh);
+
+       return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops rtsx_usb_ms_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(rtsx_usb_ms_suspend, rtsx_usb_ms_resume)
+       SET_RUNTIME_PM_OPS(rtsx_usb_ms_runtime_suspend, rtsx_usb_ms_runtime_resume, NULL)
+};
+
+
+static void rtsx_usb_ms_poll_card(struct work_struct *work)
+{
+       struct rtsx_usb_ms *host = container_of(work, struct rtsx_usb_ms,
+                       poll_card.work);
        struct rtsx_ucr *ucr = host->ucr;
-       u8 val = 0;
        int err;
+       u8 val;
 
-       for (;;) {
-               pm_runtime_get_sync(ms_dev(host));
-               mutex_lock(&ucr->dev_mutex);
-
-               /* Check pending MS card changes */
-               err = rtsx_usb_read_register(ucr, CARD_INT_PEND, &val);
-               if (err) {
-                       mutex_unlock(&ucr->dev_mutex);
-                       goto poll_again;
-               }
+       if (host->eject || host->power_mode != MEMSTICK_POWER_ON)
+               return;
 
-               /* Clear the pending */
-               rtsx_usb_write_register(ucr, CARD_INT_PEND,
-                               XD_INT | MS_INT | SD_INT,
-                               XD_INT | MS_INT | SD_INT);
+       pm_runtime_get_sync(ms_dev(host));
+       mutex_lock(&ucr->dev_mutex);
 
+       /* Check pending MS card changes */
+       err = rtsx_usb_read_register(ucr, CARD_INT_PEND, &val);
+       if (err) {
                mutex_unlock(&ucr->dev_mutex);
+               goto poll_again;
+       }
 
-               if (val & MS_INT) {
-                       dev_dbg(ms_dev(host), "MS slot change detected\n");
-                       memstick_detect_change(host->msh);
-               }
+       /* Clear the pending */
+       rtsx_usb_write_register(ucr, CARD_INT_PEND,
+                       XD_INT | MS_INT | SD_INT,
+                       XD_INT | MS_INT | SD_INT);
 
-poll_again:
-               pm_runtime_put(ms_dev(host));
-               if (host->eject)
-                       break;
+       mutex_unlock(&ucr->dev_mutex);
 
-               schedule_timeout_idle(HZ);
+       if (val & MS_INT) {
+               dev_dbg(ms_dev(host), "MS slot change detected\n");
+               memstick_detect_change(host->msh);
        }
 
-       complete(&host->detect_ms_exit);
-       return 0;
+poll_again:
+       pm_runtime_put_sync(ms_dev(host));
+
+       if (!host->eject && host->power_mode == MEMSTICK_POWER_ON)
+               schedule_delayed_work(&host->poll_card, 100);
 }
 
 static int rtsx_usb_ms_drv_probe(struct platform_device *pdev)
@@ -747,45 +792,42 @@ static int rtsx_usb_ms_drv_probe(struct platform_device *pdev)
        mutex_init(&host->host_mutex);
        INIT_WORK(&host->handle_req, rtsx_usb_ms_handle_req);
 
-       init_completion(&host->detect_ms_exit);
-       host->detect_ms = kthread_create(rtsx_usb_detect_ms_card, host,
-                       "rtsx_usb_ms_%d", pdev->id);
-       if (IS_ERR(host->detect_ms)) {
-               dev_dbg(&(pdev->dev),
-                               "Unable to create polling thread.\n");
-               err = PTR_ERR(host->detect_ms);
-               goto err_out;
-       }
+       INIT_DELAYED_WORK(&host->poll_card, rtsx_usb_ms_poll_card);
 
        msh->request = rtsx_usb_ms_request;
        msh->set_param = rtsx_usb_ms_set_param;
        msh->caps = MEMSTICK_CAP_PAR4;
 
-       pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_noresume(ms_dev(host));
+       pm_runtime_set_active(ms_dev(host));
+       pm_runtime_enable(ms_dev(host));
+
        err = memstick_add_host(msh);
        if (err)
                goto err_out;
 
-       wake_up_process(host->detect_ms);
+       pm_runtime_put(ms_dev(host));
+
        return 0;
 err_out:
        memstick_free_host(msh);
+       pm_runtime_disable(ms_dev(host));
+       pm_runtime_put_noidle(ms_dev(host));
        return err;
 }
 
 static int rtsx_usb_ms_drv_remove(struct platform_device *pdev)
 {
        struct rtsx_usb_ms *host = platform_get_drvdata(pdev);
-       struct memstick_host *msh;
+       struct memstick_host *msh = host->msh;
        int err;
 
-       msh = host->msh;
        host->eject = true;
        cancel_work_sync(&host->handle_req);
 
        mutex_lock(&host->host_mutex);
        if (host->req) {
-               dev_dbg(&(pdev->dev),
+               dev_dbg(ms_dev(host),
                        "%s: Controller removed during transfer\n",
                        dev_name(&msh->dev));
                host->req->error = -ENOMEDIUM;
@@ -797,7 +839,6 @@ static int rtsx_usb_ms_drv_remove(struct platform_device *pdev)
        }
        mutex_unlock(&host->host_mutex);
 
-       wait_for_completion(&host->detect_ms_exit);
        memstick_remove_host(msh);
        memstick_free_host(msh);
 
@@ -807,18 +848,15 @@ static int rtsx_usb_ms_drv_remove(struct platform_device *pdev)
        if (pm_runtime_active(ms_dev(host)))
                pm_runtime_put(ms_dev(host));
 
-       pm_runtime_disable(&pdev->dev);
+       pm_runtime_disable(ms_dev(host));
        platform_set_drvdata(pdev, NULL);
 
-       dev_dbg(&(pdev->dev),
+       dev_dbg(ms_dev(host),
                ": Realtek USB Memstick controller has been removed\n");
 
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(rtsx_usb_ms_pm_ops,
-               rtsx_usb_ms_suspend, rtsx_usb_ms_resume);
-
 static struct platform_device_id rtsx_usb_ms_ids[] = {
        {
                .name = "rtsx_usb_ms",
index af22bbc3d00cbcd248c4e10247b87bbb46ecab3f..fe3134cf3008fe9ba16c60a195512580e5cdf2b0 100644 (file)
@@ -57,4 +57,4 @@ obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
 obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
 obj-$(CONFIG_PCI_ENDPOINT_TEST)        += pci_endpoint_test.o
 obj-$(CONFIG_OCXL)             += ocxl/
-obj-$(CONFIG_MISC_RTSX)                += cardreader/
+obj-y          += cardreader/
index 69e815e32a8cf1f7e3c037bc39fbed3c96ef0438..ed8993b5d058b9283d82e050aa5dc19f382b7ab6 100644 (file)
@@ -1,3 +1,14 @@
+config MISC_ALCOR_PCI
+       tristate "Alcor Micro/Alcor Link PCI-E card reader"
+       depends on PCI
+       select MFD_CORE
+       help
+         This supports for Alcor Micro PCI-Express card reader including au6601,
+         au6621.
+         Alcor Micro card readers support access to many types of memory cards,
+         such as Memory Stick, Memory Stick Pro, Secure Digital and
+         MultiMediaCard.
+
 config MISC_RTSX_PCI
        tristate "Realtek PCI-E card reader"
        depends on PCI
index 9fabfcc6fa7a8d21b252639853f95b727ff9c6af..9882d2a1025c6cc85edb219341a1124a48f9a725 100644 (file)
@@ -1,4 +1,4 @@
-rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o rts5260.o
-
+obj-$(CONFIG_MISC_ALCOR_PCI)   += alcor_pci.o
 obj-$(CONFIG_MISC_RTSX_PCI)    += rtsx_pci.o
+rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o rts5260.o
 obj-$(CONFIG_MISC_RTSX_USB)    += rtsx_usb.o
diff --git a/drivers/misc/cardreader/alcor_pci.c b/drivers/misc/cardreader/alcor_pci.c
new file mode 100644 (file)
index 0000000..bcb10fa
--- /dev/null
@@ -0,0 +1,371 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Oleksij Rempel <linux@rempel-privat.de>
+ *
+ * Driver for Alcor Micro AU6601 and AU6621 controllers
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+
+#include <linux/alcor_pci.h>
+
+#define DRV_NAME_ALCOR_PCI                     "alcor_pci"
+
+static DEFINE_IDA(alcor_pci_idr);
+
+static struct mfd_cell alcor_pci_cells[] = {
+       [ALCOR_SD_CARD] = {
+               .name = DRV_NAME_ALCOR_PCI_SDMMC,
+       },
+       [ALCOR_MS_CARD] = {
+               .name = DRV_NAME_ALCOR_PCI_MS,
+       },
+};
+
+static const struct alcor_dev_cfg alcor_cfg = {
+       .dma = 0,
+};
+
+static const struct alcor_dev_cfg au6621_cfg = {
+       .dma = 1,
+};
+
+static const struct pci_device_id pci_ids[] = {
+       { PCI_DEVICE(PCI_ID_ALCOR_MICRO, PCI_ID_AU6601),
+               .driver_data = (kernel_ulong_t)&alcor_cfg },
+       { PCI_DEVICE(PCI_ID_ALCOR_MICRO, PCI_ID_AU6621),
+               .driver_data = (kernel_ulong_t)&au6621_cfg },
+       { },
+};
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+void alcor_write8(struct alcor_pci_priv *priv, u8 val, unsigned int addr)
+{
+       writeb(val, priv->iobase + addr);
+}
+EXPORT_SYMBOL_GPL(alcor_write8);
+
+void alcor_write16(struct alcor_pci_priv *priv, u16 val, unsigned int addr)
+{
+       writew(val, priv->iobase + addr);
+}
+EXPORT_SYMBOL_GPL(alcor_write16);
+
+void alcor_write32(struct alcor_pci_priv *priv, u32 val, unsigned int addr)
+{
+       writel(val, priv->iobase + addr);
+}
+EXPORT_SYMBOL_GPL(alcor_write32);
+
+void alcor_write32be(struct alcor_pci_priv *priv, u32 val, unsigned int addr)
+{
+       iowrite32be(val, priv->iobase + addr);
+}
+EXPORT_SYMBOL_GPL(alcor_write32be);
+
+u8 alcor_read8(struct alcor_pci_priv *priv, unsigned int addr)
+{
+       return readb(priv->iobase + addr);
+}
+EXPORT_SYMBOL_GPL(alcor_read8);
+
+u32 alcor_read32(struct alcor_pci_priv *priv, unsigned int addr)
+{
+       return readl(priv->iobase + addr);
+}
+EXPORT_SYMBOL_GPL(alcor_read32);
+
+u32 alcor_read32be(struct alcor_pci_priv *priv, unsigned int addr)
+{
+       return ioread32be(priv->iobase + addr);
+}
+EXPORT_SYMBOL_GPL(alcor_read32be);
+
+static int alcor_pci_find_cap_offset(struct alcor_pci_priv *priv,
+                                    struct pci_dev *pci)
+{
+       int where;
+       u8 val8;
+       u32 val32;
+
+       where = ALCOR_CAP_START_OFFSET;
+       pci_read_config_byte(pci, where, &val8);
+       if (!val8)
+               return 0;
+
+       where = (int)val8;
+       while (1) {
+               pci_read_config_dword(pci, where, &val32);
+               if (val32 == 0xffffffff) {
+                       dev_dbg(priv->dev, "find_cap_offset invalid value %x.\n",
+                               val32);
+                       return 0;
+               }
+
+               if ((val32 & 0xff) == 0x10) {
+                       dev_dbg(priv->dev, "pcie cap offset: %x\n", where);
+                       return where;
+               }
+
+               if ((val32 & 0xff00) == 0x00) {
+                       dev_dbg(priv->dev, "pci_find_cap_offset invalid value %x.\n",
+                               val32);
+                       break;
+               }
+               where = (int)((val32 >> 8) & 0xff);
+       }
+
+       return 0;
+}
+
+static void alcor_pci_init_check_aspm(struct alcor_pci_priv *priv)
+{
+       struct pci_dev *pci;
+       int where;
+       u32 val32;
+
+       priv->pdev_cap_off    = alcor_pci_find_cap_offset(priv, priv->pdev);
+       priv->parent_cap_off = alcor_pci_find_cap_offset(priv,
+                                                        priv->parent_pdev);
+
+       if ((priv->pdev_cap_off == 0) || (priv->parent_cap_off == 0)) {
+               dev_dbg(priv->dev, "pci_cap_off: %x, parent_cap_off: %x\n",
+                       priv->pdev_cap_off, priv->parent_cap_off);
+               return;
+       }
+
+       /* link capability */
+       pci   = priv->pdev;
+       where = priv->pdev_cap_off + ALCOR_PCIE_LINK_CAP_OFFSET;
+       pci_read_config_dword(pci, where, &val32);
+       priv->pdev_aspm_cap = (u8)(val32 >> 10) & 0x03;
+
+       pci   = priv->parent_pdev;
+       where = priv->parent_cap_off + ALCOR_PCIE_LINK_CAP_OFFSET;
+       pci_read_config_dword(pci, where, &val32);
+       priv->parent_aspm_cap = (u8)(val32 >> 10) & 0x03;
+
+       if (priv->pdev_aspm_cap != priv->parent_aspm_cap) {
+               u8 aspm_cap;
+
+               dev_dbg(priv->dev, "pdev_aspm_cap: %x, parent_aspm_cap: %x\n",
+                       priv->pdev_aspm_cap, priv->parent_aspm_cap);
+               aspm_cap = priv->pdev_aspm_cap & priv->parent_aspm_cap;
+               priv->pdev_aspm_cap    = aspm_cap;
+               priv->parent_aspm_cap = aspm_cap;
+       }
+
+       dev_dbg(priv->dev, "ext_config_dev_aspm: %x, pdev_aspm_cap: %x\n",
+               priv->ext_config_dev_aspm, priv->pdev_aspm_cap);
+       priv->ext_config_dev_aspm &= priv->pdev_aspm_cap;
+}
+
+static void alcor_pci_aspm_ctrl(struct alcor_pci_priv *priv, u8 aspm_enable)
+{
+       struct pci_dev *pci;
+       u8 aspm_ctrl, i;
+       int where;
+       u32 val32;
+
+       if ((!priv->pdev_cap_off) || (!priv->parent_cap_off)) {
+               dev_dbg(priv->dev, "pci_cap_off: %x, parent_cap_off: %x\n",
+                       priv->pdev_cap_off, priv->parent_cap_off);
+               return;
+       }
+
+       if (!priv->pdev_aspm_cap)
+               return;
+
+       aspm_ctrl = 0;
+       if (aspm_enable) {
+               aspm_ctrl = priv->ext_config_dev_aspm;
+
+               if (!aspm_ctrl) {
+                       dev_dbg(priv->dev, "aspm_ctrl == 0\n");
+                       return;
+               }
+       }
+
+       for (i = 0; i < 2; i++) {
+
+               if (i) {
+                       pci   = priv->parent_pdev;
+                       where = priv->parent_cap_off
+                               + ALCOR_PCIE_LINK_CTRL_OFFSET;
+               } else {
+                       pci   = priv->pdev;
+                       where = priv->pdev_cap_off
+                               + ALCOR_PCIE_LINK_CTRL_OFFSET;
+               }
+
+               pci_read_config_dword(pci, where, &val32);
+               val32 &= (~0x03);
+               val32 |= (aspm_ctrl & priv->pdev_aspm_cap);
+               pci_write_config_byte(pci, where, (u8)val32);
+       }
+
+}
+
+static inline void alcor_mask_sd_irqs(struct alcor_pci_priv *priv)
+{
+       alcor_write32(priv, 0, AU6601_REG_INT_ENABLE);
+}
+
+static inline void alcor_unmask_sd_irqs(struct alcor_pci_priv *priv)
+{
+       alcor_write32(priv, AU6601_INT_CMD_MASK | AU6601_INT_DATA_MASK |
+                 AU6601_INT_CARD_INSERT | AU6601_INT_CARD_REMOVE |
+                 AU6601_INT_OVER_CURRENT_ERR,
+                 AU6601_REG_INT_ENABLE);
+}
+
+static inline void alcor_mask_ms_irqs(struct alcor_pci_priv *priv)
+{
+       alcor_write32(priv, 0, AU6601_MS_INT_ENABLE);
+}
+
+static inline void alcor_unmask_ms_irqs(struct alcor_pci_priv *priv)
+{
+       alcor_write32(priv, 0x3d00fa, AU6601_MS_INT_ENABLE);
+}
+
+static int alcor_pci_probe(struct pci_dev *pdev,
+                          const struct pci_device_id *ent)
+{
+       struct alcor_dev_cfg *cfg;
+       struct alcor_pci_priv *priv;
+       int ret, i, bar = 0;
+
+       cfg = (void *)ent->driver_data;
+
+       ret = pcim_enable_device(pdev);
+       if (ret)
+               return ret;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       ret = ida_simple_get(&alcor_pci_idr, 0, 0, GFP_KERNEL);
+       if (ret < 0)
+               return ret;
+       priv->id = ret;
+
+       priv->pdev = pdev;
+       priv->parent_pdev = pdev->bus->self;
+       priv->dev = &pdev->dev;
+       priv->cfg = cfg;
+       priv->irq = pdev->irq;
+
+       ret = pci_request_regions(pdev, DRV_NAME_ALCOR_PCI);
+       if (ret) {
+               dev_err(&pdev->dev, "Cannot request region\n");
+               return -ENOMEM;
+       }
+
+       if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) {
+               dev_err(&pdev->dev, "BAR %d is not iomem. Aborting.\n", bar);
+               ret = -ENODEV;
+               goto error_release_regions;
+       }
+
+       priv->iobase = pcim_iomap(pdev, bar, 0);
+       if (!priv->iobase) {
+               ret = -ENOMEM;
+               goto error_release_regions;
+       }
+
+       /* make sure irqs are disabled */
+       alcor_write32(priv, 0, AU6601_REG_INT_ENABLE);
+       alcor_write32(priv, 0, AU6601_MS_INT_ENABLE);
+
+       ret = dma_set_mask_and_coherent(priv->dev, AU6601_SDMA_MASK);
+       if (ret) {
+               dev_err(priv->dev, "Failed to set DMA mask\n");
+               goto error_release_regions;
+       }
+
+       pci_set_master(pdev);
+       pci_set_drvdata(pdev, priv);
+       alcor_pci_init_check_aspm(priv);
+
+       for (i = 0; i < ARRAY_SIZE(alcor_pci_cells); i++) {
+               alcor_pci_cells[i].platform_data = priv;
+               alcor_pci_cells[i].pdata_size = sizeof(*priv);
+       }
+       ret = mfd_add_devices(&pdev->dev, priv->id, alcor_pci_cells,
+                       ARRAY_SIZE(alcor_pci_cells), NULL, 0, NULL);
+       if (ret < 0)
+               goto error_release_regions;
+
+       alcor_pci_aspm_ctrl(priv, 0);
+
+       return 0;
+
+error_release_regions:
+       pci_release_regions(pdev);
+       return ret;
+}
+
+static void alcor_pci_remove(struct pci_dev *pdev)
+{
+       struct alcor_pci_priv *priv;
+
+       priv = pci_get_drvdata(pdev);
+
+       alcor_pci_aspm_ctrl(priv, 1);
+
+       mfd_remove_devices(&pdev->dev);
+
+       ida_simple_remove(&alcor_pci_idr, priv->id);
+
+       pci_release_regions(pdev);
+       pci_set_drvdata(pdev, NULL);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int alcor_suspend(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct alcor_pci_priv *priv = pci_get_drvdata(pdev);
+
+       alcor_pci_aspm_ctrl(priv, 1);
+       return 0;
+}
+
+static int alcor_resume(struct device *dev)
+{
+
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct alcor_pci_priv *priv = pci_get_drvdata(pdev);
+
+       alcor_pci_aspm_ctrl(priv, 0);
+       return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(alcor_pci_pm_ops, alcor_suspend, alcor_resume);
+
+static struct pci_driver alcor_driver = {
+       .name   =       DRV_NAME_ALCOR_PCI,
+       .id_table =     pci_ids,
+       .probe  =       alcor_pci_probe,
+       .remove =       alcor_pci_remove,
+       .driver =       {
+               .pm     = &alcor_pci_pm_ops
+       },
+};
+
+module_pci_driver(alcor_driver);
+
+MODULE_AUTHOR("Oleksij Rempel <linux@rempel-privat.de>");
+MODULE_DESCRIPTION("PCI driver for Alcor Micro AU6601 Secure Digital Host Controller Interface");
+MODULE_LICENSE("GPL");
index b97903ff1a721b7eaac32b0c23ed6258c75c7c36..f7a66f61408552966941ddd97f62f2f6fdf00ddc 100644 (file)
@@ -723,8 +723,15 @@ static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message)
        return 0;
 }
 
+static int rtsx_usb_resume_child(struct device *dev, void *data)
+{
+       pm_request_resume(dev);
+       return 0;
+}
+
 static int rtsx_usb_resume(struct usb_interface *intf)
 {
+       device_for_each_child(&intf->dev, NULL, rtsx_usb_resume_child);
        return 0;
 }
 
@@ -734,6 +741,7 @@ static int rtsx_usb_reset_resume(struct usb_interface *intf)
                (struct rtsx_ucr *)usb_get_intfdata(intf);
 
        rtsx_usb_reset_chip(ucr);
+       device_for_each_child(&intf->dev, NULL, rtsx_usb_resume_child);
        return 0;
 }
 
index 62e7619d5a4da3939cf8fb96b320abd55761b6be..aef1185f383d42f3a3f7192b2003d521471acd18 100644 (file)
@@ -1960,7 +1960,7 @@ static void mmc_blk_urgent_bkops(struct mmc_queue *mq,
                                 struct mmc_queue_req *mqrq)
 {
        if (mmc_blk_urgent_bkops_needed(mq, mqrq))
-               mmc_start_bkops(mq->card, true);
+               mmc_run_bkops(mq->card);
 }
 
 void mmc_blk_mq_complete(struct request *req)
index 1170feb8f96982755e601af401fe31950363a918..eef3014524063e34d6ce281182eda9c56bc7c72f 100644 (file)
 #define MMC_STATE_BLOCKADDR    (1<<2)          /* card uses block-addressing */
 #define MMC_CARD_SDXC          (1<<3)          /* card is SDXC */
 #define MMC_CARD_REMOVED       (1<<4)          /* card has been removed */
-#define MMC_STATE_DOING_BKOPS  (1<<5)          /* card is doing BKOPS */
-#define MMC_STATE_SUSPENDED    (1<<6)          /* card is suspended */
+#define MMC_STATE_SUSPENDED    (1<<5)          /* card is suspended */
 
 #define mmc_card_present(c)    ((c)->state & MMC_STATE_PRESENT)
 #define mmc_card_readonly(c)   ((c)->state & MMC_STATE_READONLY)
 #define mmc_card_blockaddr(c)  ((c)->state & MMC_STATE_BLOCKADDR)
 #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
 #define mmc_card_removed(c)    ((c) && ((c)->state & MMC_CARD_REMOVED))
-#define mmc_card_doing_bkops(c)        ((c)->state & MMC_STATE_DOING_BKOPS)
 #define mmc_card_suspended(c)  ((c)->state & MMC_STATE_SUSPENDED)
 
 #define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
@@ -39,8 +37,6 @@
 #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
 #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
 #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
-#define mmc_card_set_doing_bkops(c)    ((c)->state |= MMC_STATE_DOING_BKOPS)
-#define mmc_card_clr_doing_bkops(c)    ((c)->state &= ~MMC_STATE_DOING_BKOPS)
 #define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
 #define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED)
 
index 50a5c340307b8c33b9ed6ad72eafeb8afa227174..5bd58b95d318ea2b86b4a784244bbbf65a3dfca2 100644 (file)
@@ -887,7 +887,10 @@ void mmc_release_host(struct mmc_host *host)
                spin_unlock_irqrestore(&host->lock, flags);
                wake_up(&host->wq);
                pm_runtime_mark_last_busy(mmc_dev(host));
-               pm_runtime_put_autosuspend(mmc_dev(host));
+               if (host->caps & MMC_CAP_SYNC_RUNTIME_PM)
+                       pm_runtime_put_sync_suspend(mmc_dev(host));
+               else
+                       pm_runtime_put_autosuspend(mmc_dev(host));
        }
 }
 EXPORT_SYMBOL(mmc_release_host);
@@ -2413,20 +2416,6 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
 }
 EXPORT_SYMBOL(mmc_set_blocklen);
 
-int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
-                       bool is_rel_write)
-{
-       struct mmc_command cmd = {};
-
-       cmd.opcode = MMC_SET_BLOCK_COUNT;
-       cmd.arg = blockcount & 0x0000FFFF;
-       if (is_rel_write)
-               cmd.arg |= 1 << 31;
-       cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
-       return mmc_wait_for_cmd(card->host, &cmd, 5);
-}
-EXPORT_SYMBOL(mmc_set_blockcount);
-
 static void mmc_hw_reset_for_init(struct mmc_host *host)
 {
        mmc_pwrseq_reset(host);
index 087ba68b292099cbf07cb8ad00ea547967443593..8fb6bc37f8081638f453386c282d55ae17de4c43 100644 (file)
@@ -118,8 +118,6 @@ int mmc_erase_group_aligned(struct mmc_card *card, unsigned int from,
 unsigned int mmc_calc_max_discard(struct mmc_card *card);
 
 int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
-int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
-                       bool is_rel_write);
 
 int __mmc_claim_host(struct mmc_host *host, struct mmc_ctx *ctx,
                     atomic_t *abort);
index 55997cf84b39f5dd9c3ced5ea9db6702cb02c65a..da892a599524b9727a3ac1d679333ac36d33c492 100644 (file)
@@ -1181,6 +1181,9 @@ static int mmc_select_hs400(struct mmc_card *card)
        if (err)
                goto out_err;
 
+       if (host->ops->hs400_prepare_ddr)
+               host->ops->hs400_prepare_ddr(host);
+
        /* Switch card to DDR */
        err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                         EXT_CSD_BUS_WIDTH,
@@ -2011,12 +2014,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
        if (mmc_card_suspended(host->card))
                goto out;
 
-       if (mmc_card_doing_bkops(host->card)) {
-               err = mmc_stop_bkops(host->card);
-               if (err)
-                       goto out;
-       }
-
        err = mmc_flush_cache(host->card);
        if (err)
                goto out;
index 873b2aa0c155623f60a0a30374e2174d39e5da29..9054329fe903e83e95699d8702b91d09eaeceacf 100644 (file)
@@ -802,12 +802,6 @@ static int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
        unsigned int opcode;
        int err;
 
-       if (!card->ext_csd.hpi) {
-               pr_warn("%s: Card didn't support HPI command\n",
-                       mmc_hostname(card->host));
-               return -EINVAL;
-       }
-
        opcode = card->ext_csd.hpi_cmd;
        if (opcode == MMC_STOP_TRANSMISSION)
                cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
@@ -897,34 +891,6 @@ int mmc_can_ext_csd(struct mmc_card *card)
        return (card && card->csd.mmca_vsn > CSD_SPEC_VER_3);
 }
 
-/**
- *     mmc_stop_bkops - stop ongoing BKOPS
- *     @card: MMC card to check BKOPS
- *
- *     Send HPI command to stop ongoing background operations to
- *     allow rapid servicing of foreground operations, e.g. read/
- *     writes. Wait until the card comes out of the programming state
- *     to avoid errors in servicing read/write requests.
- */
-int mmc_stop_bkops(struct mmc_card *card)
-{
-       int err = 0;
-
-       err = mmc_interrupt_hpi(card);
-
-       /*
-        * If err is EINVAL, we can't issue an HPI.
-        * It should complete the BKOPS.
-        */
-       if (!err || (err == -EINVAL)) {
-               mmc_card_clr_doing_bkops(card);
-               mmc_retune_release(card->host);
-               err = 0;
-       }
-
-       return err;
-}
-
 static int mmc_read_bkops_status(struct mmc_card *card)
 {
        int err;
@@ -941,22 +907,17 @@ static int mmc_read_bkops_status(struct mmc_card *card)
 }
 
 /**
- *     mmc_start_bkops - start BKOPS for supported cards
- *     @card: MMC card to start BKOPS
- *     @from_exception: A flag to indicate if this function was
- *                      called due to an exception raised by the card
+ *     mmc_run_bkops - Run BKOPS for supported cards
+ *     @card: MMC card to run BKOPS for
  *
- *     Start background operations whenever requested.
- *     When the urgent BKOPS bit is set in a R1 command response
- *     then background operations should be started immediately.
+ *     Run background operations synchronously for cards having manual BKOPS
+ *     enabled and in case it reports urgent BKOPS level.
 */
-void mmc_start_bkops(struct mmc_card *card, bool from_exception)
+void mmc_run_bkops(struct mmc_card *card)
 {
        int err;
-       int timeout;
-       bool use_busy_signal;
 
-       if (!card->ext_csd.man_bkops_en || mmc_card_doing_bkops(card))
+       if (!card->ext_csd.man_bkops_en)
                return;
 
        err = mmc_read_bkops_status(card);
@@ -966,44 +927,26 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
                return;
        }
 
-       if (!card->ext_csd.raw_bkops_status)
-               return;
-
-       if (card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2 &&
-           from_exception)
+       if (!card->ext_csd.raw_bkops_status ||
+           card->ext_csd.raw_bkops_status < EXT_CSD_BKOPS_LEVEL_2)
                return;
 
-       if (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2) {
-               timeout = MMC_OPS_TIMEOUT_MS;
-               use_busy_signal = true;
-       } else {
-               timeout = 0;
-               use_busy_signal = false;
-       }
-
        mmc_retune_hold(card->host);
 
-       err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                       EXT_CSD_BKOPS_START, 1, timeout, 0,
-                       use_busy_signal, true, false);
-       if (err) {
+       /*
+        * For urgent BKOPS status, LEVEL_2 and higher, let's execute
+        * synchronously. Future wise, we may consider to start BKOPS, for less
+        * urgent levels by using an asynchronous background task, when idle.
+        */
+       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                       EXT_CSD_BKOPS_START, 1, MMC_OPS_TIMEOUT_MS);
+       if (err)
                pr_warn("%s: Error %d starting bkops\n",
                        mmc_hostname(card->host), err);
-               mmc_retune_release(card->host);
-               return;
-       }
 
-       /*
-        * For urgent bkops status (LEVEL_2 and more)
-        * bkops executed synchronously, otherwise
-        * the operation is in progress
-        */
-       if (!use_busy_signal)
-               mmc_card_set_doing_bkops(card);
-       else
-               mmc_retune_release(card->host);
+       mmc_retune_release(card->host);
 }
-EXPORT_SYMBOL(mmc_start_bkops);
+EXPORT_SYMBOL(mmc_run_bkops);
 
 /*
  * Flush the cache to the non-volatile storage.
index a1390d4863815fcb4718ae974ac19490341a63e5..018a5e3f66d6f8af780c6bcfe7b9627f1b7a16df 100644 (file)
@@ -40,8 +40,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                bool use_busy_signal, bool send_status, bool retry_crc_err);
 int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                unsigned int timeout_ms);
-int mmc_stop_bkops(struct mmc_card *card);
-void mmc_start_bkops(struct mmc_card *card, bool from_exception);
+void mmc_run_bkops(struct mmc_card *card);
 int mmc_flush_cache(struct mmc_card *card);
 int mmc_cmdq_enable(struct mmc_card *card);
 int mmc_cmdq_disable(struct mmc_card *card);
index ef18daeaa4cc6f0a54f2814762fd7d615fcf4c9f..eabb1cab17656f2641a6936778a5ab540f493335 100644 (file)
@@ -3145,17 +3145,7 @@ static int mtf_testlist_show(struct seq_file *sf, void *data)
        return 0;
 }
 
-static int mtf_testlist_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, mtf_testlist_show, inode->i_private);
-}
-
-static const struct file_operations mmc_test_fops_testlist = {
-       .open           = mtf_testlist_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(mtf_testlist);
 
 static void mmc_test_free_dbgfs_file(struct mmc_card *card)
 {
@@ -3216,7 +3206,7 @@ static int mmc_test_register_dbgfs_file(struct mmc_card *card)
                goto err;
 
        ret = __mmc_test_register_dbgfs_file(card, "testlist", S_IRUGO,
-               &mmc_test_fops_testlist);
+               &mtf_testlist_fops);
        if (ret)
                goto err;
 
index 86803a3a04dc9609a0c55de2df03f3a9e8cb1341..319ccd93383d25759d9104d3fd4eaae20745fc67 100644 (file)
@@ -9,7 +9,6 @@
  */
 
 #include <linux/err.h>
-#include <linux/gpio.h>
 #include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
@@ -27,8 +26,8 @@ struct mmc_gpio {
        bool override_cd_active_level;
        irqreturn_t (*cd_gpio_isr)(int irq, void *dev_id);
        char *ro_label;
+       char *cd_label;
        u32 cd_debounce_delay_ms;
-       char cd_label[];
 };
 
 static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
@@ -45,15 +44,19 @@ static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
 
 int mmc_gpio_alloc(struct mmc_host *host)
 {
-       size_t len = strlen(dev_name(host->parent)) + 4;
        struct mmc_gpio *ctx = devm_kzalloc(host->parent,
-                               sizeof(*ctx) + 2 * len, GFP_KERNEL);
+                                           sizeof(*ctx), GFP_KERNEL);
 
        if (ctx) {
-               ctx->ro_label = ctx->cd_label + len;
                ctx->cd_debounce_delay_ms = 200;
-               snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
-               snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent));
+               ctx->cd_label = devm_kasprintf(host->parent, GFP_KERNEL,
+                               "%s cd", dev_name(host->parent));
+               if (!ctx->cd_label)
+                       return -ENOMEM;
+               ctx->ro_label = devm_kasprintf(host->parent, GFP_KERNEL,
+                               "%s ro", dev_name(host->parent));
+               if (!ctx->ro_label)
+                       return -ENOMEM;
                host->slot.handler_priv = ctx;
                host->slot.cd_irq = -EINVAL;
        }
@@ -98,36 +101,6 @@ int mmc_gpio_get_cd(struct mmc_host *host)
 }
 EXPORT_SYMBOL(mmc_gpio_get_cd);
 
-/**
- * mmc_gpio_request_ro - request a gpio for write-protection
- * @host: mmc host
- * @gpio: gpio number requested
- *
- * As devm_* managed functions are used in mmc_gpio_request_ro(), client
- * drivers do not need to worry about freeing up memory.
- *
- * Returns zero on success, else an error.
- */
-int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio)
-{
-       struct mmc_gpio *ctx = host->slot.handler_priv;
-       int ret;
-
-       if (!gpio_is_valid(gpio))
-               return -EINVAL;
-
-       ret = devm_gpio_request_one(host->parent, gpio, GPIOF_DIR_IN,
-                                   ctx->ro_label);
-       if (ret < 0)
-               return ret;
-
-       ctx->override_ro_active_level = true;
-       ctx->ro_gpio = gpio_to_desc(gpio);
-
-       return 0;
-}
-EXPORT_SYMBOL(mmc_gpio_request_ro);
-
 void mmc_gpiod_request_cd_irq(struct mmc_host *host)
 {
        struct mmc_gpio *ctx = host->slot.handler_priv;
@@ -196,50 +169,6 @@ void mmc_gpio_set_cd_isr(struct mmc_host *host,
 }
 EXPORT_SYMBOL(mmc_gpio_set_cd_isr);
 
-/**
- * mmc_gpio_request_cd - request a gpio for card-detection
- * @host: mmc host
- * @gpio: gpio number requested
- * @debounce: debounce time in microseconds
- *
- * As devm_* managed functions are used in mmc_gpio_request_cd(), client
- * drivers do not need to worry about freeing up memory.
- *
- * If GPIO debouncing is desired, set the debounce parameter to a non-zero
- * value. The caller is responsible for ensuring that the GPIO driver associated
- * with the GPIO supports debouncing, otherwise an error will be returned.
- *
- * Returns zero on success, else an error.
- */
-int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio,
-                       unsigned int debounce)
-{
-       struct mmc_gpio *ctx = host->slot.handler_priv;
-       int ret;
-
-       ret = devm_gpio_request_one(host->parent, gpio, GPIOF_DIR_IN,
-                                   ctx->cd_label);
-       if (ret < 0)
-               /*
-                * don't bother freeing memory. It might still get used by other
-                * slot functions, in any case it will be freed, when the device
-                * is destroyed.
-                */
-               return ret;
-
-       if (debounce) {
-               ret = gpio_set_debounce(gpio, debounce);
-               if (ret < 0)
-                       return ret;
-       }
-
-       ctx->override_cd_active_level = true;
-       ctx->cd_gpio = gpio_to_desc(gpio);
-
-       return 0;
-}
-EXPORT_SYMBOL(mmc_gpio_request_cd);
-
 /**
  * mmc_gpiod_request_cd - request a gpio descriptor for card-detection
  * @host: mmc host
@@ -250,8 +179,7 @@ EXPORT_SYMBOL(mmc_gpio_request_cd);
  * @gpio_invert: will return whether the GPIO line is inverted or not, set
  * to NULL to ignore
  *
- * Use this function in place of mmc_gpio_request_cd() to use the GPIO
- * descriptor API.  Note that it must be called prior to mmc_add_host()
+ * Note that this 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.
@@ -302,9 +230,6 @@ EXPORT_SYMBOL(mmc_can_gpio_cd);
  * @gpio_invert: will return whether the GPIO line is inverted or not,
  * set to NULL to ignore
  *
- * Use this function in place of mmc_gpio_request_ro() to use the GPIO
- * descriptor API.
- *
  * Returns zero on success, else an error.
  */
 int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
index 1b58739d97447017548aeab9efe56f3a3938942d..e26b8145efb32411bf4feb2659163a8b7ae59350 100644 (file)
@@ -441,6 +441,13 @@ config MMC_WBSD
 
          If unsure, say N.
 
+config MMC_ALCOR
+       tristate "Alcor Micro/Alcor Link SD/MMC controller"
+       depends on MISC_ALCOR_PCI
+       help
+         Say Y here to include driver code to support SD/MMC card interface
+         of Alcor Micro PCI-E card reader
+
 config MMC_AU1X
        tristate "Alchemy AU1XX0 MMC Card Interface support"
        depends on MIPS_ALCHEMY
@@ -646,13 +653,14 @@ config MMC_SDHI_SYS_DMAC
 
 config MMC_SDHI_INTERNAL_DMAC
        tristate "DMA for SDHI SD/SDIO controllers using on-chip bus mastering"
-       depends on ARM64 || ARCH_R8A77470 || COMPILE_TEST
+       depends on ARM64 || ARCH_R7S9210 || ARCH_R8A77470 || COMPILE_TEST
        depends on MMC_SDHI
-       default MMC_SDHI if (ARM64 || ARCH_R8A77470)
+       default MMC_SDHI if (ARM64 || ARCH_R7S9210 || ARCH_R8A77470)
        help
          This provides DMA support for SDHI SD/SDIO controllers
          using on-chip bus mastering. This supports the controllers
-         found in arm64 based SoCs.
+         found in arm64 based SoCs. This controller is also found in
+         some RZ family SoCs.
 
 config MMC_UNIPHIER
        tristate "UniPhier SD/eMMC Host Controller support"
@@ -969,6 +977,8 @@ config MMC_SDHCI_XENON
 config MMC_SDHCI_OMAP
        tristate "TI SDHCI Controller Support"
        depends on MMC_SDHCI_PLTFM && OF
+       select THERMAL
+       select TI_SOC_THERMAL
        help
          This selects the Secure Digital Host Controller Interface (SDHCI)
          support present in TI's DRA7 SOCs. The controller supports
@@ -977,3 +987,15 @@ config MMC_SDHCI_OMAP
          If you have a controller with this interface, say Y or M here.
 
          If unsure, say N.
+
+config MMC_SDHCI_AM654
+       tristate "Support for the SDHCI Controller in TI's AM654 SOCs"
+       depends on MMC_SDHCI_PLTFM && OF
+       help
+         This selects the Secure Digital Host Controller Interface (SDHCI)
+         support present in TI's AM654 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.
index 720d3777709838191fed6e7f49b837a5aee07328..73578718f11990bc88e825e1089fedde4d8ac94d 100644 (file)
@@ -22,8 +22,10 @@ obj-$(CONFIG_MMC_SDHCI_S3C)  += sdhci-s3c.o
 obj-$(CONFIG_MMC_SDHCI_SIRF)           += sdhci-sirf.o
 obj-$(CONFIG_MMC_SDHCI_F_SDH30)        += sdhci_f_sdh30.o
 obj-$(CONFIG_MMC_SDHCI_SPEAR)  += sdhci-spear.o
+obj-$(CONFIG_MMC_SDHCI_AM654)  += sdhci_am654.o
 obj-$(CONFIG_MMC_WBSD)         += wbsd.o
 obj-$(CONFIG_MMC_AU1X)         += au1xmmc.o
+obj-$(CONFIG_MMC_ALCOR)        += alcor.o
 obj-$(CONFIG_MMC_MTK)          += mtk-sd.o
 obj-$(CONFIG_MMC_OMAP)         += omap.o
 obj-$(CONFIG_MMC_OMAP_HS)      += omap_hsmmc.o
diff --git a/drivers/mmc/host/alcor.c b/drivers/mmc/host/alcor.c
new file mode 100644 (file)
index 0000000..c712b7d
--- /dev/null
@@ -0,0 +1,1162 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Oleksij Rempel <linux@rempel-privat.de>
+ *
+ * Driver for Alcor Micro AU6601 and AU6621 controllers
+ */
+
+/* Note: this driver was created without any documentation. Based
+ * on sniffing, testing and in some cases mimic of original driver.
+ * As soon as some one with documentation or more experience in SD/MMC, or
+ * reverse engineering then me, please review this driver and question every
+ * thing what I did. 2018 Oleksij Rempel <linux@rempel-privat.de>
+ */
+
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/pm.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+
+#include <linux/alcor_pci.h>
+
+enum alcor_cookie {
+       COOKIE_UNMAPPED,
+       COOKIE_PRE_MAPPED,
+       COOKIE_MAPPED,
+};
+
+struct alcor_pll_conf {
+       unsigned int clk_src_freq;
+       unsigned int clk_src_reg;
+       unsigned int min_div;
+       unsigned int max_div;
+};
+
+struct alcor_sdmmc_host {
+       struct  device *dev;
+       struct alcor_pci_priv *alcor_pci;
+
+       struct mmc_host *mmc;
+       struct mmc_request *mrq;
+       struct mmc_command *cmd;
+       struct mmc_data *data;
+       unsigned int dma_on:1;
+       unsigned int early_data:1;
+
+       struct mutex cmd_mutex;
+
+       struct delayed_work timeout_work;
+
+       struct sg_mapping_iter sg_miter;        /* SG state for PIO */
+       struct scatterlist *sg;
+       unsigned int blocks;            /* remaining PIO blocks */
+       int sg_count;
+
+       u32                     irq_status_sd;
+       unsigned char           cur_power_mode;
+};
+
+static const struct alcor_pll_conf alcor_pll_cfg[] = {
+       /* MHZ,         CLK src,                max div, min div */
+       { 31250000,     AU6601_CLK_31_25_MHZ,   1,      511},
+       { 48000000,     AU6601_CLK_48_MHZ,      1,      511},
+       {125000000,     AU6601_CLK_125_MHZ,     1,      511},
+       {384000000,     AU6601_CLK_384_MHZ,     1,      511},
+};
+
+static inline void alcor_rmw8(struct alcor_sdmmc_host *host, unsigned int addr,
+                              u8 clear, u8 set)
+{
+       struct alcor_pci_priv *priv = host->alcor_pci;
+       u32 var;
+
+       var = alcor_read8(priv, addr);
+       var &= ~clear;
+       var |= set;
+       alcor_write8(priv, var, addr);
+}
+
+/* As soon as irqs are masked, some status updates may be missed.
+ * Use this with care.
+ */
+static inline void alcor_mask_sd_irqs(struct alcor_sdmmc_host *host)
+{
+       struct alcor_pci_priv *priv = host->alcor_pci;
+
+       alcor_write32(priv, 0, AU6601_REG_INT_ENABLE);
+}
+
+static inline void alcor_unmask_sd_irqs(struct alcor_sdmmc_host *host)
+{
+       struct alcor_pci_priv *priv = host->alcor_pci;
+
+       alcor_write32(priv, AU6601_INT_CMD_MASK | AU6601_INT_DATA_MASK |
+                 AU6601_INT_CARD_INSERT | AU6601_INT_CARD_REMOVE |
+                 AU6601_INT_OVER_CURRENT_ERR,
+                 AU6601_REG_INT_ENABLE);
+}
+
+static void alcor_reset(struct alcor_sdmmc_host *host, u8 val)
+{
+       struct alcor_pci_priv *priv = host->alcor_pci;
+       int i;
+
+       alcor_write8(priv, val | AU6601_BUF_CTRL_RESET,
+                     AU6601_REG_SW_RESET);
+       for (i = 0; i < 100; i++) {
+               if (!(alcor_read8(priv, AU6601_REG_SW_RESET) & val))
+                       return;
+               udelay(50);
+       }
+       dev_err(host->dev, "%s: timeout\n", __func__);
+}
+
+static void alcor_data_set_dma(struct alcor_sdmmc_host *host)
+{
+       struct alcor_pci_priv *priv = host->alcor_pci;
+       u32 addr;
+
+       if (!host->sg_count)
+               return;
+
+       if (!host->sg) {
+               dev_err(host->dev, "have blocks, but no SG\n");
+               return;
+       }
+
+       if (!sg_dma_len(host->sg)) {
+               dev_err(host->dev, "DMA SG len == 0\n");
+               return;
+       }
+
+
+       addr = (u32)sg_dma_address(host->sg);
+
+       alcor_write32(priv, addr, AU6601_REG_SDMA_ADDR);
+       host->sg = sg_next(host->sg);
+       host->sg_count--;
+}
+
+static void alcor_trigger_data_transfer(struct alcor_sdmmc_host *host,
+                                       bool early)
+{
+       struct alcor_pci_priv *priv = host->alcor_pci;
+       struct mmc_data *data = host->data;
+       u8 ctrl = 0;
+
+       if (data->flags & MMC_DATA_WRITE)
+               ctrl |= AU6601_DATA_WRITE;
+
+       if (data->host_cookie == COOKIE_MAPPED) {
+               if (host->early_data) {
+                       host->early_data = false;
+                       return;
+               }
+
+               host->early_data = early;
+
+               alcor_data_set_dma(host);
+               ctrl |= AU6601_DATA_DMA_MODE;
+               host->dma_on = 1;
+               alcor_write32(priv, data->sg_count * 0x1000,
+                              AU6601_REG_BLOCK_SIZE);
+       } else {
+               alcor_write32(priv, data->blksz, AU6601_REG_BLOCK_SIZE);
+       }
+
+       alcor_write8(priv, ctrl | AU6601_DATA_START_XFER,
+                     AU6601_DATA_XFER_CTRL);
+}
+
+static void alcor_trf_block_pio(struct alcor_sdmmc_host *host, bool read)
+{
+       struct alcor_pci_priv *priv = host->alcor_pci;
+       size_t blksize, len;
+       u8 *buf;
+
+       if (!host->blocks)
+               return;
+
+       if (host->dma_on) {
+               dev_err(host->dev, "configured DMA but got PIO request.\n");
+               return;
+       }
+
+       if (!!(host->data->flags & MMC_DATA_READ) != read) {
+               dev_err(host->dev, "got unexpected direction %i != %i\n",
+                       !!(host->data->flags & MMC_DATA_READ), read);
+       }
+
+       if (!sg_miter_next(&host->sg_miter))
+               return;
+
+       blksize = host->data->blksz;
+       len = min(host->sg_miter.length, blksize);
+
+       dev_dbg(host->dev, "PIO, %s block size: 0x%zx\n",
+               read ? "read" : "write", blksize);
+
+       host->sg_miter.consumed = len;
+       host->blocks--;
+
+       buf = host->sg_miter.addr;
+
+       if (read)
+               ioread32_rep(priv->iobase + AU6601_REG_BUFFER, buf, len >> 2);
+       else
+               iowrite32_rep(priv->iobase + AU6601_REG_BUFFER, buf, len >> 2);
+
+       sg_miter_stop(&host->sg_miter);
+}
+
+static void alcor_prepare_sg_miter(struct alcor_sdmmc_host *host)
+{
+       unsigned int flags = SG_MITER_ATOMIC;
+       struct mmc_data *data = host->data;
+
+       if (data->flags & MMC_DATA_READ)
+               flags |= SG_MITER_TO_SG;
+       else
+               flags |= SG_MITER_FROM_SG;
+       sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
+}
+
+static void alcor_prepare_data(struct alcor_sdmmc_host *host,
+                              struct mmc_command *cmd)
+{
+       struct mmc_data *data = cmd->data;
+
+       if (!data)
+               return;
+
+
+       host->data = data;
+       host->data->bytes_xfered = 0;
+       host->blocks = data->blocks;
+       host->sg = data->sg;
+       host->sg_count = data->sg_count;
+       dev_dbg(host->dev, "prepare DATA: sg %i, blocks: %i\n",
+                       host->sg_count, host->blocks);
+
+       if (data->host_cookie != COOKIE_MAPPED)
+               alcor_prepare_sg_miter(host);
+
+       alcor_trigger_data_transfer(host, true);
+}
+
+static void alcor_send_cmd(struct alcor_sdmmc_host *host,
+                          struct mmc_command *cmd, bool set_timeout)
+{
+       struct alcor_pci_priv *priv = host->alcor_pci;
+       unsigned long timeout = 0;
+       u8 ctrl = 0;
+
+       host->cmd = cmd;
+       alcor_prepare_data(host, cmd);
+
+       dev_dbg(host->dev, "send CMD. opcode: 0x%02x, arg; 0x%08x\n",
+               cmd->opcode, cmd->arg);
+       alcor_write8(priv, cmd->opcode | 0x40, AU6601_REG_CMD_OPCODE);
+       alcor_write32be(priv, cmd->arg, AU6601_REG_CMD_ARG);
+
+       switch (mmc_resp_type(cmd)) {
+       case MMC_RSP_NONE:
+               ctrl = AU6601_CMD_NO_RESP;
+               break;
+       case MMC_RSP_R1:
+               ctrl = AU6601_CMD_6_BYTE_CRC;
+               break;
+       case MMC_RSP_R1B:
+               ctrl = AU6601_CMD_6_BYTE_CRC | AU6601_CMD_STOP_WAIT_RDY;
+               break;
+       case MMC_RSP_R2:
+               ctrl = AU6601_CMD_17_BYTE_CRC;
+               break;
+       case MMC_RSP_R3:
+               ctrl = AU6601_CMD_6_BYTE_WO_CRC;
+               break;
+       default:
+               dev_err(host->dev, "%s: cmd->flag (0x%02x) is not valid\n",
+                       mmc_hostname(host->mmc), mmc_resp_type(cmd));
+               break;
+       }
+
+       if (set_timeout) {
+               if (!cmd->data && cmd->busy_timeout)
+                       timeout = cmd->busy_timeout;
+               else
+                       timeout = 10000;
+
+               schedule_delayed_work(&host->timeout_work,
+                                     msecs_to_jiffies(timeout));
+       }
+
+       dev_dbg(host->dev, "xfer ctrl: 0x%02x; timeout: %lu\n", ctrl, timeout);
+       alcor_write8(priv, ctrl | AU6601_CMD_START_XFER,
+                                AU6601_CMD_XFER_CTRL);
+}
+
+static void alcor_request_complete(struct alcor_sdmmc_host *host,
+                                  bool cancel_timeout)
+{
+       struct mmc_request *mrq;
+
+       /*
+        * If this work gets rescheduled while running, it will
+        * be run again afterwards but without any active request.
+        */
+       if (!host->mrq)
+               return;
+
+       if (cancel_timeout)
+               cancel_delayed_work(&host->timeout_work);
+
+       mrq = host->mrq;
+
+       host->mrq = NULL;
+       host->cmd = NULL;
+       host->data = NULL;
+       host->dma_on = 0;
+
+       mmc_request_done(host->mmc, mrq);
+}
+
+static void alcor_finish_data(struct alcor_sdmmc_host *host)
+{
+       struct mmc_data *data;
+
+       data = host->data;
+       host->data = NULL;
+       host->dma_on = 0;
+
+       /*
+        * The specification states that the block count register must
+        * be updated, but it does not specify at what point in the
+        * data flow. That makes the register entirely useless to read
+        * back so we have to assume that nothing made it to the card
+        * in the event of an error.
+        */
+       if (data->error)
+               data->bytes_xfered = 0;
+       else
+               data->bytes_xfered = data->blksz * data->blocks;
+
+       /*
+        * Need to send CMD12 if -
+        * a) open-ended multiblock transfer (no CMD23)
+        * b) error in multiblock transfer
+        */
+       if (data->stop &&
+           (data->error ||
+            !host->mrq->sbc)) {
+
+               /*
+                * The controller needs a reset of internal state machines
+                * upon error conditions.
+                */
+               if (data->error)
+                       alcor_reset(host, AU6601_RESET_CMD | AU6601_RESET_DATA);
+
+               alcor_unmask_sd_irqs(host);
+               alcor_send_cmd(host, data->stop, false);
+               return;
+       }
+
+       alcor_request_complete(host, 1);
+}
+
+static void alcor_err_irq(struct alcor_sdmmc_host *host, u32 intmask)
+{
+       dev_dbg(host->dev, "ERR IRQ %x\n", intmask);
+
+       if (host->cmd) {
+               if (intmask & AU6601_INT_CMD_TIMEOUT_ERR)
+                       host->cmd->error = -ETIMEDOUT;
+               else
+                       host->cmd->error = -EILSEQ;
+       }
+
+       if (host->data) {
+               if (intmask & AU6601_INT_DATA_TIMEOUT_ERR)
+                       host->data->error = -ETIMEDOUT;
+               else
+                       host->data->error = -EILSEQ;
+
+               host->data->bytes_xfered = 0;
+       }
+
+       alcor_reset(host, AU6601_RESET_CMD | AU6601_RESET_DATA);
+       alcor_request_complete(host, 1);
+}
+
+static int alcor_cmd_irq_done(struct alcor_sdmmc_host *host, u32 intmask)
+{
+       struct alcor_pci_priv *priv = host->alcor_pci;
+
+       intmask &= AU6601_INT_CMD_END;
+
+       if (!intmask)
+               return true;
+
+       /* got CMD_END but no CMD is in progress, wake thread an process the
+        * error
+        */
+       if (!host->cmd)
+               return false;
+
+       if (host->cmd->flags & MMC_RSP_PRESENT) {
+               struct mmc_command *cmd = host->cmd;
+
+               cmd->resp[0] = alcor_read32be(priv, AU6601_REG_CMD_RSP0);
+               dev_dbg(host->dev, "RSP0: 0x%04x\n", cmd->resp[0]);
+               if (host->cmd->flags & MMC_RSP_136) {
+                       cmd->resp[1] =
+                               alcor_read32be(priv, AU6601_REG_CMD_RSP1);
+                       cmd->resp[2] =
+                               alcor_read32be(priv, AU6601_REG_CMD_RSP2);
+                       cmd->resp[3] =
+                               alcor_read32be(priv, AU6601_REG_CMD_RSP3);
+                       dev_dbg(host->dev, "RSP1,2,3: 0x%04x 0x%04x 0x%04x\n",
+                               cmd->resp[1], cmd->resp[2], cmd->resp[3]);
+               }
+
+       }
+
+       host->cmd->error = 0;
+
+       /* Processed actual command. */
+       if (!host->data)
+               return false;
+
+       alcor_trigger_data_transfer(host, false);
+       host->cmd = NULL;
+       return true;
+}
+
+static void alcor_cmd_irq_thread(struct alcor_sdmmc_host *host, u32 intmask)
+{
+       intmask &= AU6601_INT_CMD_END;
+
+       if (!intmask)
+               return;
+
+       if (!host->cmd && intmask & AU6601_INT_CMD_END) {
+               dev_dbg(host->dev, "Got command interrupt 0x%08x even though no command operation was in progress.\n",
+                       intmask);
+       }
+
+       /* Processed actual command. */
+       if (!host->data)
+               alcor_request_complete(host, 1);
+       else
+               alcor_trigger_data_transfer(host, false);
+       host->cmd = NULL;
+}
+
+static int alcor_data_irq_done(struct alcor_sdmmc_host *host, u32 intmask)
+{
+       u32 tmp;
+
+       intmask &= AU6601_INT_DATA_MASK;
+
+       /* nothing here to do */
+       if (!intmask)
+               return 1;
+
+       /* we was too fast and got DATA_END after it was processed?
+        * lets ignore it for now.
+        */
+       if (!host->data && intmask == AU6601_INT_DATA_END)
+               return 1;
+
+       /* looks like an error, so lets handle it. */
+       if (!host->data)
+               return 0;
+
+       tmp = intmask & (AU6601_INT_READ_BUF_RDY | AU6601_INT_WRITE_BUF_RDY
+                        | AU6601_INT_DMA_END);
+       switch (tmp) {
+       case 0:
+               break;
+       case AU6601_INT_READ_BUF_RDY:
+               alcor_trf_block_pio(host, true);
+               if (!host->blocks)
+                       break;
+               alcor_trigger_data_transfer(host, false);
+               return 1;
+       case AU6601_INT_WRITE_BUF_RDY:
+               alcor_trf_block_pio(host, false);
+               if (!host->blocks)
+                       break;
+               alcor_trigger_data_transfer(host, false);
+               return 1;
+       case AU6601_INT_DMA_END:
+               if (!host->sg_count)
+                       break;
+
+               alcor_data_set_dma(host);
+               break;
+       default:
+               dev_err(host->dev, "Got READ_BUF_RDY and WRITE_BUF_RDY at same time\n");
+               break;
+       }
+
+       if (intmask & AU6601_INT_DATA_END)
+               return 0;
+
+       return 1;
+}
+
+static void alcor_data_irq_thread(struct alcor_sdmmc_host *host, u32 intmask)
+{
+       intmask &= AU6601_INT_DATA_MASK;
+
+       if (!intmask)
+               return;
+
+       if (!host->data) {
+               dev_dbg(host->dev, "Got data interrupt 0x%08x even though no data operation was in progress.\n",
+                       intmask);
+               alcor_reset(host, AU6601_RESET_DATA);
+               return;
+       }
+
+       if (alcor_data_irq_done(host, intmask))
+               return;
+
+       if ((intmask & AU6601_INT_DATA_END) || !host->blocks ||
+           (host->dma_on && !host->sg_count))
+               alcor_finish_data(host);
+}
+
+static void alcor_cd_irq(struct alcor_sdmmc_host *host, u32 intmask)
+{
+       dev_dbg(host->dev, "card %s\n",
+               intmask & AU6601_INT_CARD_REMOVE ? "removed" : "inserted");
+
+       if (host->mrq) {
+               dev_dbg(host->dev, "cancel all pending tasks.\n");
+
+               if (host->data)
+                       host->data->error = -ENOMEDIUM;
+
+               if (host->cmd)
+                       host->cmd->error = -ENOMEDIUM;
+               else
+                       host->mrq->cmd->error = -ENOMEDIUM;
+
+               alcor_request_complete(host, 1);
+       }
+
+       mmc_detect_change(host->mmc, msecs_to_jiffies(1));
+}
+
+static irqreturn_t alcor_irq_thread(int irq, void *d)
+{
+       struct alcor_sdmmc_host *host = d;
+       irqreturn_t ret = IRQ_HANDLED;
+       u32 intmask, tmp;
+
+       mutex_lock(&host->cmd_mutex);
+
+       intmask = host->irq_status_sd;
+
+       /* some thing bad */
+       if (unlikely(!intmask || AU6601_INT_ALL_MASK == intmask)) {
+               dev_dbg(host->dev, "unexpected IRQ: 0x%04x\n", intmask);
+               ret = IRQ_NONE;
+               goto exit;
+       }
+
+       tmp = intmask & (AU6601_INT_CMD_MASK | AU6601_INT_DATA_MASK);
+       if (tmp) {
+               if (tmp & AU6601_INT_ERROR_MASK)
+                       alcor_err_irq(host, tmp);
+               else {
+                       alcor_cmd_irq_thread(host, tmp);
+                       alcor_data_irq_thread(host, tmp);
+               }
+               intmask &= ~(AU6601_INT_CMD_MASK | AU6601_INT_DATA_MASK);
+       }
+
+       if (intmask & (AU6601_INT_CARD_INSERT | AU6601_INT_CARD_REMOVE)) {
+               alcor_cd_irq(host, intmask);
+               intmask &= ~(AU6601_INT_CARD_INSERT | AU6601_INT_CARD_REMOVE);
+       }
+
+       if (intmask & AU6601_INT_OVER_CURRENT_ERR) {
+               dev_warn(host->dev,
+                        "warning: over current detected!\n");
+               intmask &= ~AU6601_INT_OVER_CURRENT_ERR;
+       }
+
+       if (intmask)
+               dev_dbg(host->dev, "got not handled IRQ: 0x%04x\n", intmask);
+
+exit:
+       mutex_unlock(&host->cmd_mutex);
+       alcor_unmask_sd_irqs(host);
+       return ret;
+}
+
+
+static irqreturn_t alcor_irq(int irq, void *d)
+{
+       struct alcor_sdmmc_host *host = d;
+       struct alcor_pci_priv *priv = host->alcor_pci;
+       u32 status, tmp;
+       irqreturn_t ret;
+       int cmd_done, data_done;
+
+       status = alcor_read32(priv, AU6601_REG_INT_STATUS);
+       if (!status)
+               return IRQ_NONE;
+
+       alcor_write32(priv, status, AU6601_REG_INT_STATUS);
+
+       tmp = status & (AU6601_INT_READ_BUF_RDY | AU6601_INT_WRITE_BUF_RDY
+                       | AU6601_INT_DATA_END | AU6601_INT_DMA_END
+                       | AU6601_INT_CMD_END);
+       if (tmp == status) {
+               cmd_done = alcor_cmd_irq_done(host, tmp);
+               data_done = alcor_data_irq_done(host, tmp);
+               /* use fast path for simple tasks */
+               if (cmd_done && data_done) {
+                       ret = IRQ_HANDLED;
+                       goto alcor_irq_done;
+               }
+       }
+
+       host->irq_status_sd = status;
+       ret = IRQ_WAKE_THREAD;
+       alcor_mask_sd_irqs(host);
+alcor_irq_done:
+       return ret;
+}
+
+static void alcor_set_clock(struct alcor_sdmmc_host *host, unsigned int clock)
+{
+       struct alcor_pci_priv *priv = host->alcor_pci;
+       int i, diff = 0x7fffffff, tmp_clock = 0;
+       u16 clk_src = 0;
+       u8 clk_div = 0;
+
+       if (clock == 0) {
+               alcor_write16(priv, 0, AU6601_CLK_SELECT);
+               return;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(alcor_pll_cfg); i++) {
+               unsigned int tmp_div, tmp_diff;
+               const struct alcor_pll_conf *cfg = &alcor_pll_cfg[i];
+
+               tmp_div = DIV_ROUND_UP(cfg->clk_src_freq, clock);
+               if (cfg->min_div > tmp_div || tmp_div > cfg->max_div)
+                       continue;
+
+               tmp_clock = DIV_ROUND_UP(cfg->clk_src_freq, tmp_div);
+               tmp_diff = abs(clock - tmp_clock);
+
+               if (tmp_diff >= 0 && tmp_diff < diff) {
+                       diff = tmp_diff;
+                       clk_src = cfg->clk_src_reg;
+                       clk_div = tmp_div;
+               }
+       }
+
+       clk_src |= ((clk_div - 1) << 8);
+       clk_src |= AU6601_CLK_ENABLE;
+
+       dev_dbg(host->dev, "set freq %d cal freq %d, use div %d, mod %x\n",
+                       clock, tmp_clock, clk_div, clk_src);
+
+       alcor_write16(priv, clk_src, AU6601_CLK_SELECT);
+
+}
+
+static void alcor_set_timing(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct alcor_sdmmc_host *host = mmc_priv(mmc);
+
+       if (ios->timing == MMC_TIMING_LEGACY) {
+               alcor_rmw8(host, AU6601_CLK_DELAY,
+                           AU6601_CLK_POSITIVE_EDGE_ALL, 0);
+       } else {
+               alcor_rmw8(host, AU6601_CLK_DELAY,
+                           0, AU6601_CLK_POSITIVE_EDGE_ALL);
+       }
+}
+
+static void alcor_set_bus_width(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct alcor_sdmmc_host *host = mmc_priv(mmc);
+       struct alcor_pci_priv *priv = host->alcor_pci;
+
+       if (ios->bus_width == MMC_BUS_WIDTH_1) {
+               alcor_write8(priv, 0, AU6601_REG_BUS_CTRL);
+       } else if (ios->bus_width == MMC_BUS_WIDTH_4) {
+               alcor_write8(priv, AU6601_BUS_WIDTH_4BIT,
+                             AU6601_REG_BUS_CTRL);
+       } else
+               dev_err(host->dev, "Unknown BUS mode\n");
+
+}
+
+static int alcor_card_busy(struct mmc_host *mmc)
+{
+       struct alcor_sdmmc_host *host = mmc_priv(mmc);
+       struct alcor_pci_priv *priv = host->alcor_pci;
+       u8 status;
+
+       /* Check whether dat[0:3] low */
+       status = alcor_read8(priv, AU6601_DATA_PIN_STATE);
+
+       return !(status & AU6601_BUS_STAT_DAT_MASK);
+}
+
+static int alcor_get_cd(struct mmc_host *mmc)
+{
+       struct alcor_sdmmc_host *host = mmc_priv(mmc);
+       struct alcor_pci_priv *priv = host->alcor_pci;
+       u8 detect;
+
+       detect = alcor_read8(priv, AU6601_DETECT_STATUS)
+               & AU6601_DETECT_STATUS_M;
+       /* check if card is present then send command and data */
+       return (detect == AU6601_SD_DETECTED);
+}
+
+static int alcor_get_ro(struct mmc_host *mmc)
+{
+       struct alcor_sdmmc_host *host = mmc_priv(mmc);
+       struct alcor_pci_priv *priv = host->alcor_pci;
+       u8 status;
+
+       /* get write protect pin status */
+       status = alcor_read8(priv, AU6601_INTERFACE_MODE_CTRL);
+
+       return !!(status & AU6601_SD_CARD_WP);
+}
+
+static void alcor_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct alcor_sdmmc_host *host = mmc_priv(mmc);
+
+       mutex_lock(&host->cmd_mutex);
+
+       host->mrq = mrq;
+
+       /* check if card is present then send command and data */
+       if (alcor_get_cd(mmc))
+               alcor_send_cmd(host, mrq->cmd, true);
+       else {
+               mrq->cmd->error = -ENOMEDIUM;
+               alcor_request_complete(host, 1);
+       }
+
+       mutex_unlock(&host->cmd_mutex);
+}
+
+static void alcor_pre_req(struct mmc_host *mmc,
+                          struct mmc_request *mrq)
+{
+       struct alcor_sdmmc_host *host = mmc_priv(mmc);
+       struct mmc_data *data = mrq->data;
+       struct mmc_command *cmd = mrq->cmd;
+       struct scatterlist *sg;
+       unsigned int i, sg_len;
+
+       if (!data || !cmd)
+               return;
+
+       data->host_cookie = COOKIE_UNMAPPED;
+
+       /* FIXME: looks like the DMA engine works only with CMD18 */
+       if (cmd->opcode != 18)
+               return;
+       /*
+        * We don't do DMA on "complex" transfers, i.e. with
+        * non-word-aligned buffers or lengths. Also, we don't bother
+        * with all the DMA setup overhead for short transfers.
+        */
+       if (data->blocks * data->blksz < AU6601_MAX_DMA_BLOCK_SIZE)
+               return;
+
+       if (data->blksz & 3)
+               return;
+
+       for_each_sg(data->sg, sg, data->sg_len, i) {
+               if (sg->length != AU6601_MAX_DMA_BLOCK_SIZE)
+                       return;
+       }
+
+       /* This data might be unmapped at this time */
+
+       sg_len = dma_map_sg(host->dev, data->sg, data->sg_len,
+                           mmc_get_dma_dir(data));
+       if (sg_len)
+               data->host_cookie = COOKIE_MAPPED;
+
+       data->sg_count = sg_len;
+}
+
+static void alcor_post_req(struct mmc_host *mmc,
+                           struct mmc_request *mrq,
+                           int err)
+{
+       struct alcor_sdmmc_host *host = mmc_priv(mmc);
+       struct mmc_data *data = mrq->data;
+
+       if (!data)
+               return;
+
+       if (data->host_cookie == COOKIE_MAPPED) {
+               dma_unmap_sg(host->dev,
+                            data->sg,
+                            data->sg_len,
+                            mmc_get_dma_dir(data));
+       }
+
+       data->host_cookie = COOKIE_UNMAPPED;
+}
+
+static void alcor_set_power_mode(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct alcor_sdmmc_host *host = mmc_priv(mmc);
+       struct alcor_pci_priv *priv = host->alcor_pci;
+
+       switch (ios->power_mode) {
+       case MMC_POWER_OFF:
+               alcor_set_clock(host, ios->clock);
+               /* set all pins to input */
+               alcor_write8(priv, 0, AU6601_OUTPUT_ENABLE);
+               /* turn of VDD */
+               alcor_write8(priv, 0, AU6601_POWER_CONTROL);
+               break;
+       case MMC_POWER_UP:
+               break;
+       case MMC_POWER_ON:
+               /* This is most trickiest part. The order and timings of
+                * instructions seems to play important role. Any changes may
+                * confuse internal state engine if this HW.
+                * FIXME: If we will ever get access to documentation, then this
+                * part should be reviewed again.
+                */
+
+               /* enable SD card mode */
+               alcor_write8(priv, AU6601_SD_CARD,
+                             AU6601_ACTIVE_CTRL);
+               /* set signal voltage to 3.3V */
+               alcor_write8(priv, 0, AU6601_OPT);
+               /* no documentation about clk delay, for now just try to mimic
+                * original driver.
+                */
+               alcor_write8(priv, 0x20, AU6601_CLK_DELAY);
+               /* set BUS width to 1 bit */
+               alcor_write8(priv, 0, AU6601_REG_BUS_CTRL);
+               /* set CLK first time */
+               alcor_set_clock(host, ios->clock);
+               /* power on VDD */
+               alcor_write8(priv, AU6601_SD_CARD,
+                             AU6601_POWER_CONTROL);
+               /* wait until the CLK will get stable */
+               mdelay(20);
+               /* set CLK again, mimic original driver. */
+               alcor_set_clock(host, ios->clock);
+
+               /* enable output */
+               alcor_write8(priv, AU6601_SD_CARD,
+                             AU6601_OUTPUT_ENABLE);
+               /* The clk will not work on au6621. We need to trigger data
+                * transfer.
+                */
+               alcor_write8(priv, AU6601_DATA_WRITE,
+                             AU6601_DATA_XFER_CTRL);
+               /* configure timeout. Not clear what exactly it means. */
+               alcor_write8(priv, 0x7d, AU6601_TIME_OUT_CTRL);
+               mdelay(100);
+               break;
+       default:
+               dev_err(host->dev, "Unknown power parameter\n");
+       }
+}
+
+static void alcor_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct alcor_sdmmc_host *host = mmc_priv(mmc);
+
+       mutex_lock(&host->cmd_mutex);
+
+       dev_dbg(host->dev, "set ios. bus width: %x, power mode: %x\n",
+               ios->bus_width, ios->power_mode);
+
+       if (ios->power_mode != host->cur_power_mode) {
+               alcor_set_power_mode(mmc, ios);
+               host->cur_power_mode = ios->power_mode;
+       } else {
+               alcor_set_timing(mmc, ios);
+               alcor_set_bus_width(mmc, ios);
+               alcor_set_clock(host, ios->clock);
+       }
+
+       mutex_unlock(&host->cmd_mutex);
+}
+
+static int alcor_signal_voltage_switch(struct mmc_host *mmc,
+                                      struct mmc_ios *ios)
+{
+       struct alcor_sdmmc_host *host = mmc_priv(mmc);
+
+       mutex_lock(&host->cmd_mutex);
+
+       switch (ios->signal_voltage) {
+       case MMC_SIGNAL_VOLTAGE_330:
+               alcor_rmw8(host, AU6601_OPT, AU6601_OPT_SD_18V, 0);
+               break;
+       case MMC_SIGNAL_VOLTAGE_180:
+               alcor_rmw8(host, AU6601_OPT, 0, AU6601_OPT_SD_18V);
+               break;
+       default:
+               /* No signal voltage switch required */
+               break;
+       }
+
+       mutex_unlock(&host->cmd_mutex);
+       return 0;
+}
+
+static const struct mmc_host_ops alcor_sdc_ops = {
+       .card_busy      = alcor_card_busy,
+       .get_cd         = alcor_get_cd,
+       .get_ro         = alcor_get_ro,
+       .post_req       = alcor_post_req,
+       .pre_req        = alcor_pre_req,
+       .request        = alcor_request,
+       .set_ios        = alcor_set_ios,
+       .start_signal_voltage_switch = alcor_signal_voltage_switch,
+};
+
+static void alcor_timeout_timer(struct work_struct *work)
+{
+       struct delayed_work *d = to_delayed_work(work);
+       struct alcor_sdmmc_host *host = container_of(d, struct alcor_sdmmc_host,
+                                               timeout_work);
+       mutex_lock(&host->cmd_mutex);
+
+       dev_dbg(host->dev, "triggered timeout\n");
+       if (host->mrq) {
+               dev_err(host->dev, "Timeout waiting for hardware interrupt.\n");
+
+               if (host->data) {
+                       host->data->error = -ETIMEDOUT;
+               } else {
+                       if (host->cmd)
+                               host->cmd->error = -ETIMEDOUT;
+                       else
+                               host->mrq->cmd->error = -ETIMEDOUT;
+               }
+
+               alcor_reset(host, AU6601_RESET_CMD | AU6601_RESET_DATA);
+               alcor_request_complete(host, 0);
+       }
+
+       mmiowb();
+       mutex_unlock(&host->cmd_mutex);
+}
+
+static void alcor_hw_init(struct alcor_sdmmc_host *host)
+{
+       struct alcor_pci_priv *priv = host->alcor_pci;
+       struct alcor_dev_cfg *cfg = priv->cfg;
+
+       /* FIXME: This part is a mimics HW init of original driver.
+        * If we will ever get access to documentation, then this part
+        * should be reviewed again.
+        */
+
+       /* reset command state engine */
+       alcor_reset(host, AU6601_RESET_CMD);
+
+       alcor_write8(priv, 0, AU6601_DMA_BOUNDARY);
+       /* enable sd card mode */
+       alcor_write8(priv, AU6601_SD_CARD, AU6601_ACTIVE_CTRL);
+
+       /* set BUS width to 1 bit */
+       alcor_write8(priv, 0, AU6601_REG_BUS_CTRL);
+
+       /* reset data state engine */
+       alcor_reset(host, AU6601_RESET_DATA);
+       /* Not sure if a voodoo with AU6601_DMA_BOUNDARY is really needed */
+       alcor_write8(priv, 0, AU6601_DMA_BOUNDARY);
+
+       alcor_write8(priv, 0, AU6601_INTERFACE_MODE_CTRL);
+       /* not clear what we are doing here. */
+       alcor_write8(priv, 0x44, AU6601_PAD_DRIVE0);
+       alcor_write8(priv, 0x44, AU6601_PAD_DRIVE1);
+       alcor_write8(priv, 0x00, AU6601_PAD_DRIVE2);
+
+       /* for 6601 - dma_boundary; for 6621 - dma_page_cnt
+        * exact meaning of this register is not clear.
+        */
+       alcor_write8(priv, cfg->dma, AU6601_DMA_BOUNDARY);
+
+       /* make sure all pins are set to input and VDD is off */
+       alcor_write8(priv, 0, AU6601_OUTPUT_ENABLE);
+       alcor_write8(priv, 0, AU6601_POWER_CONTROL);
+
+       alcor_write8(priv, AU6601_DETECT_EN, AU6601_DETECT_STATUS);
+       /* now we should be safe to enable IRQs */
+       alcor_unmask_sd_irqs(host);
+}
+
+static void alcor_hw_uninit(struct alcor_sdmmc_host *host)
+{
+       struct alcor_pci_priv *priv = host->alcor_pci;
+
+       alcor_mask_sd_irqs(host);
+       alcor_reset(host, AU6601_RESET_CMD | AU6601_RESET_DATA);
+
+       alcor_write8(priv, 0, AU6601_DETECT_STATUS);
+
+       alcor_write8(priv, 0, AU6601_OUTPUT_ENABLE);
+       alcor_write8(priv, 0, AU6601_POWER_CONTROL);
+
+       alcor_write8(priv, 0, AU6601_OPT);
+}
+
+static void alcor_init_mmc(struct alcor_sdmmc_host *host)
+{
+       struct mmc_host *mmc = host->mmc;
+
+       mmc->f_min = AU6601_MIN_CLOCK;
+       mmc->f_max = AU6601_MAX_CLOCK;
+       mmc->ocr_avail = MMC_VDD_33_34;
+       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED
+               | MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50
+               | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50;
+       mmc->caps2 = MMC_CAP2_NO_SDIO;
+       mmc->ops = &alcor_sdc_ops;
+
+       /* Hardware cannot do scatter lists */
+       mmc->max_segs = AU6601_MAX_DMA_SEGMENTS;
+       mmc->max_seg_size = AU6601_MAX_DMA_BLOCK_SIZE;
+
+       mmc->max_blk_size = mmc->max_seg_size;
+       mmc->max_blk_count = mmc->max_segs;
+
+       mmc->max_req_size = mmc->max_seg_size * mmc->max_segs;
+}
+
+static int alcor_pci_sdmmc_drv_probe(struct platform_device *pdev)
+{
+       struct alcor_pci_priv *priv = pdev->dev.platform_data;
+       struct mmc_host *mmc;
+       struct alcor_sdmmc_host *host;
+       int ret;
+
+       mmc = mmc_alloc_host(sizeof(*host), &pdev->dev);
+       if (!mmc) {
+               dev_err(&pdev->dev, "Can't allocate MMC\n");
+               return -ENOMEM;
+       }
+
+       host = mmc_priv(mmc);
+       host->mmc = mmc;
+       host->dev = &pdev->dev;
+       host->cur_power_mode = MMC_POWER_UNDEFINED;
+       host->alcor_pci = priv;
+
+       /* make sure irqs are disabled */
+       alcor_write32(priv, 0, AU6601_REG_INT_ENABLE);
+       alcor_write32(priv, 0, AU6601_MS_INT_ENABLE);
+
+       ret = devm_request_threaded_irq(&pdev->dev, priv->irq,
+                       alcor_irq, alcor_irq_thread, IRQF_SHARED,
+                       DRV_NAME_ALCOR_PCI_SDMMC, host);
+
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to get irq for data line\n");
+               return ret;
+       }
+
+       mutex_init(&host->cmd_mutex);
+       INIT_DELAYED_WORK(&host->timeout_work, alcor_timeout_timer);
+
+       alcor_init_mmc(host);
+       alcor_hw_init(host);
+
+       dev_set_drvdata(&pdev->dev, host);
+       mmc_add_host(mmc);
+       return 0;
+}
+
+static int alcor_pci_sdmmc_drv_remove(struct platform_device *pdev)
+{
+       struct alcor_sdmmc_host *host = dev_get_drvdata(&pdev->dev);
+
+       if (cancel_delayed_work_sync(&host->timeout_work))
+               alcor_request_complete(host, 0);
+
+       alcor_hw_uninit(host);
+       mmc_remove_host(host->mmc);
+       mmc_free_host(host->mmc);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int alcor_pci_sdmmc_suspend(struct device *dev)
+{
+       struct alcor_sdmmc_host *host = dev_get_drvdata(dev);
+
+       if (cancel_delayed_work_sync(&host->timeout_work))
+               alcor_request_complete(host, 0);
+
+       alcor_hw_uninit(host);
+
+       return 0;
+}
+
+static int alcor_pci_sdmmc_resume(struct device *dev)
+{
+       struct alcor_sdmmc_host *host = dev_get_drvdata(dev);
+
+       alcor_hw_init(host);
+
+       return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(alcor_mmc_pm_ops, alcor_pci_sdmmc_suspend,
+                        alcor_pci_sdmmc_resume);
+
+static const struct platform_device_id alcor_pci_sdmmc_ids[] = {
+       {
+               .name = DRV_NAME_ALCOR_PCI_SDMMC,
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(platform, alcor_pci_sdmmc_ids);
+
+static struct platform_driver alcor_pci_sdmmc_driver = {
+       .probe          = alcor_pci_sdmmc_drv_probe,
+       .remove         = alcor_pci_sdmmc_drv_remove,
+       .id_table       = alcor_pci_sdmmc_ids,
+       .driver         = {
+               .name   = DRV_NAME_ALCOR_PCI_SDMMC,
+               .pm     = &alcor_mmc_pm_ops
+       },
+};
+module_platform_driver(alcor_pci_sdmmc_driver);
+
+MODULE_AUTHOR("Oleksij Rempel <linux@rempel-privat.de>");
+MODULE_DESCRIPTION("PCI driver for Alcor Micro AU6601 Secure Digital Host Controller Interface");
+MODULE_LICENSE("GPL");
index be53044086c76f7291224c33ed10c734ece7e897..47189f9ed4e20bbb8d7b09a20f36c06c1a6ff14c 100644 (file)
@@ -446,18 +446,7 @@ static int atmci_req_show(struct seq_file *s, void *v)
        return 0;
 }
 
-static int atmci_req_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, atmci_req_show, inode->i_private);
-}
-
-static const struct file_operations atmci_req_fops = {
-       .owner          = THIS_MODULE,
-       .open           = atmci_req_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(atmci_req);
 
 static void atmci_show_status_reg(struct seq_file *s,
                const char *regname, u32 value)
@@ -583,18 +572,7 @@ static int atmci_regs_show(struct seq_file *s, void *v)
        return ret;
 }
 
-static int atmci_regs_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, atmci_regs_show, inode->i_private);
-}
-
-static const struct file_operations atmci_regs_fops = {
-       .owner          = THIS_MODULE,
-       .open           = atmci_regs_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(atmci_regs);
 
 static void atmci_init_debugfs(struct atmel_mci_slot *slot)
 {
@@ -608,13 +586,14 @@ static void atmci_init_debugfs(struct atmel_mci_slot *slot)
                return;
 
        node = debugfs_create_file("regs", S_IRUSR, root, host,
-                       &atmci_regs_fops);
+                                  &atmci_regs_fops);
        if (IS_ERR(node))
                return;
        if (!node)
                goto err;
 
-       node = debugfs_create_file("req", S_IRUSR, root, slot, &atmci_req_fops);
+       node = debugfs_create_file("req", S_IRUSR, root, slot,
+                                  &atmci_req_fops);
        if (!node)
                goto err;
 
@@ -1954,13 +1933,14 @@ static void atmci_tasklet_func(unsigned long priv)
                        }
 
                        atmci_request_end(host, host->mrq);
-                       state = STATE_IDLE;
+                       goto unlock; /* atmci_request_end() sets host->state */
                        break;
                }
        } while (state != prev_state);
 
        host->state = state;
 
+unlock:
        spin_unlock(&host->lock);
 }
 
index 768972af8b853cf882b1b3311ed8fa1b0a64a49e..50293529d6dec7c8f4b13cfc02eea8d9f940fb4b 100644 (file)
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * bcm2835 sdhost driver.
  *
  *  sdhci-bcm2708.c by Broadcom
  *  sdhci-bcm2835.c by Stephen Warren and Oleksandr Tymoshenko
  *  sdhci.c and sdhci-pci.c by Pierre Ossman
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 #include <linux/clk.h>
 #include <linux/delay.h>
@@ -286,6 +275,7 @@ static void bcm2835_reset(struct mmc_host *mmc)
 
        if (host->dma_chan)
                dmaengine_terminate_sync(host->dma_chan);
+       host->dma_chan = NULL;
        bcm2835_reset_internal(host);
 }
 
@@ -463,7 +453,7 @@ static void bcm2835_transfer_pio(struct bcm2835_host *host)
 static
 void bcm2835_prepare_dma(struct bcm2835_host *host, struct mmc_data *data)
 {
-       int len, dir_data, dir_slave;
+       int sg_len, dir_data, dir_slave;
        struct dma_async_tx_descriptor *desc = NULL;
        struct dma_chan *dma_chan;
 
@@ -509,23 +499,24 @@ void bcm2835_prepare_dma(struct bcm2835_host *host, struct mmc_data *data)
                                     &host->dma_cfg_rx :
                                     &host->dma_cfg_tx);
 
-       len = dma_map_sg(dma_chan->device->dev, data->sg, data->sg_len,
-                        dir_data);
+       sg_len = dma_map_sg(dma_chan->device->dev, data->sg, data->sg_len,
+                           dir_data);
+       if (!sg_len)
+               return;
 
-       if (len > 0) {
-               desc = dmaengine_prep_slave_sg(dma_chan, data->sg,
-                                              len, dir_slave,
-                                              DMA_PREP_INTERRUPT |
-                                              DMA_CTRL_ACK);
-       }
+       desc = dmaengine_prep_slave_sg(dma_chan, data->sg, sg_len, dir_slave,
+                                      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
 
-       if (desc) {
-               desc->callback = bcm2835_dma_complete;
-               desc->callback_param = host;
-               host->dma_desc = desc;
-               host->dma_chan = dma_chan;
-               host->dma_dir = dir_data;
+       if (!desc) {
+               dma_unmap_sg(dma_chan->device->dev, data->sg, sg_len, dir_data);
+               return;
        }
+
+       desc->callback = bcm2835_dma_complete;
+       desc->callback_param = host;
+       host->dma_desc = desc;
+       host->dma_chan = dma_chan;
+       host->dma_dir = dir_data;
 }
 
 static void bcm2835_start_dma(struct bcm2835_host *host)
@@ -607,7 +598,7 @@ static void bcm2835_finish_request(struct bcm2835_host *host)
        struct dma_chan *terminate_chan = NULL;
        struct mmc_request *mrq;
 
-       cancel_delayed_work(&host->timeout_work);
+       cancel_delayed_work_sync(&host->timeout_work);
 
        mrq = host->mrq;
 
@@ -772,6 +763,8 @@ static void bcm2835_finish_command(struct bcm2835_host *host)
 
                if (!(sdhsts & SDHSTS_CRC7_ERROR) ||
                    (host->cmd->opcode != MMC_SEND_OP_COND)) {
+                       u32 edm, fsm;
+
                        if (sdhsts & SDHSTS_CMD_TIME_OUT) {
                                host->cmd->error = -ETIMEDOUT;
                        } else {
@@ -780,6 +773,13 @@ static void bcm2835_finish_command(struct bcm2835_host *host)
                                bcm2835_dumpregs(host);
                                host->cmd->error = -EILSEQ;
                        }
+                       edm = readl(host->ioaddr + SDEDM);
+                       fsm = edm & SDEDM_FSM_MASK;
+                       if (fsm == SDEDM_FSM_READWAIT ||
+                           fsm == SDEDM_FSM_WRITESTART1)
+                               /* Kick the FSM out of its wait */
+                               writel(edm | SDEDM_FORCE_DATA_MODE,
+                                      host->ioaddr + SDEDM);
                        bcm2835_finish_request(host);
                        return;
                }
@@ -837,6 +837,8 @@ static void bcm2835_timeout(struct work_struct *work)
                dev_err(dev, "timeout waiting for hardware interrupt.\n");
                bcm2835_dumpregs(host);
 
+               bcm2835_reset(host->mmc);
+
                if (host->data) {
                        host->data->error = -ETIMEDOUT;
                        bcm2835_finish_data(host);
@@ -1052,10 +1054,12 @@ static void bcm2835_dma_complete_work(struct work_struct *work)
 {
        struct bcm2835_host *host =
                container_of(work, struct bcm2835_host, dma_work);
-       struct mmc_data *data = host->data;
+       struct mmc_data *data;
 
        mutex_lock(&host->mutex);
 
+       data = host->data;
+
        if (host->dma_chan) {
                dma_unmap_sg(host->dma_chan->device->dev,
                             data->sg, data->sg_len,
@@ -1180,9 +1184,6 @@ static void bcm2835_request(struct mmc_host *mmc, struct mmc_request *mrq)
                return;
        }
 
-       if (host->use_dma && mrq->data && (mrq->data->blocks > PIO_THRESHOLD))
-               bcm2835_prepare_dma(host, mrq->data);
-
        mutex_lock(&host->mutex);
 
        WARN_ON(host->mrq);
@@ -1206,6 +1207,9 @@ static void bcm2835_request(struct mmc_host *mmc, struct mmc_request *mrq)
                return;
        }
 
+       if (host->use_dma && mrq->data && (mrq->data->blocks > PIO_THRESHOLD))
+               bcm2835_prepare_dma(host, mrq->data);
+
        host->use_sbc = !!mrq->sbc && host->mrq->data &&
                        (host->mrq->data->flags & MMC_DATA_READ);
        if (host->use_sbc) {
@@ -1445,6 +1449,9 @@ static int bcm2835_remove(struct platform_device *pdev)
        cancel_work_sync(&host->dma_work);
        cancel_delayed_work_sync(&host->timeout_work);
 
+       if (host->dma_chan_rxtx)
+               dma_release_channel(host->dma_chan_rxtx);
+
        mmc_free_host(host->mmc);
        platform_set_drvdata(pdev, NULL);
 
index 54c3fbb4a39181ea728fb5af34dca80827d2889e..ed8f2254b66a842adf97213628d0ba8dcb6a3dd2 100644 (file)
@@ -52,16 +52,7 @@ MODULE_DEVICE_TABLE(of, dw_mci_bluefield_match);
 
 static int dw_mci_bluefield_probe(struct platform_device *pdev)
 {
-       const struct dw_mci_drv_data *drv_data = NULL;
-       const struct of_device_id *match;
-
-       if (pdev->dev.of_node) {
-               match = of_match_node(dw_mci_bluefield_match,
-                                     pdev->dev.of_node);
-               drv_data = match->data;
-       }
-
-       return dw_mci_pltfm_register(pdev, drv_data);
+       return dw_mci_pltfm_register(pdev, &bluefield_drv_data);
 }
 
 static struct platform_driver dw_mci_bluefield_pltfm_driver = {
index 0c1efd5100b779b61bc2d5954e75dd7c77bd603d..33215d66afa2ee764b6c28e84e5daf2b11be9c04 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
 #include <linux/err.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/irq.h>
@@ -126,9 +126,23 @@ enum jz4740_mmc_state {
        JZ4740_MMC_STATE_DONE,
 };
 
-struct jz4740_mmc_host_next {
-       int sg_len;
-       s32 cookie;
+/*
+ * The MMC core allows to prepare a mmc_request while another mmc_request
+ * is in-flight. This is used via the pre_req/post_req hooks.
+ * This driver uses the pre_req/post_req hooks to map/unmap the mmc_request.
+ * Following what other drivers do (sdhci, dw_mmc) we use the following cookie
+ * flags to keep track of the mmc_request mapping state.
+ *
+ * COOKIE_UNMAPPED: the request is not mapped.
+ * COOKIE_PREMAPPED: the request was mapped in pre_req,
+ * and should be unmapped in post_req.
+ * COOKIE_MAPPED: the request was mapped in the irq handler,
+ * and should be unmapped before mmc_request_done is called..
+ */
+enum jz4780_cookie {
+       COOKIE_UNMAPPED = 0,
+       COOKIE_PREMAPPED,
+       COOKIE_MAPPED,
 };
 
 struct jz4740_mmc_host {
@@ -136,6 +150,7 @@ struct jz4740_mmc_host {
        struct platform_device *pdev;
        struct jz4740_mmc_platform_data *pdata;
        struct clk *clk;
+       struct gpio_desc *power;
 
        enum jz4740_mmc_version version;
 
@@ -162,9 +177,7 @@ struct jz4740_mmc_host {
        /* DMA support */
        struct dma_chan *dma_rx;
        struct dma_chan *dma_tx;
-       struct jz4740_mmc_host_next next_data;
        bool use_dma;
-       int sg_len;
 
 /* The DMA trigger level is 8 words, that is to say, the DMA read
  * trigger is when data words in MSC_RXFIFO is >= 8 and the DMA write
@@ -226,9 +239,6 @@ static int jz4740_mmc_acquire_dma_channels(struct jz4740_mmc_host *host)
                return PTR_ERR(host->dma_rx);
        }
 
-       /* Initialize DMA pre request cookie */
-       host->next_data.cookie = 1;
-
        return 0;
 }
 
@@ -245,60 +255,44 @@ static void jz4740_mmc_dma_unmap(struct jz4740_mmc_host *host,
        enum dma_data_direction dir = mmc_get_dma_dir(data);
 
        dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir);
+       data->host_cookie = COOKIE_UNMAPPED;
 }
 
-/* Prepares DMA data for current/next transfer, returns non-zero on failure */
+/* Prepares DMA data for current or next transfer.
+ * A request can be in-flight when this is called.
+ */
 static int jz4740_mmc_prepare_dma_data(struct jz4740_mmc_host *host,
                                       struct mmc_data *data,
-                                      struct jz4740_mmc_host_next *next,
-                                      struct dma_chan *chan)
+                                      int cookie)
 {
-       struct jz4740_mmc_host_next *next_data = &host->next_data;
+       struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
        enum dma_data_direction dir = mmc_get_dma_dir(data);
-       int sg_len;
-
-       if (!next && data->host_cookie &&
-           data->host_cookie != host->next_data.cookie) {
-               dev_warn(mmc_dev(host->mmc),
-                        "[%s] invalid cookie: data->host_cookie %d host->next_data.cookie %d\n",
-                        __func__,
-                        data->host_cookie,
-                        host->next_data.cookie);
-               data->host_cookie = 0;
-       }
+       int sg_count;
 
-       /* Check if next job is already prepared */
-       if (next || data->host_cookie != host->next_data.cookie) {
-               sg_len = dma_map_sg(chan->device->dev,
-                                   data->sg,
-                                   data->sg_len,
-                                   dir);
+       if (data->host_cookie == COOKIE_PREMAPPED)
+               return data->sg_count;
 
-       } else {
-               sg_len = next_data->sg_len;
-               next_data->sg_len = 0;
-       }
+       sg_count = dma_map_sg(chan->device->dev,
+                       data->sg,
+                       data->sg_len,
+                       dir);
 
-       if (sg_len <= 0) {
+       if (sg_count <= 0) {
                dev_err(mmc_dev(host->mmc),
                        "Failed to map scatterlist for DMA operation\n");
                return -EINVAL;
        }
 
-       if (next) {
-               next->sg_len = sg_len;
-               data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie;
-       } else
-               host->sg_len = sg_len;
+       data->sg_count = sg_count;
+       data->host_cookie = cookie;
 
-       return 0;
+       return data->sg_count;
 }
 
 static int jz4740_mmc_start_dma_transfer(struct jz4740_mmc_host *host,
                                         struct mmc_data *data)
 {
-       int ret;
-       struct dma_chan *chan;
+       struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
        struct dma_async_tx_descriptor *desc;
        struct dma_slave_config conf = {
                .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
@@ -306,29 +300,26 @@ static int jz4740_mmc_start_dma_transfer(struct jz4740_mmc_host *host,
                .src_maxburst = JZ4740_MMC_FIFO_HALF_SIZE,
                .dst_maxburst = JZ4740_MMC_FIFO_HALF_SIZE,
        };
+       int sg_count;
 
        if (data->flags & MMC_DATA_WRITE) {
                conf.direction = DMA_MEM_TO_DEV;
                conf.dst_addr = host->mem_res->start + JZ_REG_MMC_TXFIFO;
                conf.slave_id = JZ4740_DMA_TYPE_MMC_TRANSMIT;
-               chan = host->dma_tx;
        } else {
                conf.direction = DMA_DEV_TO_MEM;
                conf.src_addr = host->mem_res->start + JZ_REG_MMC_RXFIFO;
                conf.slave_id = JZ4740_DMA_TYPE_MMC_RECEIVE;
-               chan = host->dma_rx;
        }
 
-       ret = jz4740_mmc_prepare_dma_data(host, data, NULL, chan);
-       if (ret)
-               return ret;
+       sg_count = jz4740_mmc_prepare_dma_data(host, data, COOKIE_MAPPED);
+       if (sg_count < 0)
+               return sg_count;
 
        dmaengine_slave_config(chan, &conf);
-       desc = dmaengine_prep_slave_sg(chan,
-                                      data->sg,
-                                      host->sg_len,
-                                      conf.direction,
-                                      DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       desc = dmaengine_prep_slave_sg(chan, data->sg, sg_count,
+                       conf.direction,
+                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
        if (!desc) {
                dev_err(mmc_dev(host->mmc),
                        "Failed to allocate DMA %s descriptor",
@@ -342,7 +333,8 @@ static int jz4740_mmc_start_dma_transfer(struct jz4740_mmc_host *host,
        return 0;
 
 dma_unmap:
-       jz4740_mmc_dma_unmap(host, data);
+       if (data->host_cookie == COOKIE_MAPPED)
+               jz4740_mmc_dma_unmap(host, data);
        return -ENOMEM;
 }
 
@@ -351,16 +343,13 @@ static void jz4740_mmc_pre_request(struct mmc_host *mmc,
 {
        struct jz4740_mmc_host *host = mmc_priv(mmc);
        struct mmc_data *data = mrq->data;
-       struct jz4740_mmc_host_next *next_data = &host->next_data;
 
-       BUG_ON(data->host_cookie);
-
-       if (host->use_dma) {
-               struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
+       if (!host->use_dma)
+               return;
 
-               if (jz4740_mmc_prepare_dma_data(host, data, next_data, chan))
-                       data->host_cookie = 0;
-       }
+       data->host_cookie = COOKIE_UNMAPPED;
+       if (jz4740_mmc_prepare_dma_data(host, data, COOKIE_PREMAPPED) < 0)
+               data->host_cookie = COOKIE_UNMAPPED;
 }
 
 static void jz4740_mmc_post_request(struct mmc_host *mmc,
@@ -370,10 +359,8 @@ static void jz4740_mmc_post_request(struct mmc_host *mmc,
        struct jz4740_mmc_host *host = mmc_priv(mmc);
        struct mmc_data *data = mrq->data;
 
-       if (host->use_dma && data->host_cookie) {
+       if (data && data->host_cookie != COOKIE_UNMAPPED)
                jz4740_mmc_dma_unmap(host, data);
-               data->host_cookie = 0;
-       }
 
        if (err) {
                struct dma_chan *chan = jz4740_mmc_get_dma_chan(host, data);
@@ -436,10 +423,14 @@ static void jz4740_mmc_reset(struct jz4740_mmc_host *host)
 static void jz4740_mmc_request_done(struct jz4740_mmc_host *host)
 {
        struct mmc_request *req;
+       struct mmc_data *data;
 
        req = host->req;
+       data = req->data;
        host->req = NULL;
 
+       if (data && data->host_cookie == COOKIE_MAPPED)
+               jz4740_mmc_dma_unmap(host, data);
        mmc_request_done(host->mmc, req);
 }
 
@@ -903,18 +894,16 @@ static void jz4740_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        switch (ios->power_mode) {
        case MMC_POWER_UP:
                jz4740_mmc_reset(host);
-               if (host->pdata && gpio_is_valid(host->pdata->gpio_power))
-                       gpio_set_value(host->pdata->gpio_power,
-                                       !host->pdata->power_active_low);
+               if (host->power)
+                       gpiod_set_value(host->power, 1);
                host->cmdat |= JZ_MMC_CMDAT_INIT;
                clk_prepare_enable(host->clk);
                break;
        case MMC_POWER_ON:
                break;
        default:
-               if (host->pdata && gpio_is_valid(host->pdata->gpio_power))
-                       gpio_set_value(host->pdata->gpio_power,
-                                       host->pdata->power_active_low);
+               if (host->power)
+                       gpiod_set_value(host->power, 0);
                clk_disable_unprepare(host->clk);
                break;
        }
@@ -947,30 +936,9 @@ static const struct mmc_host_ops jz4740_mmc_ops = {
        .enable_sdio_irq = jz4740_mmc_enable_sdio_irq,
 };
 
-static int jz4740_mmc_request_gpio(struct device *dev, int gpio,
-       const char *name, bool output, int value)
-{
-       int ret;
-
-       if (!gpio_is_valid(gpio))
-               return 0;
-
-       ret = gpio_request(gpio, name);
-       if (ret) {
-               dev_err(dev, "Failed to request %s gpio: %d\n", name, ret);
-               return ret;
-       }
-
-       if (output)
-               gpio_direction_output(gpio, value);
-       else
-               gpio_direction_input(gpio);
-
-       return 0;
-}
-
-static int jz4740_mmc_request_gpios(struct mmc_host *mmc,
-       struct platform_device *pdev)
+static int jz4740_mmc_request_gpios(struct jz4740_mmc_host *host,
+                                   struct mmc_host *mmc,
+                                   struct platform_device *pdev)
 {
        struct jz4740_mmc_platform_data *pdata = dev_get_platdata(&pdev->dev);
        int ret = 0;
@@ -983,31 +951,21 @@ static int jz4740_mmc_request_gpios(struct mmc_host *mmc,
        if (!pdata->read_only_active_low)
                mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
 
-       if (gpio_is_valid(pdata->gpio_card_detect)) {
-               ret = mmc_gpio_request_cd(mmc, pdata->gpio_card_detect, 0);
-               if (ret)
-                       return ret;
-       }
-
-       if (gpio_is_valid(pdata->gpio_read_only)) {
-               ret = mmc_gpio_request_ro(mmc, pdata->gpio_read_only);
-               if (ret)
-                       return ret;
-       }
-
-       return jz4740_mmc_request_gpio(&pdev->dev, pdata->gpio_power,
-                       "MMC read only", true, pdata->power_active_low);
-}
-
-static void jz4740_mmc_free_gpios(struct platform_device *pdev)
-{
-       struct jz4740_mmc_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       /*
+        * Get optional card detect and write protect GPIOs,
+        * only back out on probe deferral.
+        */
+       ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0, NULL);
+       if (ret == -EPROBE_DEFER)
+               return ret;
 
-       if (!pdata)
-               return;
+       ret = mmc_gpiod_request_ro(mmc, "wp", 0, false, 0, NULL);
+       if (ret == -EPROBE_DEFER)
+               return ret;
 
-       if (gpio_is_valid(pdata->gpio_power))
-               gpio_free(pdata->gpio_power);
+       host->power = devm_gpiod_get_optional(&pdev->dev, "power",
+                                             GPIOD_OUT_HIGH);
+       return PTR_ERR_OR_ZERO(host->power);
 }
 
 static const struct of_device_id jz4740_mmc_of_match[] = {
@@ -1053,7 +1011,7 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
                mmc->caps |= MMC_CAP_SDIO_IRQ;
                if (!(pdata && pdata->data_1bit))
                        mmc->caps |= MMC_CAP_4_BIT_DATA;
-               ret = jz4740_mmc_request_gpios(mmc, pdev);
+               ret = jz4740_mmc_request_gpios(host, mmc, pdev);
                if (ret)
                        goto err_free_host;
        }
@@ -1104,7 +1062,7 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
                        dev_name(&pdev->dev), host);
        if (ret) {
                dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
-               goto err_free_gpios;
+               goto err_free_host;
        }
 
        jz4740_mmc_clock_disable(host);
@@ -1135,8 +1093,6 @@ err_release_dma:
                jz4740_mmc_release_dma_channels(host);
 err_free_irq:
        free_irq(host->irq, host);
-err_free_gpios:
-       jz4740_mmc_free_gpios(pdev);
 err_free_host:
        mmc_free_host(mmc);
 
@@ -1155,8 +1111,6 @@ static int jz4740_mmc_remove(struct platform_device *pdev)
 
        free_irq(host->irq, host);
 
-       jz4740_mmc_free_gpios(pdev);
-
        if (host->use_dma)
                jz4740_mmc_release_dma_channels(host);
 
index c201c378537e4f1a8a601e8d857481a7e6af9f0c..c2690c1a50ffc1e2a086916d3aa4b870d2c80c07 100644 (file)
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/ioport.h>
-#include <linux/spinlock.h>
 #include <linux/dma-mapping.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
@@ -66,6 +66,9 @@
 
 #define SD_EMMC_DELAY 0x4
 #define SD_EMMC_ADJUST 0x8
+#define   ADJUST_ADJ_DELAY_MASK GENMASK(21, 16)
+#define   ADJUST_DS_EN BIT(15)
+#define   ADJUST_ADJ_EN BIT(13)
 
 #define SD_EMMC_DELAY1 0x4
 #define SD_EMMC_DELAY2 0x8
 #define   CFG_CLK_ALWAYS_ON BIT(18)
 #define   CFG_CHK_DS BIT(20)
 #define   CFG_AUTO_CLK BIT(23)
+#define   CFG_ERR_ABORT BIT(27)
 
 #define SD_EMMC_STATUS 0x48
 #define   STATUS_BUSY BIT(31)
+#define   STATUS_DESC_BUSY BIT(30)
 #define   STATUS_DATI GENMASK(23, 16)
 
 #define SD_EMMC_IRQ_EN 0x4c
@@ -141,6 +146,7 @@ struct meson_mmc_data {
        unsigned int tx_delay_mask;
        unsigned int rx_delay_mask;
        unsigned int always_on;
+       unsigned int adjust;
 };
 
 struct sd_emmc_desc {
@@ -156,7 +162,6 @@ struct meson_host {
        struct  mmc_host        *mmc;
        struct  mmc_command     *cmd;
 
-       spinlock_t lock;
        void __iomem *regs;
        struct clk *core_clk;
        struct clk *mmc_clk;
@@ -633,14 +638,8 @@ static int meson_mmc_clk_init(struct meson_host *host)
        if (ret)
                return ret;
 
-       /*
-        * Set phases : These values are mostly the datasheet recommended ones
-        * except for the Tx phase. Datasheet recommends 180 but some cards
-        * fail at initialisation with it. 270 works just fine, it fixes these
-        * initialisation issues and enable eMMC DDR52 mode.
-        */
        clk_set_phase(host->mmc_clk, 180);
-       clk_set_phase(host->tx_clk, 270);
+       clk_set_phase(host->tx_clk, 0);
        clk_set_phase(host->rx_clk, 0);
 
        return clk_prepare_enable(host->mmc_clk);
@@ -928,6 +927,7 @@ static void meson_mmc_start_cmd(struct mmc_host *mmc, struct mmc_command *cmd)
 
        cmd_cfg |= FIELD_PREP(CMD_CFG_CMD_INDEX_MASK, cmd->opcode);
        cmd_cfg |= CMD_CFG_OWNER;  /* owned by CPU */
+       cmd_cfg |= CMD_CFG_ERROR; /* stop in case of error */
 
        meson_mmc_set_response_bits(cmd, &cmd_cfg);
 
@@ -1022,29 +1022,34 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id)
        u32 irq_en, status, raw_status;
        irqreturn_t ret = IRQ_NONE;
 
-       if (WARN_ON(!host) || WARN_ON(!host->cmd))
+       irq_en = readl(host->regs + SD_EMMC_IRQ_EN);
+       raw_status = readl(host->regs + SD_EMMC_STATUS);
+       status = raw_status & irq_en;
+
+       if (!status) {
+               dev_dbg(host->dev,
+                       "Unexpected IRQ! irq_en 0x%08x - status 0x%08x\n",
+                        irq_en, raw_status);
                return IRQ_NONE;
+       }
 
-       spin_lock(&host->lock);
+       if (WARN_ON(!host) || WARN_ON(!host->cmd))
+               return IRQ_NONE;
 
        cmd = host->cmd;
        data = cmd->data;
-       irq_en = readl(host->regs + SD_EMMC_IRQ_EN);
-       raw_status = readl(host->regs + SD_EMMC_STATUS);
-       status = raw_status & irq_en;
-
        cmd->error = 0;
        if (status & IRQ_CRC_ERR) {
                dev_dbg(host->dev, "CRC Error - status 0x%08x\n", status);
                cmd->error = -EILSEQ;
-               ret = IRQ_HANDLED;
+               ret = IRQ_WAKE_THREAD;
                goto out;
        }
 
        if (status & IRQ_TIMEOUTS) {
                dev_dbg(host->dev, "Timeout - status 0x%08x\n", status);
                cmd->error = -ETIMEDOUT;
-               ret = IRQ_HANDLED;
+               ret = IRQ_WAKE_THREAD;
                goto out;
        }
 
@@ -1069,17 +1074,48 @@ out:
        /* ack all enabled interrupts */
        writel(irq_en, host->regs + SD_EMMC_STATUS);
 
+       if (cmd->error) {
+               /* Stop desc in case of errors */
+               u32 start = readl(host->regs + SD_EMMC_START);
+
+               start &= ~START_DESC_BUSY;
+               writel(start, host->regs + SD_EMMC_START);
+       }
+
        if (ret == IRQ_HANDLED)
                meson_mmc_request_done(host->mmc, cmd->mrq);
-       else if (ret == IRQ_NONE)
-               dev_warn(host->dev,
-                        "Unexpected IRQ! status=0x%08x, irq_en=0x%08x\n",
-                        raw_status, irq_en);
 
-       spin_unlock(&host->lock);
        return ret;
 }
 
+static int meson_mmc_wait_desc_stop(struct meson_host *host)
+{
+       int loop;
+       u32 status;
+
+       /*
+        * It may sometimes take a while for it to actually halt. Here, we
+        * are giving it 5ms to comply
+        *
+        * If we don't confirm the descriptor is stopped, it might raise new
+        * IRQs after we have called mmc_request_done() which is bad.
+        */
+       for (loop = 50; loop; loop--) {
+               status = readl(host->regs + SD_EMMC_STATUS);
+               if (status & (STATUS_BUSY | STATUS_DESC_BUSY))
+                       udelay(100);
+               else
+                       break;
+       }
+
+       if (status & (STATUS_BUSY | STATUS_DESC_BUSY)) {
+               dev_err(host->dev, "Timed out waiting for host to stop\n");
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
 static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id)
 {
        struct meson_host *host = dev_id;
@@ -1090,6 +1126,13 @@ static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id)
        if (WARN_ON(!cmd))
                return IRQ_NONE;
 
+       if (cmd->error) {
+               meson_mmc_wait_desc_stop(host);
+               meson_mmc_request_done(host->mmc, cmd->mrq);
+
+               return IRQ_HANDLED;
+       }
+
        data = cmd->data;
        if (meson_mmc_bounce_buf_read(data)) {
                xfer_bytes = data->blksz * data->blocks;
@@ -1123,14 +1166,21 @@ static int meson_mmc_get_cd(struct mmc_host *mmc)
 
 static void meson_mmc_cfg_init(struct meson_host *host)
 {
-       u32 cfg = 0;
+       u32 cfg = 0, adj = 0;
 
        cfg |= FIELD_PREP(CFG_RESP_TIMEOUT_MASK,
                          ilog2(SD_EMMC_CFG_RESP_TIMEOUT));
        cfg |= FIELD_PREP(CFG_RC_CC_MASK, ilog2(SD_EMMC_CFG_CMD_GAP));
        cfg |= FIELD_PREP(CFG_BLK_LEN_MASK, ilog2(SD_EMMC_CFG_BLK_SIZE));
 
+       /* abort chain on R/W errors */
+       cfg |= CFG_ERR_ABORT;
+
        writel(cfg, host->regs + SD_EMMC_CFG);
+
+       /* enable signal resampling w/o delay */
+       adj = ADJUST_ADJ_EN;
+       writel(adj, host->regs + host->data->adjust);
 }
 
 static int meson_mmc_card_busy(struct mmc_host *mmc)
@@ -1191,8 +1241,6 @@ static int meson_mmc_probe(struct platform_device *pdev)
        host->dev = &pdev->dev;
        dev_set_drvdata(&pdev->dev, host);
 
-       spin_lock_init(&host->lock);
-
        /* Get regulators and the supported OCR mask */
        host->vqmmc_enabled = false;
        ret = mmc_regulator_get_supply(mmc);
@@ -1356,12 +1404,14 @@ static const struct meson_mmc_data meson_gx_data = {
        .tx_delay_mask  = CLK_V2_TX_DELAY_MASK,
        .rx_delay_mask  = CLK_V2_RX_DELAY_MASK,
        .always_on      = CLK_V2_ALWAYS_ON,
+       .adjust         = SD_EMMC_ADJUST,
 };
 
 static const struct meson_mmc_data meson_axg_data = {
        .tx_delay_mask  = CLK_V3_TX_DELAY_MASK,
        .rx_delay_mask  = CLK_V3_RX_DELAY_MASK,
        .always_on      = CLK_V3_ALWAYS_ON,
+       .adjust         = SD_EMMC_V3_ADJUST,
 };
 
 static const struct of_device_id meson_mmc_of_match[] = {
index abe253c262a2e4399abe27e62c758d7133f7ada2..ec980bda071c3faaeead09a224e83b79df4ad09e 100644 (file)
@@ -596,6 +596,9 @@ static int meson_mx_mmc_register_clks(struct meson_mx_mmc_host *host)
        init.name = devm_kasprintf(host->controller_dev, GFP_KERNEL,
                                   "%s#fixed_factor",
                                   dev_name(host->controller_dev));
+       if (!init.name)
+               return -ENOMEM;
+
        init.ops = &clk_fixed_factor_ops;
        init.flags = 0;
        init.parent_names = &clk_fixed_factor_parent;
@@ -612,6 +615,9 @@ static int meson_mx_mmc_register_clks(struct meson_mx_mmc_host *host)
        clk_div_parent = __clk_get_name(host->fixed_factor_clk);
        init.name = devm_kasprintf(host->controller_dev, GFP_KERNEL,
                                   "%s#div", dev_name(host->controller_dev));
+       if (!init.name)
+               return -ENOMEM;
+
        init.ops = &clk_divider_ops;
        init.flags = CLK_SET_RATE_PARENT;
        init.parent_names = &clk_div_parent;
index 476e53d301283d0efa06486312dfc06d40373a16..10ba46b728e82279d66aea48792388145383bbee 100644 (file)
@@ -1434,13 +1434,16 @@ static int mmc_spi_probe(struct spi_device *spi)
        if (status != 0)
                goto fail_add_host;
 
-       if (host->pdata && host->pdata->flags & MMC_SPI_USE_CD_GPIO) {
-               status = mmc_gpio_request_cd(mmc, host->pdata->cd_gpio,
-                                            host->pdata->cd_debounce);
-               if (status != 0)
-                       goto fail_add_host;
-
-               /* The platform has a CD GPIO signal that may support
+       /*
+        * Index 0 is card detect
+        * Old boardfiles were specifying 1 ms as debounce
+        */
+       status = mmc_gpiod_request_cd(mmc, NULL, 0, false, 1, NULL);
+       if (status == -EPROBE_DEFER)
+               goto fail_add_host;
+       if (!status) {
+               /*
+                * The platform has a CD GPIO signal that may support
                 * interrupts, so let mmc_gpiod_request_cd_irq() decide
                 * if polling is needed or not.
                 */
@@ -1448,12 +1451,12 @@ static int mmc_spi_probe(struct spi_device *spi)
                mmc_gpiod_request_cd_irq(mmc);
        }
 
-       if (host->pdata && host->pdata->flags & MMC_SPI_USE_RO_GPIO) {
+       /* Index 1 is write protect/read only */
+       status = mmc_gpiod_request_ro(mmc, NULL, 1, false, 0, NULL);
+       if (status == -EPROBE_DEFER)
+               goto fail_add_host;
+       if (!status)
                has_ro = true;
-               status = mmc_gpio_request_ro(mmc, host->pdata->ro_gpio);
-               if (status != 0)
-                       goto fail_add_host;
-       }
 
        dev_info(&spi->dev, "SD/MMC host %s%s%s%s%s\n",
                        dev_name(&mmc->class_dev),
index 82bab35fff41f1e7ead0e78852d842a293c684f0..e352f5ad58018cebcec91dd87a45e638cb4d8a7c 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/err.h>
 #include <linux/highmem.h>
 #include <linux/log2.h>
+#include <linux/mmc/mmc.h>
 #include <linux/mmc/pm.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
@@ -274,6 +275,7 @@ static struct variant_data variant_stm32_sdmmc = {
        .cmdreg_lrsp_crc        = MCI_CPSM_STM32_LRSP_CRC,
        .cmdreg_srsp_crc        = MCI_CPSM_STM32_SRSP_CRC,
        .cmdreg_srsp            = MCI_CPSM_STM32_SRSP,
+       .cmdreg_stop            = MCI_CPSM_STM32_CMDSTOP,
        .data_cmd_enable        = MCI_CPSM_STM32_CMDTRANS,
        .irq_pio_mask           = MCI_IRQ_PIO_STM32_MASK,
        .datactrl_first         = true,
@@ -1100,6 +1102,10 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
                mmci_reg_delay(host);
        }
 
+       if (host->variant->cmdreg_stop &&
+           cmd->opcode == MMC_STOP_TRANSMISSION)
+               c |= host->variant->cmdreg_stop;
+
        c |= cmd->opcode | host->variant->cmdreg_cpsm_enable;
        if (cmd->flags & MMC_RSP_PRESENT) {
                if (cmd->flags & MMC_RSP_136)
@@ -1190,11 +1196,10 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
                        /* The error clause is handled above, success! */
                        data->bytes_xfered = data->blksz * data->blocks;
 
-               if (!data->stop || host->mrq->sbc) {
+               if (!data->stop || (host->mrq->sbc && !data->error))
                        mmci_request_end(host, data->mrq);
-               } else {
+               else
                        mmci_start_command(host, data->stop, 0);
-               }
        }
 }
 
index 550dd3914461b17245ecc894d995c3b47076b881..24229097d05c2c0fee4b083faeb1a37189c2f7fd 100644 (file)
@@ -264,6 +264,7 @@ struct mmci_host;
  * @cmdreg_lrsp_crc: enable value for long response with crc
  * @cmdreg_srsp_crc: enable value for short response with crc
  * @cmdreg_srsp: enable value for short response without crc
+ * @cmdreg_stop: enable value for stop and abort transmission
  * @datalength_bits: number of bits in the MMCIDATALENGTH register
  * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
  *           is asserted (likewise for RX)
@@ -316,6 +317,7 @@ struct variant_data {
        unsigned int            cmdreg_lrsp_crc;
        unsigned int            cmdreg_srsp_crc;
        unsigned int            cmdreg_srsp;
+       unsigned int            cmdreg_stop;
        unsigned int            datalength_bits;
        unsigned int            fifosize;
        unsigned int            fifohalfsize;
index 6334cc752d8b75e1fa80cb286a28420f7178bf8a..8afeaf81ae6636c8ff8cc370d6858452d8e8a097 100644 (file)
@@ -1114,6 +1114,7 @@ static void msdc_start_command(struct msdc_host *host,
                struct mmc_request *mrq, struct mmc_command *cmd)
 {
        u32 rawcmd;
+       unsigned long flags;
 
        WARN_ON(host->cmd);
        host->cmd = cmd;
@@ -1131,7 +1132,10 @@ static void msdc_start_command(struct msdc_host *host,
        cmd->error = 0;
        rawcmd = msdc_cmd_prepare_raw_cmd(host, mrq, cmd);
 
+       spin_lock_irqsave(&host->lock, flags);
        sdr_set_bits(host->base + MSDC_INTEN, cmd_ints_mask);
+       spin_unlock_irqrestore(&host->lock, flags);
+
        writel(cmd->arg, host->base + SDC_ARG);
        writel(rawcmd, host->base + SDC_CMD);
 }
@@ -1351,6 +1355,31 @@ static void msdc_request_timeout(struct work_struct *work)
        }
 }
 
+static void __msdc_enable_sdio_irq(struct mmc_host *mmc, int enb)
+{
+       unsigned long flags;
+       struct msdc_host *host = mmc_priv(mmc);
+
+       spin_lock_irqsave(&host->lock, flags);
+       if (enb)
+               sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ);
+       else
+               sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ);
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enb)
+{
+       struct msdc_host *host = mmc_priv(mmc);
+
+       __msdc_enable_sdio_irq(mmc, enb);
+
+       if (enb)
+               pm_runtime_get_noresume(host->dev);
+       else
+               pm_runtime_put_noidle(host->dev);
+}
+
 static irqreturn_t msdc_irq(int irq, void *dev_id)
 {
        struct msdc_host *host = (struct msdc_host *) dev_id;
@@ -1373,7 +1402,12 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
                data = host->data;
                spin_unlock_irqrestore(&host->lock, flags);
 
-               if (!(events & event_mask))
+               if ((events & event_mask) & MSDC_INT_SDIOIRQ) {
+                       __msdc_enable_sdio_irq(host->mmc, 0);
+                       sdio_signal_irq(host->mmc);
+               }
+
+               if (!(events & (event_mask & ~MSDC_INT_SDIOIRQ)))
                        break;
 
                if (!mrq) {
@@ -1493,8 +1527,11 @@ static void msdc_init_hw(struct msdc_host *host)
         */
        sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIO);
 
-       /* disable detect SDIO device interrupt function */
-       sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
+       /* Config SDIO device detect interrupt function */
+       if (host->mmc->caps & MMC_CAP_SDIO_IRQ)
+               sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
+       else
+               sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
 
        /* Configure to default data timeout */
        sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3);
@@ -2013,6 +2050,11 @@ static void msdc_hw_reset(struct mmc_host *mmc)
        sdr_clr_bits(host->base + EMMC_IOCON, 1);
 }
 
+static void msdc_ack_sdio_irq(struct mmc_host *mmc)
+{
+       __msdc_enable_sdio_irq(mmc, 1);
+}
+
 static const struct mmc_host_ops mt_msdc_ops = {
        .post_req = msdc_post_req,
        .pre_req = msdc_pre_req,
@@ -2020,6 +2062,8 @@ static const struct mmc_host_ops mt_msdc_ops = {
        .set_ios = msdc_ops_set_ios,
        .get_ro = mmc_gpio_get_ro,
        .get_cd = mmc_gpio_get_cd,
+       .enable_sdio_irq = msdc_enable_sdio_irq,
+       .ack_sdio_irq = msdc_ack_sdio_irq,
        .start_signal_voltage_switch = msdc_ops_switch_volt,
        .card_busy = msdc_card_busy,
        .execute_tuning = msdc_execute_tuning,
@@ -2147,6 +2191,9 @@ static int msdc_drv_probe(struct platform_device *pdev)
        else
                mmc->f_min = DIV_ROUND_UP(host->src_clk_freq, 4 * 4095);
 
+       if (mmc->caps & MMC_CAP_SDIO_IRQ)
+               mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
+
        mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23;
        /* MMC core transfer sizes tunable parameters */
        mmc->max_segs = MAX_BD_NUM;
index c9eed8436b6befbbdd3471d22c435da1660715ad..b294b221f225dd3a5b58eaef8e2aeae00efd035f 100644 (file)
@@ -16,9 +16,7 @@
 #include <linux/device.h>
 #include <linux/slab.h>
 #include <linux/irq.h>
-#include <linux/gpio.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/of_irq.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/mmc_spi.h>
 
 MODULE_LICENSE("GPL");
 
-enum {
-       CD_GPIO = 0,
-       WP_GPIO,
-       NUM_GPIOS,
-};
-
 struct of_mmc_spi {
-       int gpios[NUM_GPIOS];
-       bool alow_gpios[NUM_GPIOS];
        int detect_irq;
        struct mmc_spi_platform_data pdata;
 };
@@ -102,30 +92,6 @@ struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi)
                oms->pdata.ocr_mask |= mask;
        }
 
-       for (i = 0; i < ARRAY_SIZE(oms->gpios); i++) {
-               enum of_gpio_flags gpio_flags;
-
-               oms->gpios[i] = of_get_gpio_flags(np, i, &gpio_flags);
-               if (!gpio_is_valid(oms->gpios[i]))
-                       continue;
-
-               if (gpio_flags & OF_GPIO_ACTIVE_LOW)
-                       oms->alow_gpios[i] = true;
-       }
-
-       if (gpio_is_valid(oms->gpios[CD_GPIO])) {
-               oms->pdata.cd_gpio = oms->gpios[CD_GPIO];
-               oms->pdata.flags |= MMC_SPI_USE_CD_GPIO;
-               if (!oms->alow_gpios[CD_GPIO])
-                       oms->pdata.caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
-       }
-       if (gpio_is_valid(oms->gpios[WP_GPIO])) {
-               oms->pdata.ro_gpio = oms->gpios[WP_GPIO];
-               oms->pdata.flags |= MMC_SPI_USE_RO_GPIO;
-               if (!oms->alow_gpios[WP_GPIO])
-                       oms->pdata.caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
-       }
-
        oms->detect_irq = irq_of_parse_and_map(np, 0);
        if (oms->detect_irq != 0) {
                oms->pdata.init = of_mmc_spi_init;
index 3f4ea8f624be5f1e62a109b8e18ade78be7d3954..29a1ddaa74666336f66791160c538d4b09376341 100644 (file)
@@ -1652,7 +1652,7 @@ static struct mmc_host_ops omap_hsmmc_ops = {
 
 #ifdef CONFIG_DEBUG_FS
 
-static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
+static int mmc_regs_show(struct seq_file *s, void *data)
 {
        struct mmc_host *mmc = s->private;
        struct omap_hsmmc_host *host = mmc_priv(mmc);
@@ -1691,17 +1691,7 @@ static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
        return 0;
 }
 
-static int omap_hsmmc_regs_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, omap_hsmmc_regs_show, inode->i_private);
-}
-
-static const struct file_operations mmc_regs_fops = {
-       .open           = omap_hsmmc_regs_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(mmc_regs);
 
 static void omap_hsmmc_debugfs(struct mmc_host *mmc)
 {
index f7ffbf1676b13f9735b234773cc510752afe60b6..8779bbaa6b697441fe50bc2c39d1337cfc0b43bf 100644 (file)
 #include <linux/mmc/slot-gpio.h>
 #include <linux/io.h>
 #include <linux/regulator/consumer.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/gfp.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
 #include <linux/of_device.h>
 
 #include <asm/sizes.h>
@@ -63,6 +62,8 @@ struct pxamci_host {
        unsigned int            imask;
        unsigned int            power_mode;
        unsigned long           detect_delay_ms;
+       bool                    use_ro_gpio;
+       struct gpio_desc        *power;
        struct pxamci_platform_data *pdata;
 
        struct mmc_request      *mrq;
@@ -101,16 +102,13 @@ static inline int pxamci_set_power(struct pxamci_host *host,
 {
        struct mmc_host *mmc = host->mmc;
        struct regulator *supply = mmc->supply.vmmc;
-       int on;
 
        if (!IS_ERR(supply))
                return mmc_regulator_set_ocr(mmc, supply, vdd);
 
-       if (host->pdata &&
-           gpio_is_valid(host->pdata->gpio_power)) {
-               on = ((1 << vdd) & host->pdata->ocr_mask);
-               gpio_set_value(host->pdata->gpio_power,
-                              !!on ^ host->pdata->gpio_power_invert);
+       if (host->power) {
+               bool on = !!((1 << vdd) & host->pdata->ocr_mask);
+               gpiod_set_value(host->power, on);
        }
 
        if (host->pdata && host->pdata->setpower)
@@ -432,7 +430,7 @@ static int pxamci_get_ro(struct mmc_host *mmc)
 {
        struct pxamci_host *host = mmc_priv(mmc);
 
-       if (host->pdata && gpio_is_valid(host->pdata->gpio_card_ro))
+       if (host->use_ro_gpio)
                return mmc_gpio_get_ro(mmc);
        if (host->pdata && host->pdata->get_ro)
                return !!host->pdata->get_ro(mmc_dev(mmc));
@@ -730,52 +728,38 @@ static int pxamci_probe(struct platform_device *pdev)
        }
 
        if (host->pdata) {
-               int gpio_cd = host->pdata->gpio_card_detect;
-               int gpio_ro = host->pdata->gpio_card_ro;
-               int gpio_power = host->pdata->gpio_power;
-
                host->detect_delay_ms = host->pdata->detect_delay_ms;
 
-               if (gpio_is_valid(gpio_power)) {
-                       ret = devm_gpio_request(dev, gpio_power,
-                                               "mmc card power");
-                       if (ret) {
-                               dev_err(dev,
-                                       "Failed requesting gpio_power %d\n",
-                                       gpio_power);
-                               goto out;
-                       }
-                       gpio_direction_output(gpio_power,
-                                             host->pdata->gpio_power_invert);
+               host->power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
+               if (IS_ERR(host->power)) {
+                       dev_err(dev, "Failed requesting gpio_power\n");
+                       goto out;
                }
 
-               if (gpio_is_valid(gpio_ro)) {
-                       ret = mmc_gpio_request_ro(mmc, gpio_ro);
-                       if (ret) {
-                               dev_err(dev,
-                                       "Failed requesting gpio_ro %d\n",
-                                       gpio_ro);
-                               goto out;
-                       } else {
-                               mmc->caps2 |= host->pdata->gpio_card_ro_invert ?
-                                       0 : MMC_CAP2_RO_ACTIVE_HIGH;
-                       }
+               /* FIXME: should we pass detection delay to debounce? */
+               ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0, NULL);
+               if (ret && ret != -ENOENT) {
+                       dev_err(dev, "Failed requesting gpio_cd\n");
+                       goto out;
                }
 
-               if (gpio_is_valid(gpio_cd))
-                       ret = mmc_gpio_request_cd(mmc, gpio_cd, 0);
-               if (ret) {
-                       dev_err(dev, "Failed requesting gpio_cd %d\n",
-                               gpio_cd);
+               ret = mmc_gpiod_request_ro(mmc, "wp", 0, false, 0, NULL);
+               if (ret && ret != -ENOENT) {
+                       dev_err(dev, "Failed requesting gpio_ro\n");
                        goto out;
                }
+               if (!ret) {
+                       host->use_ro_gpio = true;
+                       mmc->caps2 |= host->pdata->gpio_card_ro_invert ?
+                               0 : MMC_CAP2_RO_ACTIVE_HIGH;
+               }
 
                if (host->pdata->init)
                        host->pdata->init(dev, pxamci_detect_irq, mmc);
 
-               if (gpio_is_valid(gpio_power) && host->pdata->setpower)
+               if (host->power && host->pdata->setpower)
                        dev_warn(dev, "gpio_power and setpower() both defined\n");
-               if (gpio_is_valid(gpio_ro) && host->pdata->get_ro)
+               if (host->use_ro_gpio && host->pdata->get_ro)
                        dev_warn(dev, "gpio_ro and get_ro() both defined\n");
        }
 
index d3ac43c3d0b655dc03023ade54926461f250ca2d..31a351a20dc02aabbe7d5bb65ab1f76eee6d4f06 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/pinctrl/pinctrl-state.h>
 #include <linux/regulator/consumer.h>
+#include <linux/sys_soc.h>
 
 #include "renesas_sdhi.h"
 #include "tmio_mmc.h"
 #define SDHI_VER_GEN3_SD       0xcc10
 #define SDHI_VER_GEN3_SDMMC    0xcd10
 
+struct renesas_sdhi_quirks {
+       bool hs400_disabled;
+       bool hs400_4taps;
+};
+
 static void renesas_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
 {
        u32 val;
@@ -163,15 +169,6 @@ static void renesas_sdhi_set_clock(struct tmio_mmc_host *host,
        if (new_clock == 0)
                goto out;
 
-       /*
-        * Both HS400 and HS200/SD104 set 200MHz, but some devices need to
-        * set 400MHz to distinguish the CPG settings in HS400.
-        */
-       if (host->mmc->ios.timing == MMC_TIMING_MMC_HS400 &&
-           host->pdata->flags & TMIO_MMC_HAVE_4TAP_HS400 &&
-           new_clock == 200000000)
-               new_clock = 400000000;
-
        clock = renesas_sdhi_clk_update(host, new_clock) / 512;
 
        for (clk = 0x80000080; new_clock >= (clock << 1); clk >>= 1)
@@ -532,6 +529,10 @@ static void renesas_sdhi_hw_reset(struct tmio_mmc_host *host)
        sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
                       ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
                       sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
+
+       if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
+               sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK,
+                                            TMIO_MASK_INIT_RCAR2);
 }
 
 static int renesas_sdhi_wait_idle(struct tmio_mmc_host *host, u32 bit)
@@ -602,11 +603,31 @@ static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
        renesas_sdhi_sdbuf_width(host, enable ? width : 16);
 }
 
+static const struct renesas_sdhi_quirks sdhi_quirks_h3_m3w_es1 = {
+       .hs400_disabled = true,
+       .hs400_4taps = true,
+};
+
+static const struct renesas_sdhi_quirks sdhi_quirks_h3_es2 = {
+       .hs400_disabled = false,
+       .hs400_4taps = true,
+};
+
+static const struct soc_device_attribute sdhi_quirks_match[]  = {
+       { .soc_id = "r8a7795", .revision = "ES1.*", .data = &sdhi_quirks_h3_m3w_es1 },
+       { .soc_id = "r8a7795", .revision = "ES2.0", .data = &sdhi_quirks_h3_es2 },
+       { .soc_id = "r8a7796", .revision = "ES1.0", .data = &sdhi_quirks_h3_m3w_es1 },
+       { .soc_id = "r8a7796", .revision = "ES1.1", .data = &sdhi_quirks_h3_m3w_es1 },
+       { /* Sentinel. */ },
+};
+
 int renesas_sdhi_probe(struct platform_device *pdev,
                       const struct tmio_mmc_dma_ops *dma_ops)
 {
        struct tmio_mmc_data *mmd = pdev->dev.platform_data;
+       const struct renesas_sdhi_quirks *quirks = NULL;
        const struct renesas_sdhi_of_data *of_data;
+       const struct soc_device_attribute *attr;
        struct tmio_mmc_data *mmc_data;
        struct tmio_mmc_dma *dma_priv;
        struct tmio_mmc_host *host;
@@ -616,6 +637,10 @@ int renesas_sdhi_probe(struct platform_device *pdev,
 
        of_data = of_device_get_match_data(&pdev->dev);
 
+       attr = soc_device_match(sdhi_quirks_match);
+       if (attr)
+               quirks = attr->data;
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res)
                return -EINVAL;
@@ -681,6 +706,12 @@ int renesas_sdhi_probe(struct platform_device *pdev,
        host->multi_io_quirk    = renesas_sdhi_multi_io_quirk;
        host->dma_ops           = dma_ops;
 
+       if (quirks && quirks->hs400_disabled)
+               host->mmc->caps2 &= ~(MMC_CAP2_HS400 | MMC_CAP2_HS400_ES);
+
+       if (quirks && quirks->hs400_4taps)
+               mmc_data->flags |= TMIO_MMC_HAVE_4TAP_HS400;
+
        /* For some SoC, we disable internal WP. GPIO may override this */
        if (mmc_can_gpio_ro(host->mmc))
                mmc_data->capabilities2 &= ~MMC_CAP2_NO_WRITE_PROTECT;
@@ -691,6 +722,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
                host->ops.card_busy = renesas_sdhi_card_busy;
                host->ops.start_signal_voltage_switch =
                        renesas_sdhi_start_signal_voltage_switch;
+               host->sdcard_irq_setbit_mask = TMIO_STAT_ALWAYS_SET_27;
        }
 
        /* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */
index b6f54102bfdd3a76c6b77f4c9d62df8ad3c624f6..92c9b15252da7e411db9eceb8191b5b042cde4a5 100644 (file)
@@ -34,7 +34,7 @@
 #define DTRAN_MODE_CH_NUM_CH0  0       /* "downstream" = for write commands */
 #define DTRAN_MODE_CH_NUM_CH1  BIT(16) /* "upstream" = for read commands */
 #define DTRAN_MODE_BUS_WIDTH   (BIT(5) | BIT(4))
-#define DTRAN_MODE_ADDR_MODE   BIT(0)  /* 1 = Increment address */
+#define DTRAN_MODE_ADDR_MODE   BIT(0)  /* 1 = Increment address, 0 = Fixed */
 
 /* DM_CM_DTRAN_CTRL */
 #define DTRAN_CTRL_DM_START    BIT(0)
@@ -73,6 +73,9 @@ static unsigned long global_flags;
 #define SDHI_INTERNAL_DMAC_ONE_RX_ONLY 0
 #define SDHI_INTERNAL_DMAC_RX_IN_USE   1
 
+/* RZ/A2 does not have the ADRR_MODE bit */
+#define SDHI_INTERNAL_DMAC_ADDR_MODE_FIXED_ONLY 2
+
 /* Definitions for sampling clocks */
 static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
        {
@@ -81,15 +84,14 @@ static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
        },
 };
 
-static const struct renesas_sdhi_of_data of_rcar_r8a7795_compatible = {
+static const struct renesas_sdhi_of_data of_rza2_compatible = {
        .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
-                         TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2 |
-                         TMIO_MMC_HAVE_4TAP_HS400,
+                         TMIO_MMC_HAVE_CBSY,
+       .tmio_ocr_mask  = MMC_VDD_32_33,
        .capabilities   = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
                          MMC_CAP_CMD23,
-       .capabilities2  = MMC_CAP2_NO_WRITE_PROTECT,
        .bus_shift      = 2,
-       .scc_offset     = 0x1000,
+       .scc_offset     = 0 - 0x1000,
        .taps           = rcar_gen3_scc_taps,
        .taps_num       = ARRAY_SIZE(rcar_gen3_scc_taps),
        /* DMAC can handle 0xffffffff blk count but only 1 segment */
@@ -113,9 +115,10 @@ static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
 };
 
 static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = {
+       { .compatible = "renesas,sdhi-r7s9210", .data = &of_rza2_compatible, },
        { .compatible = "renesas,sdhi-mmc-r8a77470", .data = &of_rcar_gen3_compatible, },
-       { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_r8a7795_compatible, },
-       { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_r8a7795_compatible, },
+       { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, },
+       { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, },
        { .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
        {},
 };
@@ -172,7 +175,10 @@ renesas_sdhi_internal_dmac_start_dma(struct tmio_mmc_host *host,
                                     struct mmc_data *data)
 {
        struct scatterlist *sg = host->sg_ptr;
-       u32 dtran_mode = DTRAN_MODE_BUS_WIDTH | DTRAN_MODE_ADDR_MODE;
+       u32 dtran_mode = DTRAN_MODE_BUS_WIDTH;
+
+       if (!test_bit(SDHI_INTERNAL_DMAC_ADDR_MODE_FIXED_ONLY, &global_flags))
+               dtran_mode |= DTRAN_MODE_ADDR_MODE;
 
        if (!dma_map_sg(&host->pdev->dev, sg, host->sg_len,
                        mmc_get_dma_dir(data)))
@@ -292,18 +298,22 @@ static const struct tmio_mmc_dma_ops renesas_sdhi_internal_dmac_dma_ops = {
  */
 static const struct soc_device_attribute soc_whitelist[] = {
        /* specific ones */
+       { .soc_id = "r7s9210",
+         .data = (void *)BIT(SDHI_INTERNAL_DMAC_ADDR_MODE_FIXED_ONLY) },
        { .soc_id = "r8a7795", .revision = "ES1.*",
          .data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
        { .soc_id = "r8a7796", .revision = "ES1.0",
          .data = (void *)BIT(SDHI_INTERNAL_DMAC_ONE_RX_ONLY) },
        /* generic ones */
        { .soc_id = "r8a774a1" },
+       { .soc_id = "r8a774c0" },
        { .soc_id = "r8a77470" },
        { .soc_id = "r8a7795" },
        { .soc_id = "r8a7796" },
        { .soc_id = "r8a77965" },
        { .soc_id = "r8a77970" },
        { .soc_id = "r8a77980" },
+       { .soc_id = "r8a77990" },
        { .soc_id = "r8a77995" },
        { /* sentinel */ }
 };
index 1a4016f635d398c28ca9edc5cf202eae6776ffa7..8471160316e073c5fee142b3393ea57c9d9f4e0a 100644 (file)
@@ -75,19 +75,6 @@ static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
        },
 };
 
-static const struct renesas_sdhi_of_data of_rcar_r8a7795_compatible = {
-       .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
-                         TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2 |
-                         TMIO_MMC_HAVE_4TAP_HS400,
-       .capabilities   = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
-                         MMC_CAP_CMD23,
-       .capabilities2  = MMC_CAP2_NO_WRITE_PROTECT,
-       .bus_shift      = 2,
-       .scc_offset     = 0x1000,
-       .taps           = rcar_gen3_scc_taps,
-       .taps_num       = ARRAY_SIZE(rcar_gen3_scc_taps),
-};
-
 static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
        .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_CLK_ACTUAL |
                          TMIO_MMC_HAVE_CBSY | TMIO_MMC_MIN_RCAR2,
@@ -114,8 +101,8 @@ static const struct of_device_id renesas_sdhi_sys_dmac_of_match[] = {
        { .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, },
        { .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, },
        { .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, },
-       { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_r8a7795_compatible, },
-       { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_r8a7795_compatible, },
+       { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, },
+       { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, },
        { .compatible = "renesas,rcar-gen1-sdhi", .data = &of_rcar_gen1_compatible, },
        { .compatible = "renesas,rcar-gen2-sdhi", .data = &of_rcar_gen2_compatible, },
        { .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, },
@@ -493,8 +480,7 @@ static const struct soc_device_attribute gen3_soc_whitelist[] = {
 
 static int renesas_sdhi_sys_dmac_probe(struct platform_device *pdev)
 {
-       if ((of_device_get_match_data(&pdev->dev) == &of_rcar_gen3_compatible ||
-           of_device_get_match_data(&pdev->dev) == &of_rcar_r8a7795_compatible) &&
+       if (of_device_get_match_data(&pdev->dev) == &of_rcar_gen3_compatible &&
            !soc_device_match(gen3_soc_whitelist))
                return -ENODEV;
 
index 9a3ff22dd0fe29353ffa20a94695670b15c81737..669c6ab021c8605960c0000027b1510df0d69096 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/mmc/sd.h>
 #include <linux/mmc/card.h>
 #include <linux/scatterlist.h>
+#include <linux/pm.h>
 #include <linux/pm_runtime.h>
 
 #include <linux/rtsx_usb.h>
@@ -1042,9 +1043,9 @@ static int sd_set_power_mode(struct rtsx_usb_sdmmc *host,
 
        if (power_mode == MMC_POWER_OFF) {
                err = sd_power_off(host);
-               pm_runtime_put(sdmmc_dev(host));
+               pm_runtime_put_noidle(sdmmc_dev(host));
        } else {
-               pm_runtime_get_sync(sdmmc_dev(host));
+               pm_runtime_get_noresume(sdmmc_dev(host));
                err = sd_power_on(host);
        }
 
@@ -1297,16 +1298,20 @@ static void rtsx_usb_update_led(struct work_struct *work)
                container_of(work, struct rtsx_usb_sdmmc, led_work);
        struct rtsx_ucr *ucr = host->ucr;
 
-       pm_runtime_get_sync(sdmmc_dev(host));
+       pm_runtime_get_noresume(sdmmc_dev(host));
        mutex_lock(&ucr->dev_mutex);
 
+       if (host->power_mode == MMC_POWER_OFF)
+               goto out;
+
        if (host->led.brightness == LED_OFF)
                rtsx_usb_turn_off_led(ucr);
        else
                rtsx_usb_turn_on_led(ucr);
 
+out:
        mutex_unlock(&ucr->dev_mutex);
-       pm_runtime_put(sdmmc_dev(host));
+       pm_runtime_put_sync_suspend(sdmmc_dev(host));
 }
 #endif
 
@@ -1320,7 +1325,7 @@ static void rtsx_usb_init_host(struct rtsx_usb_sdmmc *host)
        mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED |
                MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST |
                MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 |
-               MMC_CAP_NEEDS_POLL | MMC_CAP_ERASE;
+               MMC_CAP_ERASE | MMC_CAP_SYNC_RUNTIME_PM;
        mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE |
                MMC_CAP2_NO_SDIO;
 
@@ -1363,8 +1368,6 @@ static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev)
 
        mutex_init(&host->host_mutex);
        rtsx_usb_init_host(host);
-       pm_runtime_use_autosuspend(&pdev->dev);
-       pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
        pm_runtime_enable(&pdev->dev);
 
 #ifdef RTSX_USB_USE_LEDS_CLASS
@@ -1419,7 +1422,6 @@ static int rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev)
 
        mmc_free_host(mmc);
        pm_runtime_disable(&pdev->dev);
-       pm_runtime_dont_use_autosuspend(&pdev->dev);
        platform_set_drvdata(pdev, NULL);
 
        dev_dbg(&(pdev->dev),
@@ -1428,6 +1430,31 @@ static int rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int rtsx_usb_sdmmc_runtime_suspend(struct device *dev)
+{
+       struct rtsx_usb_sdmmc *host = dev_get_drvdata(dev);
+
+       host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
+       return 0;
+}
+
+static int rtsx_usb_sdmmc_runtime_resume(struct device *dev)
+{
+       struct rtsx_usb_sdmmc *host = dev_get_drvdata(dev);
+
+       host->mmc->caps |= MMC_CAP_NEEDS_POLL;
+       if (sdmmc_get_cd(host->mmc) == 1)
+               mmc_detect_change(host->mmc, 0);
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops rtsx_usb_sdmmc_dev_pm_ops = {
+       SET_RUNTIME_PM_OPS(rtsx_usb_sdmmc_runtime_suspend,
+                          rtsx_usb_sdmmc_runtime_resume, NULL)
+};
+
 static const struct platform_device_id rtsx_usb_sdmmc_ids[] = {
        {
                .name = "rtsx_usb_sdmmc",
@@ -1443,6 +1470,7 @@ static struct platform_driver rtsx_usb_sdmmc_driver = {
        .id_table       = rtsx_usb_sdmmc_ids,
        .driver         = {
                .name   = "rtsx_usb_sdmmc",
+               .pm     = &rtsx_usb_sdmmc_dev_pm_ops,
        },
 };
 module_platform_driver(rtsx_usb_sdmmc_driver);
index f77493604312941d8b7985c756d7a94f93af1bc6..10f5219b3b408fa3232d31498ce21910071f3503 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/of_gpio.h>
 #include <linux/mmc/slot-gpio.h>
 
 #include <plat/gpio-cfg.h>
@@ -1406,18 +1405,7 @@ static int s3cmci_state_show(struct seq_file *seq, void *v)
        return 0;
 }
 
-static int s3cmci_state_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, s3cmci_state_show, inode->i_private);
-}
-
-static const struct file_operations s3cmci_fops_state = {
-       .owner          = THIS_MODULE,
-       .open           = s3cmci_state_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(s3cmci_state);
 
 #define DBG_REG(_r) { .addr = S3C2410_SDI##_r, .name = #_r }
 
@@ -1459,18 +1447,7 @@ static int s3cmci_regs_show(struct seq_file *seq, void *v)
        return 0;
 }
 
-static int s3cmci_regs_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, s3cmci_regs_show, inode->i_private);
-}
-
-static const struct file_operations s3cmci_fops_regs = {
-       .owner          = THIS_MODULE,
-       .open           = s3cmci_regs_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(s3cmci_regs);
 
 static void s3cmci_debugfs_attach(struct s3cmci_host *host)
 {
@@ -1484,14 +1461,14 @@ static void s3cmci_debugfs_attach(struct s3cmci_host *host)
 
        host->debug_state = debugfs_create_file("state", 0444,
                                                host->debug_root, host,
-                                               &s3cmci_fops_state);
+                                               &s3cmci_state_fops);
 
        if (IS_ERR(host->debug_state))
                dev_err(dev, "failed to create debug state file\n");
 
        host->debug_regs = debugfs_create_file("regs", 0444,
                                               host->debug_root, host,
-                                              &s3cmci_fops_regs);
+                                              &s3cmci_regs_fops);
 
        if (IS_ERR(host->debug_regs))
                dev_err(dev, "failed to create debug regs file\n");
@@ -1545,25 +1522,19 @@ static int s3cmci_probe_pdata(struct s3cmci_host *host)
        if (pdata->wprotect_invert)
                mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
 
-       if (pdata->detect_invert)
-                mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
-
-       if (gpio_is_valid(pdata->gpio_detect)) {
-               ret = mmc_gpio_request_cd(mmc, pdata->gpio_detect, 0);
-               if (ret) {
-                       dev_err(&pdev->dev, "error requesting GPIO for CD %d\n",
-                               ret);
-                       return ret;
-               }
+       /* If we get -ENOENT we have no card detect GPIO line */
+       ret = mmc_gpiod_request_cd(mmc, "cd", 0, false, 0, NULL);
+       if (ret != -ENOENT) {
+               dev_err(&pdev->dev, "error requesting GPIO for CD %d\n",
+                       ret);
+               return ret;
        }
 
-       if (gpio_is_valid(pdata->gpio_wprotect)) {
-               ret = mmc_gpio_request_ro(mmc, pdata->gpio_wprotect);
-               if (ret) {
-                       dev_err(&pdev->dev, "error requesting GPIO for WP %d\n",
-                               ret);
-                       return ret;
-               }
+       ret = mmc_gpiod_request_ro(host->mmc, "wp", 0, false, 0, NULL);
+       if (ret != -ENOENT) {
+               dev_err(&pdev->dev, "error requesting GPIO for WP %d\n",
+                       ret);
+               return ret;
        }
 
        return 0;
index 057e24f4a620f692add8f632995872f5bcb88500..6669e540851d1430f561c9e7e1fdfc1614cae03a 100644 (file)
@@ -437,7 +437,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
                   MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
                   MMC_CAP_CMD_DURING_TFR | MMC_CAP_WAIT_WHILE_BUSY,
        .flags   = SDHCI_ACPI_RUNTIME_PM,
-       .quirks  = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+       .quirks  = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
+                  SDHCI_QUIRK_NO_LED,
        .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
                   SDHCI_QUIRK2_STOP_WITH_TC |
                   SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400,
@@ -448,6 +449,7 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
 
 static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
        .quirks  = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
+                  SDHCI_QUIRK_NO_LED |
                   SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
        .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
        .caps    = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD |
@@ -462,7 +464,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
 static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
        .flags   = SDHCI_ACPI_SD_CD | SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL |
                   SDHCI_ACPI_RUNTIME_PM,
-       .quirks  = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+       .quirks  = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
+                  SDHCI_QUIRK_NO_LED,
        .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
                   SDHCI_QUIRK2_STOP_WITH_TC,
        .caps    = MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_AGGRESSIVE_PM,
index 7a343b87b5e581814235bdf4bbe0cd660732d27e..e2412875dac586003e592792ac55d4fd49d97423 100644 (file)
@@ -14,7 +14,7 @@
  */
 
 #include <linux/bitfield.h>
-#include <linux/bitops.h>
+#include <linux/bits.h>
 #include <linux/iopoll.h>
 #include <linux/module.h>
 #include <linux/mmc/host.h>
index f44e49014a440e1a4790d1d13b3ea7f62037db5f..d0d319398a547827a5a7a5053f3f12f802402f61 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/clk.h>
-#include <linux/gpio.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/mmc/host.h>
@@ -21,7 +20,6 @@
 #include <linux/mmc/slot-gpio.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/of_gpio.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/platform_data/mmc-esdhc-imx.h>
 #include <linux/pm_runtime.h>
@@ -429,7 +427,7 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
                                val = readl(host->ioaddr + ESDHC_MIX_CTRL);
                        else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING)
                                /* the std tuning bits is in ACMD12_ERR for imx6sl */
-                               val = readl(host->ioaddr + SDHCI_ACMD12_ERR);
+                               val = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS);
                }
 
                if (val & ESDHC_MIX_CTRL_EXE_TUNE)
@@ -494,7 +492,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
                        }
                        writel(new_val , host->ioaddr + ESDHC_MIX_CTRL);
                } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
-                       u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR);
+                       u32 v = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS);
                        u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL);
                        if (val & SDHCI_CTRL_TUNED_CLK) {
                                v |= ESDHC_MIX_CTRL_SMPCLK_SEL;
@@ -512,7 +510,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
                                v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
                        }
 
-                       writel(v, host->ioaddr + SDHCI_ACMD12_ERR);
+                       writel(v, host->ioaddr + SDHCI_AUTO_CMD_STATUS);
                        writel(m, host->ioaddr + ESDHC_MIX_CTRL);
                }
                return;
@@ -957,9 +955,9 @@ static void esdhc_reset_tuning(struct sdhci_host *host)
                        writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL);
                        writel(0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
                } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) {
-                       ctrl = readl(host->ioaddr + SDHCI_ACMD12_ERR);
+                       ctrl = readl(host->ioaddr + SDHCI_AUTO_CMD_STATUS);
                        ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL;
-                       writel(ctrl, host->ioaddr + SDHCI_ACMD12_ERR);
+                       writel(ctrl, host->ioaddr + SDHCI_AUTO_CMD_STATUS);
                }
        }
 }
@@ -1139,8 +1137,12 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
        if (of_get_property(np, "fsl,wp-controller", NULL))
                boarddata->wp_type = ESDHC_WP_CONTROLLER;
 
-       boarddata->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
-       if (gpio_is_valid(boarddata->wp_gpio))
+       /*
+        * If we have this property, then activate WP check.
+        * Retrieveing and requesting the actual WP GPIO will happen
+        * in the call to mmc_of_parse().
+        */
+       if (of_property_read_bool(np, "wp-gpios"))
                boarddata->wp_type = ESDHC_WP_GPIO;
 
        of_property_read_u32(np, "fsl,tuning-step", &boarddata->tuning_step);
@@ -1198,7 +1200,7 @@ static int sdhci_esdhc_imx_probe_nondt(struct platform_device *pdev,
                                host->mmc->parent->platform_data);
        /* write_protect */
        if (boarddata->wp_type == ESDHC_WP_GPIO) {
-               err = mmc_gpio_request_ro(host->mmc, boarddata->wp_gpio);
+               err = mmc_gpiod_request_ro(host->mmc, "wp", 0, false, 0, NULL);
                if (err) {
                        dev_err(mmc_dev(host->mmc),
                                "failed to request write-protect gpio!\n");
@@ -1210,7 +1212,7 @@ static int sdhci_esdhc_imx_probe_nondt(struct platform_device *pdev,
        /* card_detect */
        switch (boarddata->cd_type) {
        case ESDHC_CD_GPIO:
-               err = mmc_gpio_request_cd(host->mmc, boarddata->cd_gpio, 0);
+               err = mmc_gpiod_request_cd(host->mmc, "cd", 0, false, 0, NULL);
                if (err) {
                        dev_err(mmc_dev(host->mmc),
                                "failed to request card-detect gpio!\n");
@@ -1317,7 +1319,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
 
                /* clear tuning bits in case ROM has set it already */
                writel(0x0, host->ioaddr + ESDHC_MIX_CTRL);
-               writel(0x0, host->ioaddr + SDHCI_ACMD12_ERR);
+               writel(0x0, host->ioaddr + SDHCI_AUTO_CMD_STATUS);
                writel(0x0, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
        }
 
index 3f16d9c90ba2baba844a55143d28c4ba18472cf0..39dbbd6eaf28fbca906ef2bf984de40031397334 100644 (file)
 
 /* Tuning Block Control Register */
 #define ESDHC_TBCTL                    0x120
+#define ESDHC_HS400_WNDW_ADJUST                0x00000040
+#define ESDHC_HS400_MODE               0x00000010
 #define ESDHC_TB_EN                    0x00000004
 #define ESDHC_TBPTR                    0x128
 
+/* SD Clock Control Register */
+#define ESDHC_SDCLKCTL                 0x144
+#define ESDHC_LPBK_CLK_SEL             0x80000000
+#define ESDHC_CMD_CLK_CTL              0x00008000
+
+/* SD Timing Control Register */
+#define ESDHC_SDTIMNGCTL               0x148
+#define ESDHC_FLW_CTL_BG               0x00008000
+
+/* DLL Config 0 Register */
+#define ESDHC_DLLCFG0                  0x160
+#define ESDHC_DLL_ENABLE               0x80000000
+#define ESDHC_DLL_FREQ_SEL             0x08000000
+
+/* DLL Config 1 Register */
+#define ESD