]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
Merge tag 'mmc-v4.1' of git://git.linaro.org/people/ulf.hansson/mmc
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 13 Apr 2015 21:53:03 +0000 (14:53 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 13 Apr 2015 21:53:03 +0000 (14:53 -0700)
Pull MMC updates from Ulf Hansson:
 "MMC core:
   - Add support for marking HPI as broken through devicetree
   - Enable runtime PM management of host devices
   - Remove the ->enable|disable() callbacks
   - Restructure code and cleanups
   - Refreshed some of the MMC sections in MAINTAINERS

  MMC host:
   - dw_mmc: HS400 mode support
   - dw_mmc: Add the cmd11 timer to detect a timeout
   - dw_mmc: Endian agnostic IO accessors
   - dw_mmc: Bugfixes
   - sh_mmcif: Add exclusion between cmd and interrupt
   - omap_hsmmc: Hibernation support
   - omap_hsmmc: Rework and simplify cover/card detect
   - omap_hsmmc: Stop using ->enable|disable() callbacks
   - atmel-mci: Endian agnostic IO
   - sunxi: Enable MMC_CAP_SDIO_IRQ
   - sdhci-st: Add support for the stih407 family silicon
   - sdhci-st: UHS card support in SDR104 mode
   - sdhci-st: HS200 mode support
   - sdhci-esdhc-imx: Use common mmc DT parser
   - sdhci-of-arasan: Use common mmc DT parser
   - sdhci-iproc: Add new driver for Broadcom IPROC SDHCI controller
   - sdhci-tegra: Convert to GPIO descriptors
   - sdhci-tegra: Optmize write_w path for tegra114 and later
   - sdhci-sirf: Update tuning procedure
   - sdhci: Fix card presence logic
   - sdhci: Cleanups and consolidation"

* tag 'mmc-v4.1' of git://git.linaro.org/people/ulf.hansson/mmc: (79 commits)
  mmc: sdhci-st: Update ST SDHCI binding documentation.
  mmc: sdhci-st: Update the quirks for this controller.
  mmc: sdhci-st: Add sdhci_st_set_uhs_signaling function.
  mmc: sdhci-st: Add st_mmcss_cconfig function to configure mmcss glue registers.
  mmc: sdhci-st: Add delay management functions for top registers (eMMC).
  mmc: sdhci-st: Add support for de-asserting reset signal and top regs resource
  mmc: sdhci-st: Add macros for register offsets and bitfields for mmcss glue regs
  mmc: sdhci-esdhc-imx: Call mmc_of_parse()
  mmc: dw_mmc: Add locking around cmd11 timer
  mmc: dw_mmc: Add a return in an unexpected cmd11 timeout
  mmc: dw_mmc: Increase cmd11 timeout to 500ms
  mmc: dw_mmc: fix fifo ordering in big endian
  mmc: dw_mmc: change idmac descriptor files to __le32
  mmc: dw_mmc: make IO accessors endian agnostic
  mmc: core: Convert the error field in struct mmc_command|data into an int
  mmc: sdhci-of-arasan: Call OF parsing for MMC
  mmc: sdhci-pci: fix 64 BIT DMA quirks for rtsx
  mmc: Add support for marking hpi as broken through devicetree
  mmc: sdhci-tegra: convert to use GPIO descriptors
  mmc: omap_hsmmc: use generic slot-gpio isr to manage card detect pin
  ...

55 files changed:
CREDITS
Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt
Documentation/devicetree/bindings/mmc/mmc-card.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/sdhci-st.txt
MAINTAINERS
arch/arm/mach-omap2/hsmmc.c
drivers/mmc/core/core.c
drivers/mmc/core/mmc.c
drivers/mmc/core/pwrseq.c
drivers/mmc/core/pwrseq.h
drivers/mmc/core/pwrseq_emmc.c
drivers/mmc/core/pwrseq_simple.c
drivers/mmc/core/sdio.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/atmel-mci-regs.h
drivers/mmc/host/dw_mmc-exynos.c
drivers/mmc/host/dw_mmc-exynos.h
drivers/mmc/host/dw_mmc-rockchip.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h
drivers/mmc/host/mmc_spi.c
drivers/mmc/host/mmci.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci-bcm-kona.c
drivers/mmc/host/sdhci-bcm2835.c
drivers/mmc/host/sdhci-cns3xxx.c
drivers/mmc/host/sdhci-dove.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-iproc.c [new file with mode: 0644]
drivers/mmc/host/sdhci-msm.c
drivers/mmc/host/sdhci-of-arasan.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-of-hlwd.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-pltfm.c
drivers/mmc/host/sdhci-sirf.c
drivers/mmc/host/sdhci-spear.c
drivers/mmc/host/sdhci-st.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/sunxi-mmc.c
drivers/mmc/host/tmio_mmc_pio.c
drivers/mmc/host/wmt-sdmmc.c
include/linux/mmc/core.h
include/linux/mmc/dw_mmc.h
include/linux/mmc/host.h
include/linux/mmc/sdhci-spear.h [deleted file]
include/linux/mmc/sdhci.h [deleted file]
include/linux/platform_data/hsmmc-omap.h

diff --git a/CREDITS b/CREDITS
index 96935df0b6fe5d10cf1558c8ed6a15af89fb0cac..843e17647f3b72bfda48632d67ba089307b15602 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -187,6 +187,10 @@ N: Krishna Balasubramanian
 E: balasub@cis.ohio-state.edu
 D: Wrote SYS V IPC (part of standard kernel since 0.99.10)
 
+N: Chris Ball
+E: chris@printf.net
+D: Former maintainer of the MMC/SD/SDIO subsystem.
+
 N: Dario Ballabio
 E: ballabio_dario@emc.com
 E: dario.ballabio@tiscalinet.it
diff --git a/Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt b/Documentation/devicetree/bindings/mmc/brcm,sdhci-iproc.txt
new file mode 100644 (file)
index 0000000..72cc9cc
--- /dev/null
@@ -0,0 +1,23 @@
+Broadcom IPROC SDHCI controller
+
+This file documents differences between the core properties described
+by mmc.txt and the properties that represent the IPROC SDHCI controller.
+
+Required properties:
+- compatible : Should be "brcm,sdhci-iproc-cygnus".
+- clocks : The clock feeding the SDHCI controller.
+
+Optional properties:
+  - sdhci,auto-cmd12: specifies that controller should use auto CMD12.
+
+Example:
+
+sdhci0: sdhci@0x18041000 {
+       compatible = "brcm,sdhci-iproc-cygnus";
+       reg = <0x18041000 0x100>;
+       interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+       clocks = <&lcpll0_clks BCM_CYGNUS_LCPLL0_SDIO_CLK>;
+       bus-width = <4>;
+       sdhci,auto-cmd12;
+       no-1-8-v;
+};
index ee4fc0576c7d866b318eda917066e76e920b4f53..aad98442788bc386366b019a6166e6145b2f0017 100644 (file)
@@ -36,6 +36,8 @@ Required Properties:
   in transmit mode and CIU clock phase shift value in receive mode for double
   data rate mode operation. Refer notes below for the order of the cells and the
   valid values.
+* samsung,dw-mshc-hs400-timing: Specifies the value of CIU TX and RX clock phase
+  shift value for hs400 mode operation.
 
   Notes for the sdr-timing and ddr-timing values:
 
@@ -50,6 +52,9 @@ Required Properties:
       - if CIU clock divider value is 0 (that is divide by 1), both tx and rx
         phase shift clocks should be 0.
 
+* samsung,read-strobe-delay: RCLK (Data strobe) delay to control HS400 mode
+  (Latency value for delay line in Read path)
+
 Required properties for a slot (Deprecated - Recommend to use one slot per host):
 
 * gpios: specifies a list of gpios used for command, clock and data bus. The
@@ -82,5 +87,7 @@ Example:
                samsung,dw-mshc-ciu-div = <3>;
                samsung,dw-mshc-sdr-timing = <2 3>;
                samsung,dw-mshc-ddr-timing = <1 2>;
+               samsung,dw-mshc-hs400-timing = <0 2>;
+               samsung,read-strobe-delay = <90>;
                bus-width = <8>;
        };
index 9046ba06c47ab63570f99769455dcfeeea020e10..415c5575cbf7a1394439f3ba807e0f8547167231 100644 (file)
@@ -17,6 +17,10 @@ Optional properties:
   to select a proper data sampling window in case the clock quality is not good
   due to signal path is too long on the board. Please refer to eSDHC/uSDHC
   chapter, DLL (Delay Line) section in RM for details.
+- voltage-ranges : Specify the voltage range in case there are software
+  transparent level shifters on the outputs of the controller. Two cells are
+  required, first cell specifies minimum slot voltage (mV), second cell
+  specifies maximum slot voltage (mV). Several ranges could be specified.
 
 Examples:
 
diff --git a/Documentation/devicetree/bindings/mmc/mmc-card.txt b/Documentation/devicetree/bindings/mmc/mmc-card.txt
new file mode 100644 (file)
index 0000000..a70fcd6
--- /dev/null
@@ -0,0 +1,31 @@
+mmc-card / eMMC bindings
+------------------------
+
+This documents describes the devicetree bindings for a mmc-host controller
+child node describing a mmc-card / an eMMC, see "Use of Function subnodes"
+in mmc.txt
+
+Required properties:
+-compatible : Must be "mmc-card"
+-reg        : Must be <0>
+
+Optional properties:
+-broken-hpi : Use this to indicate that the mmc-card has a broken hpi
+              implementation, and that hpi should not be used
+
+Example:
+
+&mmc2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc2_pins_a>;
+       vmmc-supply = <&reg_vcc3v3>;
+       bus-width = <8>;
+       non-removable;
+       status = "okay";
+
+       mmccard: mmccard@0 {
+               reg = <0>;
+               compatible = "mmc-card";
+               broken-hpi;
+       };
+};
index 7527db447a35b1ed92c79611852f1f365b8900e3..18d950df2749cbf3964f52f6718ff14d21c88348 100644 (file)
@@ -5,20 +5,62 @@ Documentation/devicetree/bindings/mmc/mmc.txt and the properties
 used by the sdhci-st driver.
 
 Required properties:
-- compatible :  Must be "st,sdhci"
-- clock-names : Should be "mmc"
-                See: Documentation/devicetree/bindings/resource-names.txt
-- clocks :      Phandle of the clock used by the sdhci controler
-                See: Documentation/devicetree/bindings/clock/clock-bindings.txt
+- compatible:          Must be "st,sdhci" and it can be compatible to "st,sdhci-stih407"
+                       to set the internal glue logic used for configuring the MMC
+                       subsystem (mmcss) inside the FlashSS (available in STiH407 SoC
+                       family).
+
+- clock-names:         Should be "mmc".
+                       See: Documentation/devicetree/bindings/resource-names.txt
+- clocks:              Phandle to the clock.
+                       See: Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+- interrupts:          One mmc interrupt should be described here.
+- interrupt-names:     Should be "mmcirq".
+
+- pinctrl-names:       A pinctrl state names "default" must be defined.
+- pinctrl-0:           Phandle referencing pin configuration of the sd/emmc controller.
+                       See: Documentation/devicetree/bindings/pinctrl/pinctrl-binding.txt
+
+- reg:                 This must provide the host controller base address and it can also
+                       contain the FlashSS Top register for TX/RX delay used by the driver
+                       to configure DLL inside the flashSS, if so reg-names must also be
+                       specified.
 
 Optional properties:
-- non-removable: non-removable slot
-                 See: Documentation/devicetree/bindings/mmc/mmc.txt
-- bus-width: Number of data lines
-                 See: Documentation/devicetree/bindings/mmc/mmc.txt
+- reg-names:           Should be "mmc" and "top-mmc-delay". "top-mmc-delay" is optional
+                       for eMMC on stih407 family silicon to configure DLL inside FlashSS.
+
+- non-removable:       Non-removable slot. Also used for configuring mmcss in STiH407 SoC
+                       family.
+                       See:  Documentation/devicetree/bindings/mmc/mmc.txt.
+
+- bus-width:           Number of data lines.
+                       See:  Documentation/devicetree/bindings/mmc/mmc.txt.
+
+- max-frequency:       Can be 200MHz, 100Mz or 50MHz (default) and used for
+                       configuring the CCONFIG3 in the mmcss.
+                       See:  Documentation/devicetree/bindings/mmc/mmc.txt.
+
+- resets:              Phandle and reset specifier pair to softreset line of HC IP.
+                       See: Documentation/devicetree/bindings/reset/reset.txt
+
+- vqmmc-supply:                Phandle to the regulator dt node, mentioned as the vcc/vdd
+                       supply in eMMC/SD specs.
+
+- sd-uhs--sdr50:       To enable the SDR50 in the mmcss.
+                       See:  Documentation/devicetree/bindings/mmc/mmc.txt.
+
+- sd-uhs-sdr104:       To enable the SDR104 in the mmcss.
+                       See:  Documentation/devicetree/bindings/mmc/mmc.txt.
+
+- sd-uhs-ddr50:                To enable the DDR50 in the mmcss.
+                       See:  Documentation/devicetree/bindings/mmc/mmc.txt.
 
 Example:
 
+/* Example stih416e eMMC configuration */
+
 mmc0: sdhci@fe81e000 {
        compatible      = "st,sdhci";
        status          = "disabled";
@@ -29,5 +71,43 @@ mmc0: sdhci@fe81e000 {
        pinctrl-0       = <&pinctrl_mmc0>;
        clock-names     = "mmc";
        clocks          = <&clk_s_a1_ls 1>;
-       bus-width       = <8>
+       bus-width       = <8>
+
+/* Example SD stih407 family configuration */
+
+mmc1: sdhci@09080000 {
+       compatible      = "st,sdhci-stih407", "st,sdhci";
+       status          = "disabled";
+       reg             = <0x09080000 0x7ff>;
+       reg-names       = "mmc";
+       interrupts      = <GIC_SPI 90 IRQ_TYPE_NONE>;
+       interrupt-names = "mmcirq";
+       pinctrl-names   = "default";
+       pinctrl-0       = <&pinctrl_sd1>;
+       clock-names     = "mmc";
+       clocks          = <&clk_s_c0_flexgen CLK_MMC_1>;
+       resets          = <&softreset STIH407_MMC1_SOFTRESET>;
+       bus-width       = <4>;
+};
+
+/* Example eMMC stih407 family configuration */
+
+mmc0: sdhci@09060000 {
+       compatible      = "st,sdhci-stih407", "st,sdhci";
+       status          = "disabled";
+       reg             = <0x09060000 0x7ff>, <0x9061008 0x20>;
+       reg-names       = "mmc", "top-mmc-delay";
+       interrupts      = <GIC_SPI 92 IRQ_TYPE_NONE>;
+       interrupt-names = "mmcirq";
+       pinctrl-names   = "default";
+       pinctrl-0       = <&pinctrl_mmc0>;
+       clock-names     = "mmc";
+       clocks          = <&clk_s_c0_flexgen CLK_MMC_0>;
+       vqmmc-supply    = <&vmmc_reg>;
+       max-frequency   = <200000000>;
+       bus-width       = <8>;
+       non-removable;
+       sd-uhs-sdr50;
+       sd-uhs-sdr104;
+       sd-uhs-ddr50;
 };
index b84686826b23cca2bb9699d6fae5d9b8cae35afa..8d2ee8e010a18218a970207b555b4eb6ba6196ac 100644 (file)
@@ -6566,10 +6566,8 @@ F:       drivers/mfd/
 F:     include/linux/mfd/
 
 MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
-M:     Chris Ball <chris@printf.net>
 M:     Ulf Hansson <ulf.hansson@linaro.org>
 L:     linux-mmc@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git
 T:     git git://git.linaro.org/people/ulf.hansson/mmc.git
 S:     Maintained
 F:     drivers/mmc/
@@ -8670,10 +8668,8 @@ S:       Maintained
 F:     drivers/mmc/host/sdricoh_cs.c
 
 SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER
-M:     Chris Ball <chris@printf.net>
 L:     linux-mmc@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git
-S:     Maintained
+S:     Orphan
 F:     drivers/mmc/host/sdhci.*
 F:     drivers/mmc/host/sdhci-pltfm.[ch]
 
@@ -8689,18 +8685,12 @@ F:      include/linux/seccomp.h
 K:     \bsecure_computing
 K:     \bTIF_SECCOMP\b
 
-SECURE DIGITAL HOST CONTROLLER INTERFACE, OPEN FIRMWARE BINDINGS (SDHCI-OF)
-M:     Anton Vorontsov <anton@enomsg.org>
-L:     linuxppc-dev@lists.ozlabs.org
-L:     linux-mmc@vger.kernel.org
-S:     Maintained
-F:     drivers/mmc/host/sdhci-pltfm.[ch]
-
 SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) SAMSUNG DRIVER
 M:     Ben Dooks <ben-linux@fluff.org>
+M:     Jaehoon Chung <jh80.chung@samsung.com>
 L:     linux-mmc@vger.kernel.org
 S:     Maintained
-F:     drivers/mmc/host/sdhci-s3c.c
+F:     drivers/mmc/host/sdhci-s3c*
 
 SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) ST SPEAR DRIVER
 M:     Viresh Kumar <viresh.linux@gmail.com>
index dc6e79c4484abbfb097abb322298c37a8b9dd5ca..9a8611ab5dfa60d3bf5e23d6118779db3495ee80 100644 (file)
@@ -150,9 +150,13 @@ static int nop_mmc_set_power(struct device *dev, int power_on, int vdd)
 static inline void omap_hsmmc_mux(struct omap_hsmmc_platform_data
                                  *mmc_controller, int controller_nr)
 {
-       if (gpio_is_valid(mmc_controller->switch_pin) &&
-           (mmc_controller->switch_pin < OMAP_MAX_GPIO_LINES))
-               omap_mux_init_gpio(mmc_controller->switch_pin,
+       if (gpio_is_valid(mmc_controller->gpio_cd) &&
+           (mmc_controller->gpio_cd < OMAP_MAX_GPIO_LINES))
+               omap_mux_init_gpio(mmc_controller->gpio_cd,
+                                  OMAP_PIN_INPUT_PULLUP);
+       if (gpio_is_valid(mmc_controller->gpio_cod) &&
+           (mmc_controller->gpio_cod < OMAP_MAX_GPIO_LINES))
+               omap_mux_init_gpio(mmc_controller->gpio_cod,
                                   OMAP_PIN_INPUT_PULLUP);
        if (gpio_is_valid(mmc_controller->gpio_wp) &&
            (mmc_controller->gpio_wp < OMAP_MAX_GPIO_LINES))
@@ -250,15 +254,20 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
        mmc->internal_clock = !c->ext_clock;
        mmc->reg_offset = 0;
 
-       mmc->switch_pin = c->gpio_cd;
+       if (c->cover_only) {
+               /* detect if mobile phone cover removed */
+               mmc->gpio_cd = -EINVAL;
+               mmc->gpio_cod = c->gpio_cd;
+       } else {
+               /* card detect pin on the mmc socket itself */
+               mmc->gpio_cd = c->gpio_cd;
+               mmc->gpio_cod = -EINVAL;
+       }
        mmc->gpio_wp = c->gpio_wp;
 
        mmc->remux = c->remux;
        mmc->init_card = c->init_card;
 
-       if (c->cover_only)
-               mmc->cover = 1;
-
        if (c->nonremovable)
                mmc->nonremovable = 1;
 
@@ -358,7 +367,15 @@ void omap_hsmmc_late_init(struct omap2_hsmmc_info *c)
                if (!mmc_pdata)
                        continue;
 
-               mmc_pdata->switch_pin = c->gpio_cd;
+               if (c->cover_only) {
+                       /* detect if mobile phone cover removed */
+                       mmc_pdata->gpio_cd = -EINVAL;
+                       mmc_pdata->gpio_cod = c->gpio_cd;
+               } else {
+                       /* card detect pin on the mmc socket itself */
+                       mmc_pdata->gpio_cd = c->gpio_cd;
+                       mmc_pdata->gpio_cod = -EINVAL;
+               }
                mmc_pdata->gpio_wp = c->gpio_wp;
 
                res = omap_device_register(pdev);
index 23f10f72e5f391d1c32b63b8a2e33dd2a7eb777e..c296bc098fe23684f4be66195b2342d7cd0159ef 100644 (file)
@@ -897,6 +897,7 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
        DECLARE_WAITQUEUE(wait, current);
        unsigned long flags;
        int stop;
+       bool pm = false;
 
        might_sleep();
 
@@ -916,15 +917,18 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
                host->claimed = 1;
                host->claimer = current;
                host->claim_cnt += 1;
+               if (host->claim_cnt == 1)
+                       pm = true;
        } else
                wake_up(&host->wq);
        spin_unlock_irqrestore(&host->lock, flags);
        remove_wait_queue(&host->wq, &wait);
-       if (host->ops->enable && !stop && host->claim_cnt == 1)
-               host->ops->enable(host);
+
+       if (pm)
+               pm_runtime_get_sync(mmc_dev(host));
+
        return stop;
 }
-
 EXPORT_SYMBOL(__mmc_claim_host);
 
 /**
@@ -940,9 +944,6 @@ void mmc_release_host(struct mmc_host *host)
 
        WARN_ON(!host->claimed);
 
-       if (host->ops->disable && host->claim_cnt == 1)
-               host->ops->disable(host);
-
        spin_lock_irqsave(&host->lock, flags);
        if (--host->claim_cnt) {
                /* Release for nested claim */
@@ -952,6 +953,8 @@ void mmc_release_host(struct mmc_host *host)
                host->claimer = NULL;
                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));
        }
 }
 EXPORT_SYMBOL(mmc_release_host);
index 1d41e8541f388d7a2f74f04e469b72841609f03b..c84131e2862565136d62c32ccd3f6cb87b472111 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/err.h>
+#include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/stat.h>
 #include <linux/pm_runtime.h>
@@ -336,6 +337,8 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
 {
        int err = 0, idx;
        unsigned int part_size;
+       struct device_node *np;
+       bool broken_hpi = false;
 
        /* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */
        card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE];
@@ -349,6 +352,11 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
                }
        }
 
+       np = mmc_of_find_child_device(card->host, 0);
+       if (np && of_device_is_compatible(np, "mmc-card"))
+               broken_hpi = of_property_read_bool(np, "broken-hpi");
+       of_node_put(np);
+
        /*
         * The EXT_CSD format is meant to be forward compatible. As long
         * as CSD_STRUCTURE does not change, all values for EXT_CSD_REV
@@ -494,7 +502,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
                }
 
                /* check whether the eMMC card supports HPI */
-               if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
+               if (!broken_hpi && (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1)) {
                        card->ext_csd.hpi = 1;
                        if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
                                card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION;
index 862356123d78c7def0c4f7530c86b223ff1adf32..ab21297811610089bc79f11c413be479a0114fe0 100644 (file)
@@ -19,7 +19,7 @@
 
 struct mmc_pwrseq_match {
        const char *compatible;
-       int (*alloc)(struct mmc_host *host, struct device *dev);
+       struct mmc_pwrseq *(*alloc)(struct mmc_host *host, struct device *dev);
 };
 
 static struct mmc_pwrseq_match pwrseq_match[] = {
@@ -52,6 +52,7 @@ int mmc_pwrseq_alloc(struct mmc_host *host)
        struct platform_device *pdev;
        struct device_node *np;
        struct mmc_pwrseq_match *match;
+       struct mmc_pwrseq *pwrseq;
        int ret = 0;
 
        np = of_parse_phandle(host->parent->of_node, "mmc-pwrseq", 0);
@@ -70,9 +71,14 @@ int mmc_pwrseq_alloc(struct mmc_host *host)
                goto err;
        }
 
-       ret = match->alloc(host, &pdev->dev);
-       if (!ret)
-               dev_info(host->parent, "allocated mmc-pwrseq\n");
+       pwrseq = match->alloc(host, &pdev->dev);
+       if (IS_ERR(pwrseq)) {
+               ret = PTR_ERR(host->pwrseq);
+               goto err;
+       }
+
+       host->pwrseq = pwrseq;
+       dev_info(host->parent, "allocated mmc-pwrseq\n");
 
 err:
        of_node_put(np);
@@ -109,4 +115,6 @@ void mmc_pwrseq_free(struct mmc_host *host)
 
        if (pwrseq && pwrseq->ops && pwrseq->ops->free)
                pwrseq->ops->free(host);
+
+       host->pwrseq = NULL;
 }
index aba3409e8d6e81debf567cffae1bb0ca0b65872c..096da48c6a7ecbb0ba294e6fd1bf9513b02bca36 100644 (file)
@@ -27,8 +27,10 @@ void mmc_pwrseq_post_power_on(struct mmc_host *host);
 void mmc_pwrseq_power_off(struct mmc_host *host);
 void mmc_pwrseq_free(struct mmc_host *host);
 
-int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev);
-int mmc_pwrseq_emmc_alloc(struct mmc_host *host, struct device *dev);
+struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host,
+                                          struct device *dev);
+struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host,
+                                        struct device *dev);
 
 #else
 
index a2d545904fbf6977a4f186a1a0c99503c945157b..9d6d2fb217967d069ff2f18db0b403dff05483e0 100644 (file)
@@ -49,7 +49,6 @@ static void mmc_pwrseq_emmc_free(struct mmc_host *host)
        unregister_restart_handler(&pwrseq->reset_nb);
        gpiod_put(pwrseq->reset_gpio);
        kfree(pwrseq);
-       host->pwrseq = NULL;
 }
 
 static struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = {
@@ -67,14 +66,15 @@ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,
        return NOTIFY_DONE;
 }
 
-int mmc_pwrseq_emmc_alloc(struct mmc_host *host, struct device *dev)
+struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host,
+                                        struct device *dev)
 {
        struct mmc_pwrseq_emmc *pwrseq;
        int ret = 0;
 
        pwrseq = kzalloc(sizeof(struct mmc_pwrseq_emmc), GFP_KERNEL);
        if (!pwrseq)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
        pwrseq->reset_gpio = gpiod_get_index(dev, "reset", 0, GPIOD_OUT_LOW);
        if (IS_ERR(pwrseq->reset_gpio)) {
@@ -92,10 +92,9 @@ int mmc_pwrseq_emmc_alloc(struct mmc_host *host, struct device *dev)
        register_restart_handler(&pwrseq->reset_nb);
 
        pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops;
-       host->pwrseq = &pwrseq->pwrseq;
 
-       return 0;
+       return &pwrseq->pwrseq;
 free:
        kfree(pwrseq);
-       return ret;
+       return ERR_PTR(ret);
 }
index c53f14a7ce546533c300313a54078e1bad327bf9..0b14b83a53d6c9614a2ac897893f5cc1690a5b6e 100644 (file)
@@ -85,7 +85,6 @@ static void mmc_pwrseq_simple_free(struct mmc_host *host)
                clk_put(pwrseq->ext_clk);
 
        kfree(pwrseq);
-       host->pwrseq = NULL;
 }
 
 static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
@@ -95,7 +94,8 @@ static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
        .free = mmc_pwrseq_simple_free,
 };
 
-int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev)
+struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host,
+                                          struct device *dev)
 {
        struct mmc_pwrseq_simple *pwrseq;
        int i, nr_gpios, ret = 0;
@@ -107,7 +107,7 @@ int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev)
        pwrseq = kzalloc(sizeof(struct mmc_pwrseq_simple) + nr_gpios *
                         sizeof(struct gpio_desc *), GFP_KERNEL);
        if (!pwrseq)
-               return -ENOMEM;
+               return ERR_PTR(-ENOMEM);
 
        pwrseq->ext_clk = clk_get(dev, "ext_clock");
        if (IS_ERR(pwrseq->ext_clk) &&
@@ -133,13 +133,12 @@ int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev)
 
        pwrseq->nr_gpios = nr_gpios;
        pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops;
-       host->pwrseq = &pwrseq->pwrseq;
 
-       return 0;
+       return &pwrseq->pwrseq;
 clk_put:
        if (!IS_ERR(pwrseq->ext_clk))
                clk_put(pwrseq->ext_clk);
 free:
        kfree(pwrseq);
-       return ret;
+       return ERR_PTR(ret);
 }
index ce6cc47206b0f3d6d91b4b69f35a66720cf14c47..5bc6c7dbbd6088153b6ee2bda65730caccea0a8a 100644 (file)
@@ -293,19 +293,22 @@ static int sdio_enable_4bit_bus(struct mmc_card *card)
        int err;
 
        if (card->type == MMC_TYPE_SDIO)
-               return sdio_enable_wide(card);
-
-       if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
-               (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+               err = sdio_enable_wide(card);
+       else if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
+                (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
                err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
                if (err)
                        return err;
+               err = sdio_enable_wide(card);
+               if (err <= 0)
+                       mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1);
        } else
                return 0;
 
-       err = sdio_enable_wide(card);
-       if (err <= 0)
-               mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1);
+       if (err > 0) {
+               mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
+               err = 0;
+       }
 
        return err;
 }
@@ -547,13 +550,8 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card)
        /*
         * Switch to wider bus (if supported).
         */
-       if (card->host->caps & MMC_CAP_4_BIT_DATA) {
+       if (card->host->caps & MMC_CAP_4_BIT_DATA)
                err = sdio_enable_4bit_bus(card);
-               if (err > 0) {
-                       mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
-                       err = 0;
-               }
-       }
 
        /* Set the driver strength for the card */
        sdio_select_driver_type(card);
@@ -803,9 +801,7 @@ try_again:
                 * Switch to wider bus (if supported).
                 */
                err = sdio_enable_4bit_bus(card);
-               if (err > 0)
-                       mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
-               else if (err)
+               if (err)
                        goto remove;
        }
 finish:
@@ -983,10 +979,6 @@ static int mmc_sdio_resume(struct mmc_host *host)
        } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
                /* We may have switched to 1-bit mode during suspend */
                err = sdio_enable_4bit_bus(host->card);
-               if (err > 0) {
-                       mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
-                       err = 0;
-               }
        }
 
        if (!err && host->sdio_irqs) {
index 61ac63a3776a789e2b98903118ab3198a00b9ffd..7f4db908f89b1a03e2f572b91e2331fa2fc44563 100644 (file)
@@ -132,7 +132,7 @@ config MMC_SDHCI_OF_ARASAN
 config MMC_SDHCI_OF_ESDHC
        tristate "SDHCI OF support for the Freescale eSDHC controller"
        depends on MMC_SDHCI_PLTFM
-       depends on PPC_OF
+       depends on PPC
        select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
        help
          This selects the Freescale eSDHC controller support.
@@ -144,7 +144,7 @@ config MMC_SDHCI_OF_ESDHC
 config MMC_SDHCI_OF_HLWD
        tristate "SDHCI OF support for the Nintendo Wii SDHCI controllers"
        depends on MMC_SDHCI_PLTFM
-       depends on PPC_OF
+       depends on PPC
        select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
        help
          This selects the Secure Digital Host Controller Interface (SDHCI)
@@ -230,7 +230,7 @@ config MMC_SDHCI_PXAV3
        tristate "Marvell MMP2 SD Host Controller support (PXAV3)"
        depends on CLKDEV_LOOKUP
        depends on MMC_SDHCI_PLTFM
-       depends on ARCH_MMP || COMPILE_TEST
+       depends on ARCH_BERLIN || ARCH_MMP || ARCH_MVEBU || COMPILE_TEST
        default CPU_MMP2
        help
          This selects the Marvell(R) PXAV3 SD Host Controller.
@@ -255,6 +255,7 @@ config MMC_SDHCI_PXAV2
 config MMC_SDHCI_SPEAR
        tristate "SDHCI support on ST SPEAr platform"
        depends on MMC_SDHCI && PLAT_SPEAR
+       depends on OF
        help
          This selects the Secure Digital Host Controller Interface (SDHCI)
          often referrered to as the HSMMC block in some of the ST SPEAR range
@@ -307,6 +308,20 @@ config MMC_SDHCI_F_SDH30
 
          If unsure, say N.
 
+config MMC_SDHCI_IPROC
+       tristate "SDHCI platform support for the iProc SD/MMC Controller"
+       depends on ARCH_BCM_IPROC || COMPILE_TEST
+       depends on MMC_SDHCI_PLTFM
+       default ARCH_BCM_IPROC
+       select MMC_SDHCI_IO_ACCESSORS
+       help
+         This selects the iProc SD/MMC controller.
+
+         If you have an IPROC platform with SD or MMC devices,
+         say Y or M here.
+
+         If unsure, say N.
+
 config MMC_MOXART
        tristate "MOXART SD/MMC Host Controller support"
        depends on ARCH_MOXART && MMC
index 6a7cfe0de332689fdb8a8631e1327057b54b0e4f..711e913450f5be77d3aa0690931d827697f706c1 100644 (file)
@@ -71,6 +71,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_ESDHC)      += sdhci-of-esdhc.o
 obj-$(CONFIG_MMC_SDHCI_OF_HLWD)                += sdhci-of-hlwd.o
 obj-$(CONFIG_MMC_SDHCI_BCM_KONA)       += sdhci-bcm-kona.o
 obj-$(CONFIG_MMC_SDHCI_BCM2835)                += sdhci-bcm2835.o
+obj-$(CONFIG_MMC_SDHCI_IPROC)          += sdhci-iproc.o
 obj-$(CONFIG_MMC_SDHCI_MSM)            += sdhci-msm.o
 obj-$(CONFIG_MMC_SDHCI_ST)             += sdhci-st.o
 
index c97001e15227aba5b337c5cb07da0a799969d6dd..0aa44e679df4965350abc9e7cce4f0d8e42da2ec 100644 (file)
 #define ATMCI_REGS_SIZE                0x100
 
 /* Register access macros */
-#define atmci_readl(port,reg)                          \
+#ifdef CONFIG_AVR32
+#define atmci_readl(port, reg)                 \
        __raw_readl((port)->regs + reg)
-#define atmci_writel(port,reg,value)                   \
+#define atmci_writel(port, reg, value)                 \
        __raw_writel((value), (port)->regs + reg)
+#else
+#define atmci_readl(port, reg)                 \
+       readl_relaxed((port)->regs + reg)
+#define atmci_writel(port, reg, value)                 \
+       writel_relaxed((value), (port)->regs + reg)
+#endif
 
 /* On AVR chips the Peripheral DMA Controller is not connected to MCI. */
 #ifdef CONFIG_AVR32
index fe32948c6114dbf9dd72820f958d3337872d4ec0..e761eb1b1441339e33a84822ff863b20165e97cf 100644 (file)
@@ -40,7 +40,12 @@ struct dw_mci_exynos_priv_data {
        u8                              ciu_div;
        u32                             sdr_timing;
        u32                             ddr_timing;
+       u32                             hs400_timing;
+       u32                             tuned_sample;
        u32                             cur_speed;
+       u32                             dqs_delay;
+       u32                             saved_dqs_en;
+       u32                             saved_strobe_ctrl;
 };
 
 static struct dw_mci_exynos_compatible {
@@ -71,6 +76,21 @@ static struct dw_mci_exynos_compatible {
        },
 };
 
+static inline u8 dw_mci_exynos_get_ciu_div(struct dw_mci *host)
+{
+       struct dw_mci_exynos_priv_data *priv = host->priv;
+
+       if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
+               return EXYNOS4412_FIXED_CIU_CLK_DIV;
+       else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
+               return EXYNOS4210_FIXED_CIU_CLK_DIV;
+       else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+                       priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+               return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL64)) + 1;
+       else
+               return SDMMC_CLKSEL_GET_DIV(mci_readl(host, CLKSEL)) + 1;
+}
+
 static int dw_mci_exynos_priv_init(struct dw_mci *host)
 {
        struct dw_mci_exynos_priv_data *priv = host->priv;
@@ -85,6 +105,16 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
                           SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
        }
 
+       if (priv->ctrl_type >= DW_MCI_TYPE_EXYNOS5420) {
+               priv->saved_strobe_ctrl = mci_readl(host, HS400_DLINE_CTRL);
+               priv->saved_dqs_en = mci_readl(host, HS400_DQS_EN);
+               priv->saved_dqs_en |= AXI_NON_BLOCKING_WR;
+               mci_writel(host, HS400_DQS_EN, priv->saved_dqs_en);
+               if (!priv->dqs_delay)
+                       priv->dqs_delay =
+                               DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl);
+       }
+
        return 0;
 }
 
@@ -97,6 +127,26 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
        return 0;
 }
 
+static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
+{
+       struct dw_mci_exynos_priv_data *priv = host->priv;
+       u32 clksel;
+
+       if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+               priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+               clksel = mci_readl(host, CLKSEL64);
+       else
+               clksel = mci_readl(host, CLKSEL);
+
+       clksel = (clksel & ~SDMMC_CLKSEL_TIMING_MASK) | timing;
+
+       if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+               priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+               mci_writel(host, CLKSEL64, clksel);
+       else
+               mci_writel(host, CLKSEL, clksel);
+}
+
 #ifdef CONFIG_PM_SLEEP
 static int dw_mci_exynos_suspend(struct device *dev)
 {
@@ -172,30 +222,38 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
        }
 }
 
-static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+static void dw_mci_exynos_config_hs400(struct dw_mci *host, u32 timing)
 {
        struct dw_mci_exynos_priv_data *priv = host->priv;
-       unsigned int wanted = ios->clock;
-       unsigned long actual;
-       u8 div = priv->ciu_div + 1;
+       u32 dqs, strobe;
 
-       if (ios->timing == MMC_TIMING_MMC_DDR52) {
-               if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
-                       priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
-                       mci_writel(host, CLKSEL64, priv->ddr_timing);
-               else
-                       mci_writel(host, CLKSEL, priv->ddr_timing);
-               /* Should be double rate for DDR mode */
-               if (ios->bus_width == MMC_BUS_WIDTH_8)
-                       wanted <<= 1;
+       /*
+        * Not supported to configure register
+        * related to HS400
+        */
+       if (priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420)
+               return;
+
+       dqs = priv->saved_dqs_en;
+       strobe = priv->saved_strobe_ctrl;
+
+       if (timing == MMC_TIMING_MMC_HS400) {
+               dqs |= DATA_STROBE_EN;
+               strobe = DQS_CTRL_RD_DELAY(strobe, priv->dqs_delay);
        } else {
-               if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
-                       priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
-                       mci_writel(host, CLKSEL64, priv->sdr_timing);
-               else
-                       mci_writel(host, CLKSEL, priv->sdr_timing);
+               dqs &= ~DATA_STROBE_EN;
        }
 
+       mci_writel(host, HS400_DQS_EN, dqs);
+       mci_writel(host, HS400_DLINE_CTRL, strobe);
+}
+
+static void dw_mci_exynos_adjust_clock(struct dw_mci *host, unsigned int wanted)
+{
+       struct dw_mci_exynos_priv_data *priv = host->priv;
+       unsigned long actual;
+       u8 div;
+       int ret;
        /*
         * Don't care if wanted clock is zero or
         * ciu clock is unavailable
@@ -207,17 +265,52 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
        if (wanted < EXYNOS_CCLKIN_MIN)
                wanted = EXYNOS_CCLKIN_MIN;
 
-       if (wanted != priv->cur_speed) {
-               int ret = clk_set_rate(host->ciu_clk, wanted * div);
-               if (ret)
-                       dev_warn(host->dev,
-                               "failed to set clk-rate %u error: %d\n",
-                                wanted * div, ret);
-               actual = clk_get_rate(host->ciu_clk);
-               host->bus_hz = actual / div;
-               priv->cur_speed = wanted;
-               host->current_speed = 0;
+       if (wanted == priv->cur_speed)
+               return;
+
+       div = dw_mci_exynos_get_ciu_div(host);
+       ret = clk_set_rate(host->ciu_clk, wanted * div);
+       if (ret)
+               dev_warn(host->dev,
+                       "failed to set clk-rate %u error: %d\n",
+                       wanted * div, ret);
+       actual = clk_get_rate(host->ciu_clk);
+       host->bus_hz = actual / div;
+       priv->cur_speed = wanted;
+       host->current_speed = 0;
+}
+
+static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
+{
+       struct dw_mci_exynos_priv_data *priv = host->priv;
+       unsigned int wanted = ios->clock;
+       u32 timing = ios->timing, clksel;
+
+       switch (timing) {
+       case MMC_TIMING_MMC_HS400:
+               /* Update tuned sample timing */
+               clksel = SDMMC_CLKSEL_UP_SAMPLE(
+                               priv->hs400_timing, priv->tuned_sample);
+               wanted <<= 1;
+               break;
+       case MMC_TIMING_MMC_DDR52:
+               clksel = priv->ddr_timing;
+               /* Should be double rate for DDR mode */
+               if (ios->bus_width == MMC_BUS_WIDTH_8)
+                       wanted <<= 1;
+               break;
+       default:
+               clksel = priv->sdr_timing;
        }
+
+       /* Set clock timing for the requested speed mode*/
+       dw_mci_exynos_set_clksel_timing(host, clksel);
+
+       /* Configure setting for HS400 */
+       dw_mci_exynos_config_hs400(host, timing);
+
+       /* Configure clock rate */
+       dw_mci_exynos_adjust_clock(host, wanted);
 }
 
 static int dw_mci_exynos_parse_dt(struct dw_mci *host)
@@ -260,6 +353,16 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
                return ret;
 
        priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
+
+       ret = of_property_read_u32_array(np,
+                       "samsung,dw-mshc-hs400-timing", timing, 2);
+       if (!ret && of_property_read_u32(np,
+                               "samsung,read-strobe-delay", &priv->dqs_delay))
+               dev_dbg(host->dev,
+                       "read-strobe-delay is not found, assuming usage of default value\n");
+
+       priv->hs400_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1],
+                                               HS400_FIXED_CIU_CLK_DIV);
        host->priv = priv;
        return 0;
 }
@@ -285,7 +388,7 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
                clksel = mci_readl(host, CLKSEL64);
        else
                clksel = mci_readl(host, CLKSEL);
-       clksel = (clksel & ~0x7) | SDMMC_CLKSEL_CCLK_SAMPLE(sample);
+       clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
        if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
                priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
                mci_writel(host, CLKSEL64, clksel);
@@ -304,13 +407,16 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
                clksel = mci_readl(host, CLKSEL64);
        else
                clksel = mci_readl(host, CLKSEL);
+
        sample = (clksel + 1) & 0x7;
-       clksel = (clksel & ~0x7) | sample;
+       clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
+
        if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
                priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
                mci_writel(host, CLKSEL64, clksel);
        else
                mci_writel(host, CLKSEL, clksel);
+
        return sample;
 }
 
@@ -343,6 +449,7 @@ out:
 static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
 {
        struct dw_mci *host = slot->host;
+       struct dw_mci_exynos_priv_data *priv = host->priv;
        struct mmc_host *mmc = slot->mmc;
        u8 start_smpl, smpl, candiates = 0;
        s8 found = -1;
@@ -360,14 +467,27 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
        } while (start_smpl != smpl);
 
        found = dw_mci_exynos_get_best_clksmpl(candiates);
-       if (found >= 0)
+       if (found >= 0) {
                dw_mci_exynos_set_clksmpl(host, found);
-       else
+               priv->tuned_sample = found;
+       } else {
                ret = -EIO;
+       }
 
        return ret;
 }
 
+static int dw_mci_exynos_prepare_hs400_tuning(struct dw_mci *host,
+                                       struct mmc_ios *ios)
+{
+       struct dw_mci_exynos_priv_data *priv = host->priv;
+
+       dw_mci_exynos_set_clksel_timing(host, priv->hs400_timing);
+       dw_mci_exynos_adjust_clock(host, (ios->clock) << 1);
+
+       return 0;
+}
+
 /* Common capabilities of Exynos4/Exynos5 SoC */
 static unsigned long exynos_dwmmc_caps[4] = {
        MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
@@ -384,6 +504,7 @@ static const struct dw_mci_drv_data exynos_drv_data = {
        .set_ios                = dw_mci_exynos_set_ios,
        .parse_dt               = dw_mci_exynos_parse_dt,
        .execute_tuning         = dw_mci_exynos_execute_tuning,
+       .prepare_hs400_tuning   = dw_mci_exynos_prepare_hs400_tuning,
 };
 
 static const struct of_device_id dw_mci_exynos_match[] = {
index 7872ce586b558e07461c748f600f6ef6777bb12b..595c934e6166cf1b9aef2c18a8a28ec3c3062163 100644 (file)
 #ifndef _DW_MMC_EXYNOS_H_
 #define _DW_MMC_EXYNOS_H_
 
-/* Extended Register's Offset */
 #define SDMMC_CLKSEL                   0x09C
 #define SDMMC_CLKSEL64                 0x0A8
 
+/* Extended Register's Offset */
+#define SDMMC_HS400_DQS_EN             0x180
+#define SDMMC_HS400_ASYNC_FIFO_CTRL    0x184
+#define SDMMC_HS400_DLINE_CTRL         0x188
+
 /* CLKSEL register defines */
 #define SDMMC_CLKSEL_CCLK_SAMPLE(x)    (((x) & 7) << 0)
 #define SDMMC_CLKSEL_CCLK_DRIVE(x)     (((x) & 7) << 16)
 #define SDMMC_CLKSEL_CCLK_DIVIDER(x)   (((x) & 7) << 24)
 #define SDMMC_CLKSEL_GET_DRV_WD3(x)    (((x) >> 16) & 0x7)
+#define SDMMC_CLKSEL_GET_DIV(x)                (((x) >> 24) & 0x7)
+#define SDMMC_CLKSEL_UP_SAMPLE(x, y)   (((x) & ~SDMMC_CLKSEL_CCLK_SAMPLE(7)) |\
+                                        SDMMC_CLKSEL_CCLK_SAMPLE(y))
 #define SDMMC_CLKSEL_TIMING(x, y, z)   (SDMMC_CLKSEL_CCLK_SAMPLE(x) |  \
                                         SDMMC_CLKSEL_CCLK_DRIVE(y) |   \
                                         SDMMC_CLKSEL_CCLK_DIVIDER(z))
+#define SDMMC_CLKSEL_TIMING_MASK       SDMMC_CLKSEL_TIMING(0x7, 0x7, 0x7)
 #define SDMMC_CLKSEL_WAKEUP_INT                BIT(11)
 
+/* RCLK_EN register defines */
+#define DATA_STROBE_EN                 BIT(0)
+#define AXI_NON_BLOCKING_WR    BIT(7)
+
+/* DLINE_CTRL register defines */
+#define DQS_CTRL_RD_DELAY(x, y)                (((x) & ~0x3FF) | ((y) & 0x3FF))
+#define DQS_CTRL_GET_RD_DELAY(x)       ((x) & 0x3FF)
+
 /* Protector Register */
 #define SDMMC_EMMCP_BASE       0x1000
 #define SDMMC_MPSECURITY       (SDMMC_EMMCP_BASE + 0x0010)
@@ -49,6 +65,7 @@
 /* Fixed clock divider */
 #define EXYNOS4210_FIXED_CIU_CLK_DIV   2
 #define EXYNOS4412_FIXED_CIU_CLK_DIV   4
+#define HS400_FIXED_CIU_CLK_DIV                1
 
 /* Minimal required clock frequency for cclkin, unit: HZ */
 #define EXYNOS_CCLKIN_MIN      50000000
index e2a726a503ee147072bbd5afaf8692dab53ca87d..dbf166f94f1b6a1457238e29b435f83171509e26 100644 (file)
@@ -76,12 +76,20 @@ static int dw_mci_rockchip_init(struct dw_mci *host)
        return 0;
 }
 
+/* Common capabilities of RK3288 SoC */
+static unsigned long dw_mci_rk3288_dwmmc_caps[4] = {
+       MMC_CAP_RUNTIME_RESUME, /* emmc */
+       MMC_CAP_RUNTIME_RESUME, /* sdmmc */
+       MMC_CAP_RUNTIME_RESUME, /* sdio0 */
+       MMC_CAP_RUNTIME_RESUME, /* sdio1 */
+};
 static const struct dw_mci_drv_data rk2928_drv_data = {
        .prepare_command        = dw_mci_rockchip_prepare_command,
        .init                   = dw_mci_rockchip_init,
 };
 
 static const struct dw_mci_drv_data rk3288_drv_data = {
+       .caps                   = dw_mci_rk3288_dwmmc_caps,
        .prepare_command        = dw_mci_rockchip_prepare_command,
        .set_ios                = dw_mci_rk3288_set_ios,
        .setup_clock    = dw_mci_rk3288_setup_clock,
index 4d2e3c2e183057ddd13e29c1d1b8398a01dd7c5c..38b29265cc7c7625484db40b4d38f2148a2c1aa6 100644 (file)
@@ -69,7 +69,8 @@ struct idmac_desc_64addr {
 
        u32             des2;   /*Buffer sizes */
 #define IDMAC_64ADDR_SET_BUFFER1_SIZE(d, s) \
-       ((d)->des2 = ((d)->des2 & 0x03ffe000) | ((s) & 0x1fff))
+       ((d)->des2 = ((d)->des2 & cpu_to_le32(0x03ffe000)) | \
+        ((cpu_to_le32(s)) & cpu_to_le32(0x1fff)))
 
        u32             des3;   /* Reserved */
 
@@ -81,7 +82,7 @@ struct idmac_desc_64addr {
 };
 
 struct idmac_desc {
-       u32             des0;   /* Control Descriptor */
+       __le32          des0;   /* Control Descriptor */
 #define IDMAC_DES0_DIC BIT(1)
 #define IDMAC_DES0_LD  BIT(2)
 #define IDMAC_DES0_FD  BIT(3)
@@ -90,18 +91,19 @@ struct idmac_desc {
 #define IDMAC_DES0_CES BIT(30)
 #define IDMAC_DES0_OWN BIT(31)
 
-       u32             des1;   /* Buffer sizes */
+       __le32          des1;   /* Buffer sizes */
 #define IDMAC_SET_BUFFER1_SIZE(d, s) \
        ((d)->des1 = ((d)->des1 & 0x03ffe000) | ((s) & 0x1fff))
 
-       u32             des2;   /* buffer 1 physical address */
+       __le32          des2;   /* buffer 1 physical address */
 
-       u32             des3;   /* buffer 2 physical address */
+       __le32          des3;   /* buffer 2 physical address */
 };
 #endif /* CONFIG_MMC_DW_IDMAC */
 
 static bool dw_mci_reset(struct dw_mci *host);
 static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);
+static int dw_mci_card_busy(struct mmc_host *mmc);
 
 #if defined(CONFIG_DEBUG_FS)
 static int dw_mci_req_show(struct seq_file *s, void *v)
@@ -335,6 +337,31 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)
        return cmdr;
 }
 
+static void dw_mci_wait_while_busy(struct dw_mci *host, u32 cmd_flags)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(500);
+
+       /*
+        * Databook says that before issuing a new data transfer command
+        * we need to check to see if the card is busy.  Data transfer commands
+        * all have SDMMC_CMD_PRV_DAT_WAIT set, so we'll key off that.
+        *
+        * ...also allow sending for SDMMC_CMD_VOLT_SWITCH where busy is
+        * expected.
+        */
+       if ((cmd_flags & SDMMC_CMD_PRV_DAT_WAIT) &&
+           !(cmd_flags & SDMMC_CMD_VOLT_SWITCH)) {
+               while (mci_readl(host, STATUS) & SDMMC_STATUS_BUSY) {
+                       if (time_after(jiffies, timeout)) {
+                               /* Command will fail; we'll pass error then */
+                               dev_err(host->dev, "Busy; trying anyway\n");
+                               break;
+                       }
+                       udelay(10);
+               }
+       }
+}
+
 static void dw_mci_start_command(struct dw_mci *host,
                                 struct mmc_command *cmd, u32 cmd_flags)
 {
@@ -345,6 +372,7 @@ static void dw_mci_start_command(struct dw_mci *host,
 
        mci_writel(host, CMDARG, cmd->arg);
        wmb();
+       dw_mci_wait_while_busy(host, cmd_flags);
 
        mci_writel(host, CMD, cmd_flags | SDMMC_CMD_START);
 }
@@ -477,23 +505,23 @@ static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
                         * Set the OWN bit and disable interrupts for this
                         * descriptor
                         */
-                       desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC |
-                                               IDMAC_DES0_CH;
+                       desc->des0 = cpu_to_le32(IDMAC_DES0_OWN |
+                                       IDMAC_DES0_DIC | IDMAC_DES0_CH);
                        /* Buffer length */
                        IDMAC_SET_BUFFER1_SIZE(desc, length);
 
                        /* Physical address to DMA to/from */
-                       desc->des2 = mem_addr;
+                       desc->des2 = cpu_to_le32(mem_addr);
                }
 
                /* Set first descriptor */
                desc = host->sg_cpu;
-               desc->des0 |= IDMAC_DES0_FD;
+               desc->des0 |= cpu_to_le32(IDMAC_DES0_FD);
 
                /* Set last descriptor */
                desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
-               desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
-               desc->des0 |= IDMAC_DES0_LD;
+               desc->des0 &= cpu_to_le32(~(IDMAC_DES0_CH | IDMAC_DES0_DIC));
+               desc->des0 |= cpu_to_le32(IDMAC_DES0_LD);
        }
 
        wmb();
@@ -562,12 +590,12 @@ static int dw_mci_idmac_init(struct dw_mci *host)
 
                /* Forward link the descriptor list */
                for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
-                       p->des3 = host->sg_dma + (sizeof(struct idmac_desc) *
-                                                               (i + 1));
+                       p->des3 = cpu_to_le32(host->sg_dma +
+                                       (sizeof(struct idmac_desc) * (i + 1)));
 
                /* Set the last descriptor as the end-of-ring descriptor */
-               p->des3 = host->sg_dma;
-               p->des0 = IDMAC_DES0_ER;
+               p->des3 = cpu_to_le32(host->sg_dma);
+               p->des0 = cpu_to_le32(IDMAC_DES0_ER);
        }
 
        dw_mci_idmac_reset(host);
@@ -737,6 +765,7 @@ static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data)
                return;
 
        if (host->timing != MMC_TIMING_MMC_HS200 &&
+           host->timing != MMC_TIMING_MMC_HS400 &&
            host->timing != MMC_TIMING_UHS_SDR104)
                goto disable;
 
@@ -876,6 +905,7 @@ static void mci_send_cmd(struct dw_mci_slot *slot, u32 cmd, u32 arg)
 
        mci_writel(host, CMDARG, arg);
        wmb();
+       dw_mci_wait_while_busy(host, cmd);
        mci_writel(host, CMD, SDMMC_CMD_START | cmd);
 
        while (time_before(jiffies, timeout)) {
@@ -992,6 +1022,26 @@ static void __dw_mci_start_request(struct dw_mci *host,
 
        dw_mci_start_command(host, cmd, cmdflags);
 
+       if (cmd->opcode == SD_SWITCH_VOLTAGE) {
+               unsigned long irqflags;
+
+               /*
+                * Databook says to fail after 2ms w/ no response, but evidence
+                * shows that sometimes the cmd11 interrupt takes over 130ms.
+                * We'll set to 500ms, plus an extra jiffy just in case jiffies
+                * is just about to roll over.
+                *
+                * We do this whole thing under spinlock and only if the
+                * command hasn't already completed (indicating the the irq
+                * already ran so we don't want the timeout).
+                */
+               spin_lock_irqsave(&host->irq_lock, irqflags);
+               if (!test_bit(EVENT_CMD_COMPLETE, &host->pending_events))
+                       mod_timer(&host->cmd11_timer,
+                               jiffies + msecs_to_jiffies(500) + 1);
+               spin_unlock_irqrestore(&host->irq_lock, irqflags);
+       }
+
        if (mrq->stop)
                host->stop_cmdr = dw_mci_prepare_command(slot->mmc, mrq->stop);
        else
@@ -1084,7 +1134,8 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        regs = mci_readl(slot->host, UHS_REG);
 
        /* DDR mode set */
-       if (ios->timing == MMC_TIMING_MMC_DDR52)
+       if (ios->timing == MMC_TIMING_MMC_DDR52 ||
+           ios->timing == MMC_TIMING_MMC_HS400)
                regs |= ((0x1 << slot->id) << 16);
        else
                regs &= ~((0x1 << slot->id) << 16);
@@ -1101,12 +1152,6 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        if (drv_data && drv_data->set_ios)
                drv_data->set_ios(slot->host, ios);
 
-       /* Slot specific timing and width adjustment */
-       dw_mci_setup_bus(slot, false);
-
-       if (slot->host->state == STATE_WAITING_CMD11_DONE && ios->clock != 0)
-               slot->host->state = STATE_IDLE;
-
        switch (ios->power_mode) {
        case MMC_POWER_UP:
                if (!IS_ERR(mmc->supply.vmmc)) {
@@ -1125,23 +1170,39 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                mci_writel(slot->host, PWREN, regs);
                break;
        case MMC_POWER_ON:
-               if (!IS_ERR(mmc->supply.vqmmc) && !slot->host->vqmmc_enabled) {
-                       ret = regulator_enable(mmc->supply.vqmmc);
-                       if (ret < 0)
-                               dev_err(slot->host->dev,
-                                       "failed to enable vqmmc regulator\n");
-                       else
+               if (!slot->host->vqmmc_enabled) {
+                       if (!IS_ERR(mmc->supply.vqmmc)) {
+                               ret = regulator_enable(mmc->supply.vqmmc);
+                               if (ret < 0)
+                                       dev_err(slot->host->dev,
+                                               "failed to enable vqmmc\n");
+                               else
+                                       slot->host->vqmmc_enabled = true;
+
+                       } else {
+                               /* Keep track so we don't reset again */
                                slot->host->vqmmc_enabled = true;
+                       }
+
+                       /* Reset our state machine after powering on */
+                       dw_mci_ctrl_reset(slot->host,
+                                         SDMMC_CTRL_ALL_RESET_FLAGS);
                }
+
+               /* Adjust clock / bus width after power is up */
+               dw_mci_setup_bus(slot, false);
+
                break;
        case MMC_POWER_OFF:
+               /* Turn clock off before power goes down */
+               dw_mci_setup_bus(slot, false);
+
                if (!IS_ERR(mmc->supply.vmmc))
                        mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
 
-               if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled) {
+               if (!IS_ERR(mmc->supply.vqmmc) && slot->host->vqmmc_enabled)
                        regulator_disable(mmc->supply.vqmmc);
-                       slot->host->vqmmc_enabled = false;
-               }
+               slot->host->vqmmc_enabled = false;
 
                regs = mci_readl(slot->host, PWREN);
                regs &= ~(1 << slot->id);
@@ -1150,6 +1211,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        default:
                break;
        }
+
+       if (slot->host->state == STATE_WAITING_CMD11_DONE && ios->clock != 0)
+               slot->host->state = STATE_IDLE;
 }
 
 static int dw_mci_card_busy(struct mmc_host *mmc)
@@ -1323,6 +1387,18 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
        return err;
 }
 
+static int dw_mci_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct dw_mci_slot *slot = mmc_priv(mmc);
+       struct dw_mci *host = slot->host;
+       const struct dw_mci_drv_data *drv_data = host->drv_data;
+
+       if (drv_data && drv_data->prepare_hs400_tuning)
+               return drv_data->prepare_hs400_tuning(host, ios);
+
+       return 0;
+}
+
 static const struct mmc_host_ops dw_mci_ops = {
        .request                = dw_mci_request,
        .pre_req                = dw_mci_pre_req,
@@ -1335,6 +1411,7 @@ static const struct mmc_host_ops dw_mci_ops = {
        .card_busy              = dw_mci_card_busy,
        .start_signal_voltage_switch = dw_mci_switch_voltage,
        .init_card              = dw_mci_init_card,
+       .prepare_hs400_tuning   = dw_mci_prepare_hs400_tuning,
 };
 
 static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
@@ -1520,7 +1597,10 @@ static void dw_mci_tasklet_func(unsigned long priv)
                        if (test_and_clear_bit(EVENT_DATA_ERROR,
                                               &host->pending_events)) {
                                dw_mci_stop_dma(host);
-                               send_stop_abort(host, data);
+                               if (data->stop ||
+                                   !(host->data_status & (SDMMC_INT_DRTO |
+                                                          SDMMC_INT_EBE)))
+                                       send_stop_abort(host, data);
                                state = STATE_DATA_ERROR;
                                break;
                        }
@@ -1547,7 +1627,10 @@ static void dw_mci_tasklet_func(unsigned long priv)
                        if (test_and_clear_bit(EVENT_DATA_ERROR,
                                               &host->pending_events)) {
                                dw_mci_stop_dma(host);
-                               send_stop_abort(host, data);
+                               if (data->stop ||
+                                   !(host->data_status & (SDMMC_INT_DRTO |
+                                                          SDMMC_INT_EBE)))
+                                       send_stop_abort(host, data);
                                state = STATE_DATA_ERROR;
                                break;
                        }
@@ -1685,8 +1768,7 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
                buf += len;
                cnt -= len;
                if (host->part_buf_count == 2) {
-                       mci_writew(host, DATA(host->data_offset),
-                                       host->part_buf16);
+                       mci_fifo_writew(host->fifo_reg, host->part_buf16);
                        host->part_buf_count = 0;
                }
        }
@@ -1703,15 +1785,14 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
                        cnt -= len;
                        /* push data from aligned buffer into fifo */
                        for (i = 0; i < items; ++i)
-                               mci_writew(host, DATA(host->data_offset),
-                                               aligned_buf[i]);
+                               mci_fifo_writew(host->fifo_reg, aligned_buf[i]);
                }
        } else
 #endif
        {
                u16 *pdata = buf;
                for (; cnt >= 2; cnt -= 2)
-                       mci_writew(host, DATA(host->data_offset), *pdata++);
+                       mci_fifo_writew(host->fifo_reg, *pdata++);
                buf = pdata;
        }
        /* put anything remaining in the part_buf */
@@ -1720,8 +1801,7 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
                 /* Push data if we have reached the expected data length */
                if ((data->bytes_xfered + init_cnt) ==
                    (data->blksz * data->blocks))
-                       mci_writew(host, DATA(host->data_offset),
-                                  host->part_buf16);
+                       mci_fifo_writew(host->fifo_reg, host->part_buf16);
        }
 }
 
@@ -1736,8 +1816,7 @@ static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt)
                        int items = len >> 1;
                        int i;
                        for (i = 0; i < items; ++i)
-                               aligned_buf[i] = mci_readw(host,
-                                               DATA(host->data_offset));
+                               aligned_buf[i] = mci_fifo_readw(host->fifo_reg);
                        /* memcpy from aligned buffer into output buffer */
                        memcpy(buf, aligned_buf, len);
                        buf += len;
@@ -1748,11 +1827,11 @@ static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt)
        {
                u16 *pdata = buf;
                for (; cnt >= 2; cnt -= 2)
-                       *pdata++ = mci_readw(host, DATA(host->data_offset));
+                       *pdata++ = mci_fifo_readw(host->fifo_reg);
                buf = pdata;
        }
        if (cnt) {
-               host->part_buf16 = mci_readw(host, DATA(host->data_offset));
+               host->part_buf16 = mci_fifo_readw(host->fifo_reg);
                dw_mci_pull_final_bytes(host, buf, cnt);
        }
 }
@@ -1768,8 +1847,7 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
                buf += len;
                cnt -= len;
                if (host->part_buf_count == 4) {
-                       mci_writel(host, DATA(host->data_offset),
-                                       host->part_buf32);
+                       mci_fifo_writel(host->fifo_reg, host->part_buf32);
                        host->part_buf_count = 0;
                }
        }
@@ -1786,15 +1864,14 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
                        cnt -= len;
                        /* push data from aligned buffer into fifo */
                        for (i = 0; i < items; ++i)
-                               mci_writel(host, DATA(host->data_offset),
-                                               aligned_buf[i]);
+                               mci_fifo_writel(host->fifo_reg, aligned_buf[i]);
                }
        } else
 #endif
        {
                u32 *pdata = buf;
                for (; cnt >= 4; cnt -= 4)
-                       mci_writel(host, DATA(host->data_offset), *pdata++);
+                       mci_fifo_writel(host->fifo_reg, *pdata++);
                buf = pdata;
        }
        /* put anything remaining in the part_buf */
@@ -1803,8 +1880,7 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
                 /* Push data if we have reached the expected data length */
                if ((data->bytes_xfered + init_cnt) ==
                    (data->blksz * data->blocks))
-                       mci_writel(host, DATA(host->data_offset),
-                                  host->part_buf32);
+                       mci_fifo_writel(host->fifo_reg, host->part_buf32);
        }
 }
 
@@ -1819,8 +1895,7 @@ static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt)
                        int items = len >> 2;
                        int i;
                        for (i = 0; i < items; ++i)
-                               aligned_buf[i] = mci_readl(host,
-                                               DATA(host->data_offset));
+                               aligned_buf[i] = mci_fifo_readl(host->fifo_reg);
                        /* memcpy from aligned buffer into output buffer */
                        memcpy(buf, aligned_buf, len);
                        buf += len;
@@ -1831,11 +1906,11 @@ static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt)
        {
                u32 *pdata = buf;
                for (; cnt >= 4; cnt -= 4)
-                       *pdata++ = mci_readl(host, DATA(host->data_offset));
+                       *pdata++ = mci_fifo_readl(host->fifo_reg);
                buf = pdata;
        }
        if (cnt) {
-               host->part_buf32 = mci_readl(host, DATA(host->data_offset));
+               host->part_buf32 = mci_fifo_readl(host->fifo_reg);
                dw_mci_pull_final_bytes(host, buf, cnt);
        }
 }
@@ -1852,8 +1927,7 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
                cnt -= len;
 
                if (host->part_buf_count == 8) {
-                       mci_writeq(host, DATA(host->data_offset),
-                                       host->part_buf);
+                       mci_fifo_writeq(host->fifo_reg, host->part_buf);
                        host->part_buf_count = 0;
                }
        }
@@ -1870,15 +1944,14 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
                        cnt -= len;
                        /* push data from aligned buffer into fifo */
                        for (i = 0; i < items; ++i)
-                               mci_writeq(host, DATA(host->data_offset),
-                                               aligned_buf[i]);
+                               mci_fifo_writeq(host->fifo_reg, aligned_buf[i]);
                }
        } else
 #endif
        {
                u64 *pdata = buf;
                for (; cnt >= 8; cnt -= 8)
-                       mci_writeq(host, DATA(host->data_offset), *pdata++);
+                       mci_fifo_writeq(host->fifo_reg, *pdata++);
                buf = pdata;
        }
        /* put anything remaining in the part_buf */
@@ -1887,8 +1960,7 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
                /* Push data if we have reached the expected data length */
                if ((data->bytes_xfered + init_cnt) ==
                    (data->blksz * data->blocks))
-                       mci_writeq(host, DATA(host->data_offset),
-                                  host->part_buf);
+                       mci_fifo_writeq(host->fifo_reg, host->part_buf);
        }
 }
 
@@ -1903,8 +1975,8 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt)
                        int items = len >> 3;
                        int i;
                        for (i = 0; i < items; ++i)
-                               aligned_buf[i] = mci_readq(host,
-                                               DATA(host->data_offset));
+                               aligned_buf[i] = mci_fifo_readq(host->fifo_reg);
+
                        /* memcpy from aligned buffer into output buffer */
                        memcpy(buf, aligned_buf, len);
                        buf += len;
@@ -1915,11 +1987,11 @@ static void dw_mci_pull_data64(struct dw_mci *host, void *buf, int cnt)
        {
                u64 *pdata = buf;
                for (; cnt >= 8; cnt -= 8)
-                       *pdata++ = mci_readq(host, DATA(host->data_offset));
+                       *pdata++ = mci_fifo_readq(host->fifo_reg);
                buf = pdata;
        }
        if (cnt) {
-               host->part_buf = mci_readq(host, DATA(host->data_offset));
+               host->part_buf = mci_fifo_readq(host->fifo_reg);
                dw_mci_pull_final_bytes(host, buf, cnt);
        }
 }
@@ -2097,9 +2169,20 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
                /* Check volt switch first, since it can look like an error */
                if ((host->state == STATE_SENDING_CMD11) &&
                    (pending & SDMMC_INT_VOLT_SWITCH)) {
+                       unsigned long irqflags;
+
                        mci_writel(host, RINTSTS, SDMMC_INT_VOLT_SWITCH);
                        pending &= ~SDMMC_INT_VOLT_SWITCH;
+
+                       /*
+                        * Hold the lock; we know cmd11_timer can't be kicked
+                        * off after the lock is released, so safe to delete.
+                        */
+                       spin_lock_irqsave(&host->irq_lock, irqflags);
                        dw_mci_cmd_interrupt(host, pending);
+                       spin_unlock_irqrestore(&host->irq_lock, irqflags);
+
+                       del_timer(&host->cmd11_timer);
                }
 
                if (pending & DW_MCI_CMD_ERROR_FLAGS) {
@@ -2156,6 +2239,10 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
                /* Handle SDIO Interrupts */
                for (i = 0; i < host->num_slots; i++) {
                        struct dw_mci_slot *slot = host->slot[i];
+
+                       if (!slot)
+                               continue;
+
                        if (pending & SDMMC_INT_SDIO(slot->sdio_id)) {
                                mci_writel(host, RINTSTS,
                                           SDMMC_INT_SDIO(slot->sdio_id));
@@ -2506,6 +2593,20 @@ ciu_out:
        return ret;
 }
 
+static void dw_mci_cmd11_timer(unsigned long arg)
+{
+       struct dw_mci *host = (struct dw_mci *)arg;
+
+       if (host->state != STATE_SENDING_CMD11) {
+               dev_warn(host->dev, "Unexpected CMD11 timeout\n");
+               return;
+       }
+
+       host->cmd_status = SDMMC_INT_RTO;
+       set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
+       tasklet_schedule(&host->tasklet);
+}
+
 #ifdef CONFIG_OF
 static struct dw_mci_of_quirks {
        char *quirk;
@@ -2574,6 +2675,34 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
 }
 #endif /* CONFIG_OF */
 
+static void dw_mci_enable_cd(struct dw_mci *host)
+{
+       struct dw_mci_board *brd = host->pdata;
+       unsigned long irqflags;
+       u32 temp;
+       int i;
+
+       /* No need for CD if broken card detection */
+       if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
+               return;
+
+       /* No need for CD if all slots have a non-error GPIO */
+       for (i = 0; i < host->num_slots; i++) {
+               struct dw_mci_slot *slot = host->slot[i];
+
+               if (IS_ERR_VALUE(mmc_gpio_get_cd(slot->mmc)))
+                       break;
+       }
+       if (i == host->num_slots)
+               return;
+
+       spin_lock_irqsave(&host->irq_lock, irqflags);
+       temp = mci_readl(host, INTMASK);
+       temp  |= SDMMC_INT_CD;
+       mci_writel(host, INTMASK, temp);
+       spin_unlock_irqrestore(&host->irq_lock, irqflags);
+}
+
 int dw_mci_probe(struct dw_mci *host)
 {
        const struct dw_mci_drv_data *drv_data = host->drv_data;
@@ -2652,6 +2781,9 @@ int dw_mci_probe(struct dw_mci *host)
                }
        }
 
+       setup_timer(&host->cmd11_timer,
+                   dw_mci_cmd11_timer, (unsigned long)host);
+
        host->quirks = host->pdata->quirks;
 
        spin_lock_init(&host->lock);
@@ -2731,9 +2863,9 @@ int dw_mci_probe(struct dw_mci *host)
        dev_info(host->dev, "Version ID is %04x\n", host->verid);
 
        if (host->verid < DW_MMC_240A)
-               host->data_offset = DATA_OFFSET;
+               host->fifo_reg = host->regs + DATA_OFFSET;
        else
-               host->data_offset = DATA_240A_OFFSET;
+               host->fifo_reg = host->regs + DATA_240A_OFFSET;
 
        tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
        ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
@@ -2747,13 +2879,13 @@ int dw_mci_probe(struct dw_mci *host)
                host->num_slots = ((mci_readl(host, HCON) >> 1) & 0x1F) + 1;
 
        /*
-        * Enable interrupts for command done, data over, data empty, card det,
+        * Enable interrupts for command done, data over, data empty,
         * receive ready and error such as transmit, receive timeout, crc error
         */
        mci_writel(host, RINTSTS, 0xFFFFFFFF);
        mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
                   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
-                  DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
+                  DW_MCI_ERROR_FLAGS);
        mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE); /* Enable mci interrupt */
 
        dev_info(host->dev, "DW MMC controller at irq %d, "
@@ -2778,6 +2910,9 @@ int dw_mci_probe(struct dw_mci *host)
                goto err_dmaunmap;
        }
 
+       /* Now that slots are all setup, we can enable card detect */
+       dw_mci_enable_cd(host);
+
        if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
                dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");
 
@@ -2864,7 +2999,7 @@ int dw_mci_resume(struct dw_mci *host)
        mci_writel(host, RINTSTS, 0xFFFFFFFF);
        mci_writel(host, INTMASK, SDMMC_INT_CMD_DONE | SDMMC_INT_DATA_OVER |
                   SDMMC_INT_TXDR | SDMMC_INT_RXDR |
-                  DW_MCI_ERROR_FLAGS | SDMMC_INT_CD);
+                  DW_MCI_ERROR_FLAGS);
        mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
 
        for (i = 0; i < host->num_slots; i++) {
@@ -2876,6 +3011,10 @@ int dw_mci_resume(struct dw_mci *host)
                        dw_mci_setup_bus(slot, true);
                }
        }
+
+       /* Now that slots are all setup, we can enable card detect */
+       dw_mci_enable_cd(host);
+
        return 0;
 }
 EXPORT_SYMBOL(dw_mci_resume);
index 18c4afe683b83c60d0941230b34735a64f58a6e4..f45ab91de33946ac86abc72ae8305eb1f18aa55e 100644 (file)
 #define SDMMC_CTRL_ALL_RESET_FLAGS \
        (SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET)
 
+/* FIFO register access macros. These should not change the data endian-ness
+ * as they are written to memory to be dealt with by the upper layers */
+#define mci_fifo_readw(__reg)  __raw_readw(__reg)
+#define mci_fifo_readl(__reg)  __raw_readl(__reg)
+#define mci_fifo_readq(__reg)  __raw_readq(__reg)
+
+#define mci_fifo_writew(__value, __reg)        __raw_writew(__reg, __value)
+#define mci_fifo_writel(__value, __reg)        __raw_writel(__reg, __value)
+#define mci_fifo_writeq(__value, __reg)        __raw_writeq(__reg, __value)
+
 /* Register access macros */
 #define mci_readl(dev, reg)                    \
-       __raw_readl((dev)->regs + SDMMC_##reg)
+       readl_relaxed((dev)->regs + SDMMC_##reg)
 #define mci_writel(dev, reg, value)                    \
-       __raw_writel((value), (dev)->regs + SDMMC_##reg)
+       writel_relaxed((value), (dev)->regs + SDMMC_##reg)
 
 /* 16-bit FIFO access macros */
 #define mci_readw(dev, reg)                    \
-       __raw_readw((dev)->regs + SDMMC_##reg)
+       readw_relaxed((dev)->regs + SDMMC_##reg)
 #define mci_writew(dev, reg, value)                    \
-       __raw_writew((value), (dev)->regs + SDMMC_##reg)
+       writew_relaxed((value), (dev)->regs + SDMMC_##reg)
 
 /* 64-bit FIFO access macros */
 #ifdef readq
 #define mci_readq(dev, reg)                    \
-       __raw_readq((dev)->regs + SDMMC_##reg)
+       readq_relaxed((dev)->regs + SDMMC_##reg)
 #define mci_writeq(dev, reg, value)                    \
-       __raw_writeq((value), (dev)->regs + SDMMC_##reg)
+       writeq_relaxed((value), (dev)->regs + SDMMC_##reg)
 #else
 /*
  * Dummy readq implementation for architectures that don't define it.
        (*(volatile u64 __force *)((dev)->regs + SDMMC_##reg))
 #define mci_writeq(dev, reg, value)                    \
        (*(volatile u64 __force *)((dev)->regs + SDMMC_##reg) = (value))
+
+#define __raw_writeq(__value, __reg) \
+       (*(volatile u64 __force *)(__reg) = (__value))
+#define __raw_readq(__reg) (*(volatile u64 __force *)(__reg))
 #endif
 
 extern int dw_mci_probe(struct dw_mci *host);
@@ -271,5 +285,7 @@ struct dw_mci_drv_data {
        void            (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
        int             (*parse_dt)(struct dw_mci *host);
        int             (*execute_tuning)(struct dw_mci_slot *slot);
+       int             (*prepare_hs400_tuning)(struct dw_mci *host,
+                                               struct mmc_ios *ios);
 };
 #endif /* _DW_MMC_H_ */
index e4a07546f8b631d4c905dbe483449bf381960279..ae19d83bb9de0d966bb095f73c2f8b900578659a 100644 (file)
@@ -1507,7 +1507,7 @@ static int mmc_spi_remove(struct spi_device *spi)
        return 0;
 }
 
-static struct of_device_id mmc_spi_of_match_table[] = {
+static const struct of_device_id mmc_spi_of_match_table[] = {
        { .compatible = "mmc-spi-slot", },
        {},
 };
index 7fe16194ebc802c65c65a1741f746ff4af42fb2c..fb266745f8240d603956b8b791370ac4764f5a23 100644 (file)
@@ -1613,7 +1613,10 @@ static int mmci_probe(struct amba_device *dev,
        dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max);
 
        /* Get regulators and the supported OCR mask */
-       mmc_regulator_get_supply(mmc);
+       ret = mmc_regulator_get_supply(mmc);
+       if (ret == -EPROBE_DEFER)
+               goto clk_disable;
+
        if (!mmc->ocr_avail)
                mmc->ocr_avail = plat->ocr_mask;
        else if (plat->ocr_mask)
index f84cfb01716d777d159a9bbabf14b4176098b45b..9df2b6801f767c9c0da6904b689299c93d031417 100644 (file)
@@ -222,10 +222,6 @@ struct omap_hsmmc_host {
        struct omap_hsmmc_next  next_data;
        struct  omap_hsmmc_platform_data        *pdata;
 
-       /* To handle board related suspend/resume functionality for MMC */
-       int (*suspend)(struct device *dev);
-       int (*resume)(struct device *dev);
-
        /* return MMC cover switch state, can be NULL if not supported.
         *
         * possible return values:
@@ -234,12 +230,7 @@ struct omap_hsmmc_host {
         */
        int (*get_cover_state)(struct device *dev);
 
-       /* Card detection IRQs */
-       int card_detect_irq;
-
        int (*card_detect)(struct device *dev);
-       int (*get_ro)(struct device *dev);
-
 };
 
 struct omap_mmc_of_data {
@@ -256,13 +247,6 @@ static int omap_hsmmc_card_detect(struct device *dev)
        return mmc_gpio_get_cd(host->mmc);
 }
 
-static int omap_hsmmc_get_wp(struct device *dev)
-{
-       struct omap_hsmmc_host *host = dev_get_drvdata(dev);
-
-       return mmc_gpio_get_ro(host->mmc);
-}
-
 static int omap_hsmmc_get_cover_state(struct device *dev)
 {
        struct omap_hsmmc_host *host = dev_get_drvdata(dev);
@@ -434,7 +418,7 @@ static inline int omap_hsmmc_have_reg(void)
 
 #endif
 
-static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id);
+static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id);
 
 static int omap_hsmmc_gpio_init(struct mmc_host *mmc,
                                struct omap_hsmmc_host *host,
@@ -442,29 +426,25 @@ static int omap_hsmmc_gpio_init(struct mmc_host *mmc,
 {
        int ret;
 
-       if (gpio_is_valid(pdata->switch_pin)) {
-               if (pdata->cover)
-                       host->get_cover_state =
-                               omap_hsmmc_get_cover_state;
-               else
-                       host->card_detect = omap_hsmmc_card_detect;
-               host->card_detect_irq =
-                               gpio_to_irq(pdata->switch_pin);
-               mmc_gpio_set_cd_isr(mmc, omap_hsmmc_detect);
-               ret = mmc_gpio_request_cd(mmc, pdata->switch_pin, 0);
+       if (gpio_is_valid(pdata->gpio_cod)) {
+               ret = mmc_gpio_request_cd(mmc, pdata->gpio_cod, 0);
                if (ret)
                        return ret;
-       } else {
-               pdata->switch_pin = -EINVAL;
+
+               host->get_cover_state = omap_hsmmc_get_cover_state;
+               mmc_gpio_set_cd_isr(mmc, omap_hsmmc_cover_irq);
+       } else if (gpio_is_valid(pdata->gpio_cd)) {
+               ret = mmc_gpio_request_cd(mmc, pdata->gpio_cd, 0);
+               if (ret)
+                       return ret;
+
+               host->card_detect = omap_hsmmc_card_detect;
        }
 
        if (gpio_is_valid(pdata->gpio_wp)) {
-               host->get_ro = omap_hsmmc_get_wp;
                ret = mmc_gpio_request_ro(mmc, pdata->gpio_wp);
                if (ret)
                        return ret;
-       } else {
-               pdata->gpio_wp = -EINVAL;
        }
 
        return 0;
@@ -882,6 +862,8 @@ static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_req
                return;
        host->mrq = NULL;
        mmc_request_done(host->mmc, mrq);
+       pm_runtime_mark_last_busy(host->dev);
+       pm_runtime_put_autosuspend(host->dev);
 }
 
 /*
@@ -1252,26 +1234,16 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
 }
 
 /*
- * irq handler to notify the core about card insertion/removal
+ * irq handler when (cell-phone) cover is mounted/removed
  */
-static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id)
+static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id)
 {
        struct omap_hsmmc_host *host = dev_id;
-       int carddetect;
 
        sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
 
-       if (host->card_detect)
-               carddetect = host->card_detect(host->dev);
-       else {
-               omap_hsmmc_protect_card(host);
-               carddetect = -ENOSYS;
-       }
-
-       if (carddetect)
-               mmc_detect_change(host->mmc, (HZ * 200) / 1000);
-       else
-               mmc_detect_change(host->mmc, (HZ * 50) / 1000);
+       omap_hsmmc_protect_card(host);
+       mmc_detect_change(host->mmc, (HZ * 200) / 1000);
        return IRQ_HANDLED;
 }
 
@@ -1305,6 +1277,8 @@ static void omap_hsmmc_dma_callback(void *param)
 
                host->mrq = NULL;
                mmc_request_done(host->mmc, mrq);
+               pm_runtime_mark_last_busy(host->dev);
+               pm_runtime_put_autosuspend(host->dev);
        }
 }
 
@@ -1537,6 +1511,7 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
 
        BUG_ON(host->req_in_progress);
        BUG_ON(host->dma_ch != -1);
+       pm_runtime_get_sync(host->dev);
        if (host->protect_card) {
                if (host->reqs_blocked < 3) {
                        /*
@@ -1553,6 +1528,8 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
                        req->data->error = -EBADF;
                req->cmd->retries = 0;
                mmc_request_done(mmc, req);
+               pm_runtime_mark_last_busy(host->dev);
+               pm_runtime_put_autosuspend(host->dev);
                return;
        } else if (host->reqs_blocked)
                host->reqs_blocked = 0;
@@ -1566,6 +1543,8 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
                        req->data->error = err;
                host->mrq = NULL;
                mmc_request_done(mmc, req);
+               pm_runtime_mark_last_busy(host->dev);
+               pm_runtime_put_autosuspend(host->dev);
                return;
        }
        if (req->sbc && !(host->flags & AUTO_CMD23)) {
@@ -1641,15 +1620,6 @@ static int omap_hsmmc_get_cd(struct mmc_host *mmc)
        return host->card_detect(host->dev);
 }
 
-static int omap_hsmmc_get_ro(struct mmc_host *mmc)
-{
-       struct omap_hsmmc_host *host = mmc_priv(mmc);
-
-       if (!host->get_ro)
-               return -ENOSYS;
-       return host->get_ro(host->dev);
-}
-
 static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
 {
        struct omap_hsmmc_host *host = mmc_priv(mmc);
@@ -1778,25 +1748,6 @@ static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
        set_sd_bus_power(host);
 }
 
-static int omap_hsmmc_enable_fclk(struct mmc_host *mmc)
-{
-       struct omap_hsmmc_host *host = mmc_priv(mmc);
-
-       pm_runtime_get_sync(host->dev);
-
-       return 0;
-}
-
-static int omap_hsmmc_disable_fclk(struct mmc_host *mmc)
-{
-       struct omap_hsmmc_host *host = mmc_priv(mmc);
-
-       pm_runtime_mark_last_busy(host->dev);
-       pm_runtime_put_autosuspend(host->dev);
-
-       return 0;
-}
-
 static int omap_hsmmc_multi_io_quirk(struct mmc_card *card,
                                     unsigned int direction, int blk_size)
 {
@@ -1808,14 +1759,12 @@ static int omap_hsmmc_multi_io_quirk(struct mmc_card *card,
 }
 
 static struct mmc_host_ops omap_hsmmc_ops = {
-       .enable = omap_hsmmc_enable_fclk,
-       .disable = omap_hsmmc_disable_fclk,
        .post_req = omap_hsmmc_post_req,
        .pre_req = omap_hsmmc_pre_req,
        .request = omap_hsmmc_request,
        .set_ios = omap_hsmmc_set_ios,
        .get_cd = omap_hsmmc_get_cd,
-       .get_ro = omap_hsmmc_get_ro,
+       .get_ro = mmc_gpio_get_ro,
        .init_card = omap_hsmmc_init_card,
        .enable_sdio_irq = omap_hsmmc_enable_sdio_irq,
 };
@@ -1937,7 +1886,8 @@ static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
        if (of_find_property(np, "ti,dual-volt", NULL))
                pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
 
-       pdata->switch_pin = -EINVAL;
+       pdata->gpio_cd = -EINVAL;
+       pdata->gpio_cod = -EINVAL;
        pdata->gpio_wp = -EINVAL;
 
        if (of_find_property(np, "ti,non-removable", NULL)) {
@@ -2179,9 +2129,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
                if (ret < 0)
                        goto err_slot_name;
        }
-       if (host->card_detect_irq && host->get_cover_state) {
+       if (host->get_cover_state) {
                ret = device_create_file(&mmc->class_dev,
-                                       &dev_attr_cover_switch);
+                                        &dev_attr_cover_switch);
                if (ret < 0)
                        goto err_slot_name;
        }
@@ -2236,7 +2186,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int omap_hsmmc_suspend(struct device *dev)
 {
        struct omap_hsmmc_host *host = dev_get_drvdata(dev);
@@ -2292,10 +2242,6 @@ static int omap_hsmmc_resume(struct device *dev)
        pm_runtime_put_autosuspend(host->dev);
        return 0;
 }
-
-#else
-#define omap_hsmmc_suspend     NULL
-#define omap_hsmmc_resume      NULL
 #endif
 
 static int omap_hsmmc_runtime_suspend(struct device *dev)
@@ -2376,8 +2322,7 @@ static int omap_hsmmc_runtime_resume(struct device *dev)
 }
 
 static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
-       .suspend        = omap_hsmmc_suspend,
-       .resume         = omap_hsmmc_resume,
+       SET_SYSTEM_SLEEP_PM_OPS(omap_hsmmc_suspend, omap_hsmmc_resume)
        .runtime_suspend = omap_hsmmc_runtime_suspend,
        .runtime_resume = omap_hsmmc_runtime_resume,
 };
index a45ed39d062c1d7a73d557cd3c62e326fbf61652..22d929fa3371adbf87c2efa744b0272701d72741 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/pm.h>
 #include <linux/mmc/slot-gpio.h>
-#include <linux/mmc/sdhci.h>
 
 #include "sdhci.h"
 
index 34bb8f92586e25980ea5467c366e1700884328a5..2bd90fb35c75e5b5c03f243aabd1edc99dce04d5 100644 (file)
@@ -54,7 +54,6 @@
 
 struct sdhci_bcm_kona_dev {
        struct mutex    write_lock; /* protect back to back writes */
-       struct clk      *external_clk;
 };
 
 
@@ -175,24 +174,6 @@ static void sdhci_bcm_kona_card_event(struct sdhci_host *host)
        }
 }
 
-/*
- * Get the base clock. Use central clock source for now. Not sure if different
- * clock speed to each dev is allowed
- */
-static unsigned int sdhci_bcm_kona_get_max_clk(struct sdhci_host *host)
-{
-       struct sdhci_bcm_kona_dev *kona_dev;
-       struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host);
-       kona_dev = sdhci_pltfm_priv(pltfm_priv);
-
-       return host->mmc->f_max;
-}
-
-static unsigned int sdhci_bcm_kona_get_timeout_clock(struct sdhci_host *host)
-{
-       return sdhci_bcm_kona_get_max_clk(host);
-}
-
 static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host,
                                u8 power_mode)
 {
@@ -207,8 +188,8 @@ static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host,
 
 static struct sdhci_ops sdhci_bcm_kona_ops = {
        .set_clock = sdhci_set_clock,
-       .get_max_clock = sdhci_bcm_kona_get_max_clk,
-       .get_timeout_clock = sdhci_bcm_kona_get_timeout_clock,
+       .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+       .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
        .platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks,
        .set_bus_width = sdhci_set_bus_width,
        .reset = sdhci_reset,
@@ -264,21 +245,21 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
                goto err_pltfm_free;
        }
 
-       /* Get and enable the external clock */
-       kona_dev->external_clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(kona_dev->external_clk)) {
-               dev_err(dev, "Failed to get external clock\n");
-               ret = PTR_ERR(kona_dev->external_clk);
+       /* Get and enable the core clock */
+       pltfm_priv->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(pltfm_priv->clk)) {
+               dev_err(dev, "Failed to get core clock\n");
+               ret = PTR_ERR(pltfm_priv->clk);
                goto err_pltfm_free;
        }
 
-       if (clk_set_rate(kona_dev->external_clk, host->mmc->f_max) != 0) {
-               dev_err(dev, "Failed to set rate external clock\n");
+       if (clk_set_rate(pltfm_priv->clk, host->mmc->f_max) != 0) {
+               dev_err(dev, "Failed to set rate core clock\n");
                goto err_pltfm_free;
        }
 
-       if (clk_prepare_enable(kona_dev->external_clk) != 0) {
-               dev_err(dev, "Failed to enable external clock\n");
+       if (clk_prepare_enable(pltfm_priv->clk) != 0) {
+               dev_err(dev, "Failed to enable core clock\n");
                goto err_pltfm_free;
        }
 
@@ -333,7 +314,7 @@ err_reset:
        sdhci_bcm_kona_sd_reset(host);
 
 err_clk_disable:
-       clk_disable_unprepare(kona_dev->external_clk);
+       clk_disable_unprepare(pltfm_priv->clk);
 
 err_pltfm_free:
        sdhci_pltfm_free(pdev);
@@ -342,22 +323,6 @@ err_pltfm_free:
        return ret;
 }
 
-static int sdhci_bcm_kona_remove(struct platform_device *pdev)
-{
-       struct sdhci_host *host = platform_get_drvdata(pdev);
-       struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host);
-       struct sdhci_bcm_kona_dev *kona_dev = sdhci_pltfm_priv(pltfm_priv);
-       int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
-
-       sdhci_remove_host(host, dead);
-
-       clk_disable_unprepare(kona_dev->external_clk);
-
-       sdhci_pltfm_free(pdev);
-
-       return 0;
-}
-
 static struct platform_driver sdhci_bcm_kona_driver = {
        .driver         = {
                .name   = "sdhci-kona",
@@ -365,7 +330,7 @@ static struct platform_driver sdhci_bcm_kona_driver = {
                .of_match_table = sdhci_bcm_kona_of_match,
        },
        .probe          = sdhci_bcm_kona_probe,
-       .remove         = sdhci_bcm_kona_remove,
+       .remove         = sdhci_pltfm_unregister,
 };
 module_platform_driver(sdhci_bcm_kona_driver);
 
index 439d259fdf1d571336fe86a3b3de483143430517..0ef0343c603ad492937ef338af8b058ecc9f51e9 100644 (file)
@@ -180,11 +180,6 @@ err:
        return ret;
 }
 
-static int bcm2835_sdhci_remove(struct platform_device *pdev)
-{
-       return sdhci_pltfm_unregister(pdev);
-}
-
 static const struct of_device_id bcm2835_sdhci_of_match[] = {
        { .compatible = "brcm,bcm2835-sdhci" },
        { }
@@ -198,7 +193,7 @@ static struct platform_driver bcm2835_sdhci_driver = {
                .pm = SDHCI_PLTFM_PMOPS,
        },
        .probe = bcm2835_sdhci_probe,
-       .remove = bcm2835_sdhci_remove,
+       .remove = sdhci_pltfm_unregister,
 };
 module_platform_driver(bcm2835_sdhci_driver);
 
index a7935a8d0922218f0874deea4e7f303a35dbb685..59f2923f80547d37f2dd5d8f43d3aeacb49854ce 100644 (file)
@@ -98,18 +98,13 @@ static int sdhci_cns3xxx_probe(struct platform_device *pdev)
        return sdhci_pltfm_register(pdev, &sdhci_cns3xxx_pdata, 0);
 }
 
-static int sdhci_cns3xxx_remove(struct platform_device *pdev)
-{
-       return sdhci_pltfm_unregister(pdev);
-}
-
 static struct platform_driver sdhci_cns3xxx_driver = {
        .driver         = {
                .name   = "sdhci-cns3xxx",
                .pm     = SDHCI_PLTFM_PMOPS,
        },
        .probe          = sdhci_cns3xxx_probe,
-       .remove         = sdhci_cns3xxx_remove,
+       .remove         = sdhci_pltfm_unregister,
 };
 
 module_platform_driver(sdhci_cns3xxx_driver);
index ca969d271a270bfb0bcb6e56fc3626f7398218a5..407c21f152b2dacad43706db77b8a2c5a97c08e8 100644 (file)
 
 #include "sdhci-pltfm.h"
 
-struct sdhci_dove_priv {
-       struct clk *clk;
-};
-
 static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)
 {
        u16 ret;
@@ -84,27 +80,17 @@ static int sdhci_dove_probe(struct platform_device *pdev)
 {
        struct sdhci_host *host;
        struct sdhci_pltfm_host *pltfm_host;
-       struct sdhci_dove_priv *priv;
        int ret;
 
-       priv = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_dove_priv),
-                           GFP_KERNEL);
-       if (!priv) {
-               dev_err(&pdev->dev, "unable to allocate private data");
-               return -ENOMEM;
-       }
-
-       priv->clk = devm_clk_get(&pdev->dev, NULL);
-
        host = sdhci_pltfm_init(pdev, &sdhci_dove_pdata, 0);
        if (IS_ERR(host))
                return PTR_ERR(host);
 
        pltfm_host = sdhci_priv(host);
-       pltfm_host->priv = priv;
+       pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
 
-       if (!IS_ERR(priv->clk))
-               clk_prepare_enable(priv->clk);
+       if (!IS_ERR(pltfm_host->clk))
+               clk_prepare_enable(pltfm_host->clk);
 
        ret = mmc_of_parse(host->mmc);
        if (ret)
@@ -117,26 +103,11 @@ static int sdhci_dove_probe(struct platform_device *pdev)
        return 0;
 
 err_sdhci_add:
-       if (!IS_ERR(priv->clk))
-               clk_disable_unprepare(priv->clk);
+       clk_disable_unprepare(pltfm_host->clk);
        sdhci_pltfm_free(pdev);
        return ret;
 }
 
-static int sdhci_dove_remove(struct platform_device *pdev)
-{
-       struct sdhci_host *host = platform_get_drvdata(pdev);
-       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct sdhci_dove_priv *priv = pltfm_host->priv;
-
-       sdhci_pltfm_unregister(pdev);
-
-       if (!IS_ERR(priv->clk))
-               clk_disable_unprepare(priv->clk);
-
-       return 0;
-}
-
 static const struct of_device_id sdhci_dove_of_match_table[] = {
        { .compatible = "marvell,dove-sdhci", },
        {}
@@ -150,7 +121,7 @@ static struct platform_driver sdhci_dove_driver = {
                .of_match_table = sdhci_dove_of_match_table,
        },
        .probe          = sdhci_dove_probe,
-       .remove         = sdhci_dove_remove,
+       .remove         = sdhci_pltfm_unregister,
 };
 
 module_platform_driver(sdhci_dove_driver);
index 10ef8244a239632819fd2f399bf1ee48b2bb8496..82f512d87cb8916e76314f465339c820ef92b1f1 100644 (file)
@@ -416,7 +416,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
                        new_val |= ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;
                else
                        new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;
-                       writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
+               writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
                return;
        case SDHCI_HOST_CONTROL2:
                new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
@@ -864,6 +864,7 @@ static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
 #ifdef CONFIG_OF
 static int
 sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
+                        struct sdhci_host *host,
                         struct esdhc_platform_data *boarddata)
 {
        struct device_node *np = pdev->dev.of_node;
@@ -900,11 +901,14 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
        if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line))
                boarddata->delay_line = 0;
 
+       mmc_of_parse_voltage(np, &host->ocr_mask);
+
        return 0;
 }
 #else
 static inline int
 sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
+                        struct sdhci_host *host,
                         struct esdhc_platform_data *boarddata)
 {
        return -ENODEV;
@@ -999,7 +1003,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
                        host->ioaddr + ESDHC_TUNING_CTRL);
 
        boarddata = &imx_data->boarddata;
-       if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) {
+       if (sdhci_esdhc_imx_probe_dt(pdev, host, boarddata) < 0) {
                if (!host->mmc->parent->platform_data) {
                        dev_err(mmc_dev(host->mmc), "no board data!\n");
                        err = -EINVAL;
@@ -1009,40 +1013,9 @@ static int sdhci_esdhc_imx_probe(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);
-               if (err) {
-                       dev_err(mmc_dev(host->mmc),
-                               "failed to request write-protect gpio!\n");
-                       goto disable_clk;
-               }
-               host->mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
-       }
-
        /* card_detect */
-       switch (boarddata->cd_type) {
-       case ESDHC_CD_GPIO:
-               err = mmc_gpio_request_cd(host->mmc, boarddata->cd_gpio, 0);
-               if (err) {
-                       dev_err(mmc_dev(host->mmc),
-                               "failed to request card-detect gpio!\n");
-                       goto disable_clk;
-               }
-               /* fall through */
-
-       case ESDHC_CD_CONTROLLER:
-               /* we have a working card_detect back */
+       if (boarddata->cd_type == ESDHC_CD_CONTROLLER)
                host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
-               break;
-
-       case ESDHC_CD_PERMANENT:
-               host->mmc->caps |= MMC_CAP_NONREMOVABLE;
-               break;
-
-       case ESDHC_CD_NONE:
-               break;
-       }
 
        switch (boarddata->max_bus_width) {
        case 8:
@@ -1075,6 +1048,11 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
                host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
        }
 
+       /* call to generic mmc_of_parse to support additional capabilities */
+       err = mmc_of_parse(host->mmc);
+       if (err)
+               goto disable_clk;
+
        err = sdhci_add_host(host);
        if (err)
                goto disable_clk;
diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c
new file mode 100644 (file)
index 0000000..3b423b0
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * iProc SDHCI platform driver
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/mmc/host.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include "sdhci-pltfm.h"
+
+struct sdhci_iproc_data {
+       const struct sdhci_pltfm_data *pdata;
+       u32 caps;
+       u32 caps1;
+};
+
+struct sdhci_iproc_host {
+       const struct sdhci_iproc_data *data;
+       u32 shadow_cmd;
+       u32 shadow_blk;
+};
+
+#define REG_OFFSET_IN_BITS(reg) ((reg) << 3 & 0x18)
+
+static inline u32 sdhci_iproc_readl(struct sdhci_host *host, int reg)
+{
+       u32 val = readl(host->ioaddr + reg);
+
+       pr_debug("%s: readl [0x%02x] 0x%08x\n",
+                mmc_hostname(host->mmc), reg, val);
+       return val;
+}
+
+static u16 sdhci_iproc_readw(struct sdhci_host *host, int reg)
+{
+       u32 val = sdhci_iproc_readl(host, (reg & ~3));
+       u16 word = val >> REG_OFFSET_IN_BITS(reg) & 0xffff;
+       return word;
+}
+
+static u8 sdhci_iproc_readb(struct sdhci_host *host, int reg)
+{
+       u32 val = sdhci_iproc_readl(host, (reg & ~3));
+       u8 byte = val >> REG_OFFSET_IN_BITS(reg) & 0xff;
+       return byte;
+}
+
+static inline void sdhci_iproc_writel(struct sdhci_host *host, u32 val, int reg)
+{
+       pr_debug("%s: writel [0x%02x] 0x%08x\n",
+                mmc_hostname(host->mmc), reg, val);
+
+       writel(val, host->ioaddr + reg);
+
+       if (host->clock <= 400000) {
+               /* Round up to micro-second four SD clock delay */
+               if (host->clock)
+                       udelay((4 * 1000000 + host->clock - 1) / host->clock);
+               else
+                       udelay(10);
+       }
+}
+
+/*
+ * The Arasan has a bugette whereby it may lose the content of successive
+ * writes to the same register that are within two SD-card clock cycles of
+ * each other (a clock domain crossing problem). The data
+ * register does not have this problem, which is just as well - otherwise we'd
+ * have to nobble the DMA engine too.
+ *
+ * This wouldn't be a problem with the code except that we can only write the
+ * controller with 32-bit writes.  So two different 16-bit registers are
+ * written back to back creates the problem.
+ *
+ * In reality, this only happens when SDHCI_BLOCK_SIZE and SDHCI_BLOCK_COUNT
+ * are written followed by SDHCI_TRANSFER_MODE and SDHCI_COMMAND.
+ * The BLOCK_SIZE and BLOCK_COUNT are meaningless until a command issued so
+ * the work around can be further optimized. We can keep shadow values of
+ * BLOCK_SIZE, BLOCK_COUNT, and TRANSFER_MODE until a COMMAND is issued.
+ * Then, write the BLOCK_SIZE+BLOCK_COUNT in a single 32-bit write followed
+ * by the TRANSFER+COMMAND in another 32-bit write.
+ */
+static void sdhci_iproc_writew(struct sdhci_host *host, u16 val, int reg)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_iproc_host *iproc_host = sdhci_pltfm_priv(pltfm_host);
+       u32 word_shift = REG_OFFSET_IN_BITS(reg);
+       u32 mask = 0xffff << word_shift;
+       u32 oldval, newval;
+
+       if (reg == SDHCI_COMMAND) {
+               /* Write the block now as we are issuing a command */
+               if (iproc_host->shadow_blk != 0) {
+                       sdhci_iproc_writel(host, iproc_host->shadow_blk,
+                               SDHCI_BLOCK_SIZE);
+                       iproc_host->shadow_blk = 0;
+               }
+               oldval = iproc_host->shadow_cmd;
+       } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) {
+               /* Block size and count are stored in shadow reg */
+               oldval = iproc_host->shadow_blk;
+       } else {
+               /* Read reg, all other registers are not shadowed */
+               oldval = sdhci_iproc_readl(host, (reg & ~3));
+       }
+       newval = (oldval & ~mask) | (val << word_shift);
+
+       if (reg == SDHCI_TRANSFER_MODE) {
+               /* Save the transfer mode until the command is issued */
+               iproc_host->shadow_cmd = newval;
+       } else if (reg == SDHCI_BLOCK_SIZE || reg == SDHCI_BLOCK_COUNT) {
+               /* Save the block info until the command is issued */
+               iproc_host->shadow_blk = newval;
+       } else {
+               /* Command or other regular 32-bit write */
+               sdhci_iproc_writel(host, newval, reg & ~3);
+       }
+}
+
+static void sdhci_iproc_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+       u32 oldval = sdhci_iproc_readl(host, (reg & ~3));
+       u32 byte_shift = REG_OFFSET_IN_BITS(reg);
+       u32 mask = 0xff << byte_shift;
+       u32 newval = (oldval & ~mask) | (val << byte_shift);
+
+       sdhci_iproc_writel(host, newval, reg & ~3);
+}
+
+static const struct sdhci_ops sdhci_iproc_ops = {
+       .read_l = sdhci_iproc_readl,
+       .read_w = sdhci_iproc_readw,
+       .read_b = sdhci_iproc_readb,
+       .write_l = sdhci_iproc_writel,
+       .write_w = sdhci_iproc_writew,
+       .write_b = sdhci_iproc_writeb,
+       .set_clock = sdhci_set_clock,
+       .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+       .set_bus_width = sdhci_set_bus_width,
+       .reset = sdhci_reset,
+       .set_uhs_signaling = sdhci_set_uhs_signaling,
+};
+
+static const struct sdhci_pltfm_data sdhci_iproc_pltfm_data = {
+       .quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK,
+       .quirks2 = SDHCI_QUIRK2_ACMD23_BROKEN,
+       .ops = &sdhci_iproc_ops,
+};
+
+static const struct sdhci_iproc_data iproc_data = {
+       .pdata = &sdhci_iproc_pltfm_data,
+       .caps = 0x05E90000,
+       .caps1 = 0x00000064,
+};
+
+static const struct of_device_id sdhci_iproc_of_match[] = {
+       { .compatible = "brcm,sdhci-iproc-cygnus", .data = &iproc_data },
+       { }
+};
+MODULE_DEVICE_TABLE(of, sdhci_iproc_of_match);
+
+static int sdhci_iproc_probe(struct platform_device *pdev)
+{
+       const struct of_device_id *match;
+       const struct sdhci_iproc_data *iproc_data;
+       struct sdhci_host *host;
+       struct sdhci_iproc_host *iproc_host;
+       struct sdhci_pltfm_host *pltfm_host;
+       int ret;
+
+       match = of_match_device(sdhci_iproc_of_match, &pdev->dev);
+       if (!match)
+               return -EINVAL;
+       iproc_data = match->data;
+
+       host = sdhci_pltfm_init(pdev, iproc_data->pdata, sizeof(*iproc_host));
+       if (IS_ERR(host))
+               return PTR_ERR(host);
+
+       pltfm_host = sdhci_priv(host);
+       iproc_host = sdhci_pltfm_priv(pltfm_host);
+
+       iproc_host->data = iproc_data;
+
+       mmc_of_parse(host->mmc);
+       sdhci_get_of_property(pdev);
+
+       /* Enable EMMC 1/8V DDR capable */
+       host->mmc->caps |= MMC_CAP_1_8V_DDR;
+
+       pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(pltfm_host->clk)) {
+               ret = PTR_ERR(pltfm_host->clk);
+               goto err;
+       }
+
+       if (iproc_host->data->pdata->quirks & SDHCI_QUIRK_MISSING_CAPS) {
+               host->caps = iproc_host->data->caps;
+               host->caps1 = iproc_host->data->caps1;
+       }
+
+       return sdhci_add_host(host);
+
+err:
+       sdhci_pltfm_free(pdev);
+       return ret;
+}
+
+static int sdhci_iproc_remove(struct platform_device *pdev)
+{
+       return sdhci_pltfm_unregister(pdev);
+}
+
+static struct platform_driver sdhci_iproc_driver = {
+       .driver = {
+               .name = "sdhci-iproc",
+               .of_match_table = sdhci_iproc_of_match,
+               .pm = SDHCI_PLTFM_PMOPS,
+       },
+       .probe = sdhci_iproc_probe,
+       .remove = sdhci_iproc_remove,
+};
+module_platform_driver(sdhci_iproc_driver);
+
+MODULE_AUTHOR("Broadcom");
+MODULE_DESCRIPTION("IPROC SDHCI driver");
+MODULE_LICENSE("GPL v2");
index 3d32ce896b091f51cdfd74b383ade7ad6e8477a7..4a09f7608c66affcede7565ea7c75c41bb10f6ba 100644 (file)
 
 #include "sdhci-pltfm.h"
 
+#define CORE_MCI_VERSION               0x50
+#define CORE_VERSION_MAJOR_SHIFT       28
+#define CORE_VERSION_MAJOR_MASK                (0xf << CORE_VERSION_MAJOR_SHIFT)
+#define CORE_VERSION_MINOR_MASK                0xff
+
 #define CORE_HC_MODE           0x78
 #define HC_MODE_EN             0x1
 #define CORE_POWER             0x0
@@ -41,6 +46,8 @@
 #define CORE_VENDOR_SPEC       0x10c
 #define CORE_CLK_PWRSAVE       BIT(1)
 
+#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c
+
 #define CDR_SELEXT_SHIFT       20
 #define CDR_SELEXT_MASK                (0xf << CDR_SELEXT_SHIFT)
 #define CMUX_SHIFT_PHASE_SHIFT 24
@@ -426,7 +433,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)
        struct sdhci_msm_host *msm_host;
        struct resource *core_memres;
        int ret;
-       u16 host_version;
+       u16 host_version, core_minor;
+       u32 core_version, caps;
+       u8 core_major;
 
        msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL);
        if (!msm_host)
@@ -516,6 +525,24 @@ static int sdhci_msm_probe(struct platform_device *pdev)
                host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
                               SDHCI_VENDOR_VER_SHIFT));
 
+       core_version = readl_relaxed(msm_host->core_mem + CORE_MCI_VERSION);
+       core_major = (core_version & CORE_VERSION_MAJOR_MASK) >>
+                     CORE_VERSION_MAJOR_SHIFT;
+       core_minor = core_version & CORE_VERSION_MINOR_MASK;
+       dev_dbg(&pdev->dev, "MCI Version: 0x%08x, major: 0x%04x, minor: 0x%02x\n",
+               core_version, core_major, core_minor);
+
+       /*
+        * Support for some capabilities is not advertised by newer
+        * controller versions and must be explicitly enabled.
+        */
+       if (core_major >= 1 && core_minor != 0x11 && core_minor != 0x12) {
+               caps = readl_relaxed(host->ioaddr + SDHCI_CAPABILITIES);
+               caps |= SDHCI_CAN_VDD_300 | SDHCI_CAN_DO_8BIT;
+               writel_relaxed(caps, host->ioaddr +
+                              CORE_VENDOR_SPEC_CAPABILITIES0);
+       }
+
        ret = sdhci_add_host(host);
        if (ret)
                goto clk_disable;
index bcb51e9dfdcd0789866ca7739a60444106f88770..6287d426c96bf933237aa948881b5bce53215fcb 100644 (file)
@@ -173,6 +173,12 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
        pltfm_host->priv = sdhci_arasan;
        pltfm_host->clk = clk_xin;
 
+       ret = mmc_of_parse(host->mmc);
+       if (ret) {
+               dev_err(&pdev->dev, "parsing dt failed (%u)\n", ret);
+               goto clk_disable_all;
+       }
+
        ret = sdhci_add_host(host);
        if (ret)
                goto err_pltfm_free;
@@ -195,7 +201,6 @@ static int sdhci_arasan_remove(struct platform_device *pdev)
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        struct sdhci_arasan_data *sdhci_arasan = pltfm_host->priv;
 
-       clk_disable_unprepare(pltfm_host->clk);
        clk_disable_unprepare(sdhci_arasan->clk_ahb);
 
        return sdhci_pltfm_unregister(pdev);
index 17fe02ed667263a710f1aff755a8f94049c641a2..22e9111b11ffcbfcfcfeba35ba9ab260256a9de7 100644 (file)
@@ -386,11 +386,6 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
        return ret;
 }
 
-static int sdhci_esdhc_remove(struct platform_device *pdev)
-{
-       return sdhci_pltfm_unregister(pdev);
-}
-
 static const struct of_device_id sdhci_esdhc_of_match[] = {
        { .compatible = "fsl,mpc8379-esdhc" },
        { .compatible = "fsl,mpc8536-esdhc" },
@@ -406,7 +401,7 @@ static struct platform_driver sdhci_esdhc_driver = {
                .pm = ESDHC_PMOPS,
        },
        .probe = sdhci_esdhc_probe,
-       .remove = sdhci_esdhc_remove,
+       .remove = sdhci_pltfm_unregister,
 };
 
 module_platform_driver(sdhci_esdhc_driver);
index be479279a1d55479bad67654e855fa71781678ea..4079a96ad37e46e23522e11682f232191c50613d 100644 (file)
@@ -75,11 +75,6 @@ static int sdhci_hlwd_probe(struct platform_device *pdev)
        return sdhci_pltfm_register(pdev, &sdhci_hlwd_pdata, 0);
 }
 
-static int sdhci_hlwd_remove(struct platform_device *pdev)
-{
-       return sdhci_pltfm_unregister(pdev);
-}
-
 static const struct of_device_id sdhci_hlwd_of_match[] = {
        { .compatible = "nintendo,hollywood-sdhci" },
        { }
@@ -93,7 +88,7 @@ static struct platform_driver sdhci_hlwd_driver = {
                .pm = SDHCI_PLTFM_PMOPS,
        },
        .probe = sdhci_hlwd_probe,
-       .remove = sdhci_hlwd_remove,
+       .remove = sdhci_pltfm_unregister,
 };
 
 module_platform_driver(sdhci_hlwd_driver);
index 29eaff78238e9ee3dd50b9e4054522ffdf035a5f..7a3fc16d0a6c601fdb65cac29451232f5f6d30aa 100644 (file)
@@ -650,6 +650,7 @@ static int rtsx_probe_slot(struct sdhci_pci_slot *slot)
 
 static const struct sdhci_pci_fixes sdhci_rtsx = {
        .quirks2        = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
+                       SDHCI_QUIRK2_BROKEN_64_BIT_DMA |
                        SDHCI_QUIRK2_BROKEN_DDR50,
        .probe_slot     = rtsx_probe_slot,
 };
index c5b01d6bb85d41fdf236473b4f2b25cae9ee68f5..a207f5aaf62f53d7aa4db3699b4d695f9ce5d625 100644 (file)
@@ -75,43 +75,41 @@ void sdhci_get_of_property(struct platform_device *pdev)
        u32 bus_width;
        int size;
 
-       if (of_device_is_available(np)) {
-               if (of_get_property(np, "sdhci,auto-cmd12", NULL))
-                       host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
+       if (of_get_property(np, "sdhci,auto-cmd12", NULL))
+               host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
 
-               if (of_get_property(np, "sdhci,1-bit-only", NULL) ||
-                   (of_property_read_u32(np, "bus-width", &bus_width) == 0 &&
-                   bus_width == 1))
-                       host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
+       if (of_get_property(np, "sdhci,1-bit-only", NULL) ||
+           (of_property_read_u32(np, "bus-width", &bus_width) == 0 &&
+           bus_width == 1))
+               host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
 
-               if (sdhci_of_wp_inverted(np))
-                       host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
+       if (sdhci_of_wp_inverted(np))
+               host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
 
-               if (of_get_property(np, "broken-cd", NULL))
-                       host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+       if (of_get_property(np, "broken-cd", NULL))
+               host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
 
-               if (of_get_property(np, "no-1-8-v", NULL))
-                       host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
+       if (of_get_property(np, "no-1-8-v", NULL))
+               host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
 
-               if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc"))
-                       host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
+       if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc"))
+               host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
 
-               if (of_device_is_compatible(np, "fsl,p2020-esdhc") ||
-                   of_device_is_compatible(np, "fsl,p1010-esdhc") ||
-                   of_device_is_compatible(np, "fsl,t4240-esdhc") ||
-                   of_device_is_compatible(np, "fsl,mpc8536-esdhc"))
-                       host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+       if (of_device_is_compatible(np, "fsl,p2020-esdhc") ||
+           of_device_is_compatible(np, "fsl,p1010-esdhc") ||
+           of_device_is_compatible(np, "fsl,t4240-esdhc") ||
+           of_device_is_compatible(np, "fsl,mpc8536-esdhc"))
+               host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
 
-               clk = of_get_property(np, "clock-frequency", &size);
-               if (clk && size == sizeof(*clk) && *clk)
-                       pltfm_host->clock = be32_to_cpup(clk);
+       clk = of_get_property(np, "clock-frequency", &size);
+       if (clk && size == sizeof(*clk) && *clk)
+               pltfm_host->clock = be32_to_cpup(clk);
 
-               if (of_find_property(np, "keep-power-in-suspend", NULL))
-                       host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
+       if (of_find_property(np, "keep-power-in-suspend", NULL))
+               host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
 
-               if (of_find_property(np, "enable-sdio-wakeup", NULL))
-                       host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
-       }
+       if (of_find_property(np, "enable-sdio-wakeup", NULL))
+               host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
 }
 #else
 void sdhci_get_of_property(struct platform_device *pdev) {}
@@ -225,9 +223,11 @@ EXPORT_SYMBOL_GPL(sdhci_pltfm_register);
 int sdhci_pltfm_unregister(struct platform_device *pdev)
 {
        struct sdhci_host *host = platform_get_drvdata(pdev);
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
        int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
 
        sdhci_remove_host(host, dead);
+       clk_disable_unprepare(pltfm_host->clk);
        sdhci_pltfm_free(pdev);
 
        return 0;
index f6f82ec3618d66bb6bf8a54fa7e118c71d7acb10..32848eb7ad807d70acee4a8125e21f509f24f65e 100644 (file)
 #define SIRF_TUNING_COUNT 128
 
 struct sdhci_sirf_priv {
-       struct clk *clk;
        int gpio_cd;
 };
 
-static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host)
-{
-       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
-       return clk_get_rate(priv->clk);
-}
-
 static void sdhci_sirf_set_bus_width(struct sdhci_host *host, int width)
 {
        u8 ctrl;
@@ -56,7 +48,7 @@ static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode)
        int tuning_seq_cnt = 3;
        u8 phase, tuned_phases[SIRF_TUNING_COUNT];
        u8 tuned_phase_cnt = 0;
-       int rc, longest_range = 0;
+       int rc = 0, longest_range = 0;
        int start = -1, end = 0, tuning_value = -1, range = 0;
        u16 clock_setting;
        struct mmc_host *mmc = host->mmc;
@@ -68,7 +60,7 @@ retry:
        phase = 0;
        do {
                sdhci_writel(host,
-                       clock_setting | phase | (phase << 7) | (phase << 16),
+                       clock_setting | phase,
                        SDHCI_CLK_DELAY_SETTING);
 
                if (!mmc_send_tuning(mmc)) {
@@ -102,7 +94,7 @@ retry:
                 */
                phase = tuning_value;
                sdhci_writel(host,
-                       clock_setting | phase | (phase << 7) | (phase << 16),
+                       clock_setting | phase,
                        SDHCI_CLK_DELAY_SETTING);
 
                dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
@@ -122,7 +114,7 @@ retry:
 static struct sdhci_ops sdhci_sirf_ops = {
        .platform_execute_tuning = sdhci_sirf_execute_tuning,
        .set_clock = sdhci_set_clock,
-       .get_max_clock  = sdhci_sirf_get_max_clk,
+       .get_max_clock  = sdhci_pltfm_clk_get_max_clock,
        .set_bus_width = sdhci_sirf_set_bus_width,
        .reset = sdhci_reset,
        .set_uhs_signaling = sdhci_set_uhs_signaling,
@@ -162,13 +154,13 @@ static int sdhci_sirf_probe(struct platform_device *pdev)
                return PTR_ERR(host);
 
        pltfm_host = sdhci_priv(host);
+       pltfm_host->clk = clk;
        priv = sdhci_pltfm_priv(pltfm_host);
-       priv->clk = clk;
        priv->gpio_cd = gpio_cd;
 
        sdhci_get_of_property(pdev);
 
-       ret = clk_prepare_enable(priv->clk);
+       ret = clk_prepare_enable(pltfm_host->clk);
        if (ret)
                goto err_clk_prepare;
 
@@ -195,37 +187,24 @@ static int sdhci_sirf_probe(struct platform_device *pdev)
 err_request_cd:
        sdhci_remove_host(host, 0);
 err_sdhci_add:
-       clk_disable_unprepare(priv->clk);
+       clk_disable_unprepare(pltfm_host->clk);
 err_clk_prepare:
        sdhci_pltfm_free(pdev);
        return ret;
 }
 
-static int sdhci_sirf_remove(struct platform_device *pdev)
-{
-       struct sdhci_host *host = platform_get_drvdata(pdev);
-       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
-
-       sdhci_pltfm_unregister(pdev);
-
-       clk_disable_unprepare(priv->clk);
-       return 0;
-}
-
 #ifdef CONFIG_PM_SLEEP
 static int sdhci_sirf_suspend(struct device *dev)
 {
        struct sdhci_host *host = dev_get_drvdata(dev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
        int ret;
 
        ret = sdhci_suspend_host(host);
        if (ret)
                return ret;
 
-       clk_disable(priv->clk);
+       clk_disable(pltfm_host->clk);
 
        return 0;
 }
@@ -234,10 +213,9 @@ static int sdhci_sirf_resume(struct device *dev)
 {
        struct sdhci_host *host = dev_get_drvdata(dev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
        int ret;
 
-       ret = clk_enable(priv->clk);
+       ret = clk_enable(pltfm_host->clk);
        if (ret) {
                dev_dbg(dev, "Resume: Error enabling clock\n");
                return ret;
@@ -264,7 +242,7 @@ static struct platform_driver sdhci_sirf_driver = {
 #endif
        },
        .probe          = sdhci_sirf_probe,
-       .remove         = sdhci_sirf_remove,
+       .remove         = sdhci_pltfm_unregister,
 };
 
 module_platform_driver(sdhci_sirf_driver);
index 22e58268545f0b028ee3cd82d4fa7e50a49a4558..df088343d60f32413a3694813ad97f9abb57b7ae 100644 (file)
 #include <linux/pm.h>
 #include <linux/slab.h>
 #include <linux/mmc/host.h>
-#include <linux/mmc/sdhci-spear.h>
 #include <linux/mmc/slot-gpio.h>
 #include <linux/io.h>
 #include "sdhci.h"
 
 struct spear_sdhci {
        struct clk *clk;
-       struct sdhci_plat_data *data;
+       int card_int_gpio;
 };
 
 /* sdhci ops */
@@ -44,38 +43,20 @@ static const struct sdhci_ops sdhci_pltfm_ops = {
        .set_uhs_signaling = sdhci_set_uhs_signaling,
 };
 
-#ifdef CONFIG_OF
-static struct sdhci_plat_data *sdhci_probe_config_dt(struct platform_device *pdev)
+static void sdhci_probe_config_dt(struct device_node *np,
+                               struct spear_sdhci *host)
 {
-       struct device_node *np = pdev->dev.of_node;
-       struct sdhci_plat_data *pdata = NULL;
        int cd_gpio;
 
        cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
        if (!gpio_is_valid(cd_gpio))
                cd_gpio = -1;
 
-       /* If pdata is required */
-       if (cd_gpio != -1) {
-               pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-               if (!pdata)
-                       dev_err(&pdev->dev, "DT: kzalloc failed\n");
-               else
-                       pdata->card_int_gpio = cd_gpio;
-       }
-
-       return pdata;
-}
-#else
-static struct sdhci_plat_data *sdhci_probe_config_dt(struct platform_device *pdev)
-{
-       return ERR_PTR(-ENOSYS);
+       host->card_int_gpio = cd_gpio;
 }
-#endif
 
 static int sdhci_probe(struct platform_device *pdev)
 {
-       struct device_node *np = pdev->dev.of_node;
        struct sdhci_host *host;
        struct resource *iomem;
        struct spear_sdhci *sdhci;
@@ -124,28 +105,18 @@ static int sdhci_probe(struct platform_device *pdev)
                dev_dbg(&pdev->dev, "Error setting desired clk, clk=%lu\n",
                                clk_get_rate(sdhci->clk));
 
-       if (np) {
-               sdhci->data = sdhci_probe_config_dt(pdev);
-               if (IS_ERR(sdhci->data)) {
-                       dev_err(&pdev->dev, "DT: Failed to get pdata\n");
-                       goto disable_clk;
-               }
-       } else {
-               sdhci->data = dev_get_platdata(&pdev->dev);
-       }
-
+       sdhci_probe_config_dt(pdev->dev.of_node, sdhci);
        /*
         * It is optional to use GPIOs for sdhci card detection. If
-        * sdhci->data is NULL, then use original sdhci lines otherwise
+        * sdhci->card_int_gpio < 0, then use original sdhci lines otherwise
         * GPIO lines. We use the built-in GPIO support for this.
         */
-       if (sdhci->data && sdhci->data->card_int_gpio >= 0) {
-               ret = mmc_gpio_request_cd(host->mmc,
-                                         sdhci->data->card_int_gpio, 0);
+       if (sdhci->card_int_gpio >= 0) {
+               ret = mmc_gpio_request_cd(host->mmc, sdhci->card_int_gpio, 0);
                if (ret < 0) {
                        dev_dbg(&pdev->dev,
                                "failed to request card-detect gpio%d\n",
-                               sdhci->data->card_int_gpio);
+                               sdhci->card_int_gpio);
                        goto disable_clk;
                }
        }
index 882b07e9667e20d3675620152cf108fc55f2a3ae..682f2bb0f4bf3dc200ccb3bf0451a8759f1cd363 100644 (file)
 #include <linux/module.h>
 #include <linux/err.h>
 #include <linux/mmc/host.h>
-
+#include <linux/reset.h>
 #include "sdhci-pltfm.h"
 
+struct st_mmc_platform_data {
+       struct  reset_control *rstc;
+       void __iomem *top_ioaddr;
+};
+
+/* MMCSS glue logic to setup the HC on some ST SoCs (e.g. STiH407 family) */
+
+#define ST_MMC_CCONFIG_REG_1           0x400
+#define ST_MMC_CCONFIG_TIMEOUT_CLK_UNIT        BIT(24)
+#define ST_MMC_CCONFIG_TIMEOUT_CLK_FREQ        BIT(12)
+#define ST_MMC_CCONFIG_TUNING_COUNT_DEFAULT    BIT(8)
+#define ST_MMC_CCONFIG_ASYNC_WAKEUP    BIT(0)
+#define ST_MMC_CCONFIG_1_DEFAULT       \
+                               ((ST_MMC_CCONFIG_TIMEOUT_CLK_UNIT) | \
+                                (ST_MMC_CCONFIG_TIMEOUT_CLK_FREQ) | \
+                                (ST_MMC_CCONFIG_TUNING_COUNT_DEFAULT))
+
+#define ST_MMC_CCONFIG_REG_2           0x404
+#define ST_MMC_CCONFIG_HIGH_SPEED      BIT(28)
+#define ST_MMC_CCONFIG_ADMA2           BIT(24)
+#define ST_MMC_CCONFIG_8BIT            BIT(20)
+#define ST_MMC_CCONFIG_MAX_BLK_LEN     16
+#define  MAX_BLK_LEN_1024              1
+#define  MAX_BLK_LEN_2048              2
+#define BASE_CLK_FREQ_200              0xc8
+#define BASE_CLK_FREQ_100              0x64
+#define BASE_CLK_FREQ_50               0x32
+#define ST_MMC_CCONFIG_2_DEFAULT \
+       (ST_MMC_CCONFIG_HIGH_SPEED | ST_MMC_CCONFIG_ADMA2 | \
+        ST_MMC_CCONFIG_8BIT | \
+        (MAX_BLK_LEN_1024 << ST_MMC_CCONFIG_MAX_BLK_LEN))
+
+#define ST_MMC_CCONFIG_REG_3                   0x408
+#define ST_MMC_CCONFIG_EMMC_SLOT_TYPE          BIT(28)
+#define ST_MMC_CCONFIG_64BIT                   BIT(24)
+#define ST_MMC_CCONFIG_ASYNCH_INTR_SUPPORT     BIT(20)
+#define ST_MMC_CCONFIG_1P8_VOLT                        BIT(16)
+#define ST_MMC_CCONFIG_3P0_VOLT                        BIT(12)
+#define ST_MMC_CCONFIG_3P3_VOLT                        BIT(8)
+#define ST_MMC_CCONFIG_SUSP_RES_SUPPORT                BIT(4)
+#define ST_MMC_CCONFIG_SDMA                    BIT(0)
+#define ST_MMC_CCONFIG_3_DEFAULT       \
+                        (ST_MMC_CCONFIG_ASYNCH_INTR_SUPPORT    | \
+                         ST_MMC_CCONFIG_3P3_VOLT               | \
+                         ST_MMC_CCONFIG_SUSP_RES_SUPPORT       | \
+                         ST_MMC_CCONFIG_SDMA)
+
+#define ST_MMC_CCONFIG_REG_4   0x40c
+#define ST_MMC_CCONFIG_D_DRIVER        BIT(20)
+#define ST_MMC_CCONFIG_C_DRIVER        BIT(16)
+#define ST_MMC_CCONFIG_A_DRIVER        BIT(12)
+#define ST_MMC_CCONFIG_DDR50   BIT(8)
+#define ST_MMC_CCONFIG_SDR104  BIT(4)
+#define ST_MMC_CCONFIG_SDR50   BIT(0)
+#define ST_MMC_CCONFIG_4_DEFAULT       0
+
+#define ST_MMC_CCONFIG_REG_5           0x410
+#define ST_MMC_CCONFIG_TUNING_FOR_SDR50        BIT(8)
+#define RETUNING_TIMER_CNT_MAX         0xf
+#define ST_MMC_CCONFIG_5_DEFAULT       0
+
+/* I/O configuration for Arasan IP */
+#define ST_MMC_GP_OUTPUT       0x450
+#define ST_MMC_GP_OUTPUT_CD    BIT(12)
+
+#define ST_MMC_STATUS_R                0x460
+
+#define ST_TOP_MMC_DLY_FIX_OFF(x)      (x - 0x8)
+
+/* TOP config registers to manage static and dynamic delay */
+#define ST_TOP_MMC_TX_CLK_DLY                  ST_TOP_MMC_DLY_FIX_OFF(0x8)
+#define ST_TOP_MMC_RX_CLK_DLY                  ST_TOP_MMC_DLY_FIX_OFF(0xc)
+/* MMC delay control register */
+#define ST_TOP_MMC_DLY_CTRL                    ST_TOP_MMC_DLY_FIX_OFF(0x18)
+#define ST_TOP_MMC_DLY_CTRL_DLL_BYPASS_CMD     BIT(0)
+#define ST_TOP_MMC_DLY_CTRL_DLL_BYPASS_PH_SEL  BIT(1)
+#define ST_TOP_MMC_DLY_CTRL_TX_DLL_ENABLE      BIT(8)
+#define ST_TOP_MMC_DLY_CTRL_RX_DLL_ENABLE      BIT(9)
+#define ST_TOP_MMC_DLY_CTRL_ATUNE_NOT_CFG_DLY  BIT(10)
+#define ST_TOP_MMC_START_DLL_LOCK              BIT(11)
+
+/* register to provide the phase-shift value for DLL */
+#define ST_TOP_MMC_TX_DLL_STEP_DLY             ST_TOP_MMC_DLY_FIX_OFF(0x1c)
+#define ST_TOP_MMC_RX_DLL_STEP_DLY             ST_TOP_MMC_DLY_FIX_OFF(0x20)
+#define ST_TOP_MMC_RX_CMD_STEP_DLY             ST_TOP_MMC_DLY_FIX_OFF(0x24)
+
+/* phase shift delay on the tx clk 2.188ns */
+#define ST_TOP_MMC_TX_DLL_STEP_DLY_VALID       0x6
+
+#define ST_TOP_MMC_DLY_MAX                     0xf
+
+#define ST_TOP_MMC_DYN_DLY_CONF        \
+               (ST_TOP_MMC_DLY_CTRL_TX_DLL_ENABLE | \
+                ST_TOP_MMC_DLY_CTRL_ATUNE_NOT_CFG_DLY | \
+                ST_TOP_MMC_START_DLL_LOCK)
+
+/*
+ * For clock speeds greater than 90MHz, we need to check that the
+ * DLL procedure has finished before switching to ultra-speed modes.
+ */
+#define        CLK_TO_CHECK_DLL_LOCK   90000000
+
+static inline void st_mmcss_set_static_delay(void __iomem *ioaddr)
+{
+       if (!ioaddr)
+               return;
+
+       writel_relaxed(0x0, ioaddr + ST_TOP_MMC_DLY_CTRL);
+       writel_relaxed(ST_TOP_MMC_DLY_MAX,
+                       ioaddr + ST_TOP_MMC_TX_CLK_DLY);
+}
+
+/**
+ * st_mmcss_cconfig: configure the Arasan HC inside the flashSS.
+ * @np: dt device node.
+ * @host: sdhci host
+ * Description: this function is to configure the Arasan host controller.
+ * On some ST SoCs, i.e. STiH407 family, the MMC devices inside a dedicated
+ * flashSS sub-system which needs to be configured to be compliant to eMMC 4.5
+ * or eMMC4.3.  This has to be done before registering the sdhci host.
+ */
+static void st_mmcss_cconfig(struct device_node *np, struct sdhci_host *host)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct mmc_host *mhost = host->mmc;
+       u32 cconf2, cconf3, cconf4, cconf5;
+
+       if (!of_device_is_compatible(np, "st,sdhci-stih407"))
+               return;
+
+       cconf2 = ST_MMC_CCONFIG_2_DEFAULT;
+       cconf3 = ST_MMC_CCONFIG_3_DEFAULT;
+       cconf4 = ST_MMC_CCONFIG_4_DEFAULT;
+       cconf5 = ST_MMC_CCONFIG_5_DEFAULT;
+
+       writel_relaxed(ST_MMC_CCONFIG_1_DEFAULT,
+                       host->ioaddr + ST_MMC_CCONFIG_REG_1);
+
+       /* Set clock frequency, default to 50MHz if max-frequency is not
+        * provided */
+
+       switch (mhost->f_max) {
+       case 200000000:
+               clk_set_rate(pltfm_host->clk, mhost->f_max);
+               cconf2 |= BASE_CLK_FREQ_200;
+               break;
+       case 100000000:
+               clk_set_rate(pltfm_host->clk, mhost->f_max);
+               cconf2 |= BASE_CLK_FREQ_100;
+               break;
+       default:
+               clk_set_rate(pltfm_host->clk, 50000000);
+               cconf2 |= BASE_CLK_FREQ_50;
+       }
+
+       writel_relaxed(cconf2, host->ioaddr + ST_MMC_CCONFIG_REG_2);
+
+       if (mhost->caps & MMC_CAP_NONREMOVABLE)
+               cconf3 |= ST_MMC_CCONFIG_EMMC_SLOT_TYPE;
+       else
+               /* CARD _D ET_CTRL */
+               writel_relaxed(ST_MMC_GP_OUTPUT_CD,
+                               host->ioaddr + ST_MMC_GP_OUTPUT);
+
+       if (mhost->caps & MMC_CAP_UHS_SDR50) {
+               /* use 1.8V */
+               cconf3 |= ST_MMC_CCONFIG_1P8_VOLT;
+               cconf4 |= ST_MMC_CCONFIG_SDR50;
+               /* Use tuning */
+               cconf5 |= ST_MMC_CCONFIG_TUNING_FOR_SDR50;
+               /* Max timeout for retuning */
+               cconf5 |= RETUNING_TIMER_CNT_MAX;
+       }
+
+       if (mhost->caps & MMC_CAP_UHS_SDR104) {
+               /*
+                * SDR104 implies the HC can support HS200 mode, so
+                * it's mandatory to use 1.8V
+                */
+               cconf3 |= ST_MMC_CCONFIG_1P8_VOLT;
+               cconf4 |= ST_MMC_CCONFIG_SDR104;
+               /* Max timeout for retuning */
+               cconf5 |= RETUNING_TIMER_CNT_MAX;
+       }
+
+       if (mhost->caps & MMC_CAP_UHS_DDR50)
+               cconf4 |= ST_MMC_CCONFIG_DDR50;
+
+       writel_relaxed(cconf3, host->ioaddr + ST_MMC_CCONFIG_REG_3);
+       writel_relaxed(cconf4, host->ioaddr + ST_MMC_CCONFIG_REG_4);
+       writel_relaxed(cconf5, host->ioaddr + ST_MMC_CCONFIG_REG_5);
+}
+
+static inline void st_mmcss_set_dll(void __iomem *ioaddr)
+{
+       if (!ioaddr)
+               return;
+
+       writel_relaxed(ST_TOP_MMC_DYN_DLY_CONF, ioaddr + ST_TOP_MMC_DLY_CTRL);
+       writel_relaxed(ST_TOP_MMC_TX_DLL_STEP_DLY_VALID,
+                       ioaddr + ST_TOP_MMC_TX_DLL_STEP_DLY);
+}
+
+static int st_mmcss_lock_dll(void __iomem *ioaddr)
+{
+       unsigned long curr, value;
+       unsigned long finish = jiffies + HZ;
+
+       /* Checks if the DLL procedure is finished */
+       do {
+               curr = jiffies;
+               value = readl(ioaddr + ST_MMC_STATUS_R);
+               if (value & 0x1)
+                       return 0;
+
+               cpu_relax();
+       } while (!time_after_eq(curr, finish));
+
+       return -EBUSY;
+}
+
+static int sdhci_st_set_dll_for_clock(struct sdhci_host *host)
+{
+       int ret = 0;
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct st_mmc_platform_data *pdata = pltfm_host->priv;
+
+       if (host->clock > CLK_TO_CHECK_DLL_LOCK) {
+               st_mmcss_set_dll(pdata->top_ioaddr);
+               ret = st_mmcss_lock_dll(host->ioaddr);
+       }
+
+       return ret;
+}
+
+static void sdhci_st_set_uhs_signaling(struct sdhci_host *host,
+                                       unsigned int uhs)
+{
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct st_mmc_platform_data *pdata = pltfm_host->priv;
+       u16 ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+       int ret = 0;
+
+       /* Select Bus Speed Mode for host */
+       ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+       switch (uhs) {
+       /*
+        * Set V18_EN -- UHS modes do not work without this.
+        * does not change signaling voltage
+        */
+
+       case MMC_TIMING_UHS_SDR12:
+               st_mmcss_set_static_delay(pdata->top_ioaddr);
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR12 | SDHCI_CTRL_VDD_180;
+               break;
+       case MMC_TIMING_UHS_SDR25:
+               st_mmcss_set_static_delay(pdata->top_ioaddr);
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR25 | SDHCI_CTRL_VDD_180;
+               break;
+       case MMC_TIMING_UHS_SDR50:
+               st_mmcss_set_static_delay(pdata->top_ioaddr);
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180;
+               ret = sdhci_st_set_dll_for_clock(host);
+               break;
+       case MMC_TIMING_UHS_SDR104:
+       case MMC_TIMING_MMC_HS200:
+               st_mmcss_set_static_delay(pdata->top_ioaddr);
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180;
+               ret =  sdhci_st_set_dll_for_clock(host);
+               break;
+       case MMC_TIMING_UHS_DDR50:
+       case MMC_TIMING_MMC_DDR52:
+               st_mmcss_set_static_delay(pdata->top_ioaddr);
+               ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180;
+               break;
+       }
+
+       if (ret)
+               dev_warn(mmc_dev(host->mmc), "Error setting dll for clock "
+                                               "(uhs %d)\n", uhs);
+
+       dev_dbg(mmc_dev(host->mmc), "uhs %d, ctrl_2 %04X\n", uhs, ctrl_2);
+
+       sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+}
+
 static u32 sdhci_st_readl(struct sdhci_host *host, int reg)
 {
        u32 ret;
@@ -48,22 +334,33 @@ static const struct sdhci_ops sdhci_st_ops = {
        .set_bus_width = sdhci_set_bus_width,
        .read_l = sdhci_st_readl,
        .reset = sdhci_reset,
+       .set_uhs_signaling = sdhci_st_set_uhs_signaling,
 };
 
 static const struct sdhci_pltfm_data sdhci_st_pdata = {
        .ops = &sdhci_st_ops,
        .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
-           SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+               SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
+               SDHCI_QUIRK_NO_HISPD_BIT,
+       .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
+               SDHCI_QUIRK2_STOP_WITH_TC,
 };
 
 
 static int sdhci_st_probe(struct platform_device *pdev)
 {
+       struct device_node *np = pdev->dev.of_node;
        struct sdhci_host *host;
+       struct st_mmc_platform_data *pdata;
        struct sdhci_pltfm_host *pltfm_host;
        struct clk *clk;
        int ret = 0;
        u16 host_version;
+       struct resource *res;
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
 
        clk =  devm_clk_get(&pdev->dev, "mmc");
        if (IS_ERR(clk)) {
@@ -71,10 +368,17 @@ static int sdhci_st_probe(struct platform_device *pdev)
                return PTR_ERR(clk);
        }
 
+       pdata->rstc = devm_reset_control_get(&pdev->dev, NULL);
+       if (IS_ERR(pdata->rstc))
+               pdata->rstc = NULL;
+       else
+               reset_control_deassert(pdata->rstc);
+
        host = sdhci_pltfm_init(pdev, &sdhci_st_pdata, 0);
        if (IS_ERR(host)) {
                dev_err(&pdev->dev, "Failed sdhci_pltfm_init\n");
-               return PTR_ERR(host);
+               ret = PTR_ERR(host);
+               goto err_pltfm_init;
        }
 
        ret = mmc_of_parse(host->mmc);
@@ -85,9 +389,22 @@ static int sdhci_st_probe(struct platform_device *pdev)
 
        clk_prepare_enable(clk);
 
+       /* Configure the FlashSS Top registers for setting eMMC TX/RX delay */
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                          "top-mmc-delay");
+       pdata->top_ioaddr = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(pdata->top_ioaddr)) {
+               dev_warn(&pdev->dev, "FlashSS Top Dly registers not available");
+               pdata->top_ioaddr = NULL;
+       }
+
        pltfm_host = sdhci_priv(host);
+       pltfm_host->priv = pdata;
        pltfm_host->clk = clk;
 
+       /* Configure the Arasan HC inside the flashSS */
+       st_mmcss_cconfig(np, host);
+
        ret = sdhci_add_host(host);
        if (ret) {
                dev_err(&pdev->dev, "Failed sdhci_add_host\n");
@@ -109,6 +426,9 @@ err_out:
        clk_disable_unprepare(clk);
 err_of:
        sdhci_pltfm_free(pdev);
+err_pltfm_init:
+       if (pdata->rstc)
+               reset_control_assert(pdata->rstc);
 
        return ret;
 }
@@ -117,10 +437,15 @@ static int sdhci_st_remove(struct platform_device *pdev)
 {
        struct sdhci_host *host = platform_get_drvdata(pdev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct st_mmc_platform_data *pdata = pltfm_host->priv;
+       int ret;
 
-       clk_disable_unprepare(pltfm_host->clk);
+       ret = sdhci_pltfm_unregister(pdev);
+
+       if (pdata->rstc)
+               reset_control_assert(pdata->rstc);
 
-       return sdhci_pltfm_unregister(pdev);
+       return ret;
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -128,11 +453,15 @@ static int sdhci_st_suspend(struct device *dev)
 {
        struct sdhci_host *host = dev_get_drvdata(dev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct st_mmc_platform_data *pdata = pltfm_host->priv;
        int ret = sdhci_suspend_host(host);
 
        if (ret)
                goto out;
 
+       if (pdata->rstc)
+               reset_control_assert(pdata->rstc);
+
        clk_disable_unprepare(pltfm_host->clk);
 out:
        return ret;
@@ -142,9 +471,16 @@ static int sdhci_st_resume(struct device *dev)
 {
        struct sdhci_host *host = dev_get_drvdata(dev);
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct st_mmc_platform_data *pdata = pltfm_host->priv;
+       struct device_node *np = dev->of_node;
 
        clk_prepare_enable(pltfm_host->clk);
 
+       if (pdata->rstc)
+               reset_control_deassert(pdata->rstc);
+
+       st_mmcss_cconfig(np, host);
+
        return sdhci_resume_host(host);
 }
 #endif
index f3778d58d1cd42031663b92144deb3fd42723755..ad28b49f0203f5d734ef7325aba081c4c4b5ce4e 100644 (file)
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/of_gpio.h>
-#include <linux/gpio.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/slot-gpio.h>
+#include <linux/gpio/consumer.h>
 
 #include "sdhci-pltfm.h"
 
@@ -41,7 +40,6 @@
 #define NVQUIRK_DISABLE_SDR50          BIT(3)
 #define NVQUIRK_DISABLE_SDR104         BIT(4)
 #define NVQUIRK_DISABLE_DDR50          BIT(5)
-#define NVQUIRK_SHADOW_XFER_MODE_REG   BIT(6)
 
 struct sdhci_tegra_soc_data {
        const struct sdhci_pltfm_data *pdata;
@@ -50,7 +48,7 @@ struct sdhci_tegra_soc_data {
 
 struct sdhci_tegra {
        const struct sdhci_tegra_soc_data *soc_data;
-       int power_gpio;
+       struct gpio_desc *power_gpio;
 };
 
 static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
@@ -71,23 +69,19 @@ static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
 static void tegra_sdhci_writew(struct sdhci_host *host, u16 val, int reg)
 {
        struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct sdhci_tegra *tegra_host = pltfm_host->priv;
-       const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
 
-       if (soc_data->nvquirks & NVQUIRK_SHADOW_XFER_MODE_REG) {
-               switch (reg) {
-               case SDHCI_TRANSFER_MODE:
-                       /*
-                        * Postpone this write, we must do it together with a
-                        * command write that is down below.
-                        */
-                       pltfm_host->xfer_mode_shadow = val;
-                       return;
-               case SDHCI_COMMAND:
-                       writel((val << 16) | pltfm_host->xfer_mode_shadow,
-                               host->ioaddr + SDHCI_TRANSFER_MODE);
-                       return;
-               }
+       switch (reg) {
+       case SDHCI_TRANSFER_MODE:
+               /*
+                * Postpone this write, we must do it together with a
+                * command write that is down below.
+                */
+               pltfm_host->xfer_mode_shadow = val;
+               return;
+       case SDHCI_COMMAND:
+               writel((val << 16) | pltfm_host->xfer_mode_shadow,
+                       host->ioaddr + SDHCI_TRANSFER_MODE);
+               return;
        }
 
        writew(val, host->ioaddr + reg);
@@ -173,7 +167,6 @@ static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width)
 static const struct sdhci_ops tegra_sdhci_ops = {
        .get_ro     = tegra_sdhci_get_ro,
        .read_w     = tegra_sdhci_readw,
-       .write_w    = tegra_sdhci_writew,
        .write_l    = tegra_sdhci_writel,
        .set_clock  = sdhci_set_clock,
        .set_bus_width = tegra_sdhci_set_bus_width,
@@ -214,6 +207,18 @@ static struct sdhci_tegra_soc_data soc_data_tegra30 = {
                    NVQUIRK_DISABLE_SDR104,
 };
 
+static const struct sdhci_ops tegra114_sdhci_ops = {
+       .get_ro     = tegra_sdhci_get_ro,
+       .read_w     = tegra_sdhci_readw,
+       .write_w    = tegra_sdhci_writew,
+       .write_l    = tegra_sdhci_writel,
+       .set_clock  = sdhci_set_clock,
+       .set_bus_width = tegra_sdhci_set_bus_width,
+       .reset      = tegra_sdhci_reset,
+       .set_uhs_signaling = sdhci_set_uhs_signaling,
+       .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+};
+
 static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {
        .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
                  SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
@@ -221,15 +226,14 @@ static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {
                  SDHCI_QUIRK_NO_HISPD_BIT |
                  SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
                  SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
-       .ops  = &tegra_sdhci_ops,
+       .ops  = &tegra114_sdhci_ops,
 };
 
 static struct sdhci_tegra_soc_data soc_data_tegra114 = {
        .pdata = &sdhci_tegra114_pdata,
        .nvquirks = NVQUIRK_DISABLE_SDR50 |
                    NVQUIRK_DISABLE_DDR50 |
-                   NVQUIRK_DISABLE_SDR104 |
-                   NVQUIRK_SHADOW_XFER_MODE_REG,
+                   NVQUIRK_DISABLE_SDR104,
 };
 
 static const struct of_device_id sdhci_tegra_dt_match[] = {
@@ -241,17 +245,6 @@ static const struct of_device_id sdhci_tegra_dt_match[] = {
 };
 MODULE_DEVICE_TABLE(of, sdhci_tegra_dt_match);
 
-static int sdhci_tegra_parse_dt(struct device *dev)
-{
-       struct device_node *np = dev->of_node;
-       struct sdhci_host *host = dev_get_drvdata(dev);
-       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct sdhci_tegra *tegra_host = pltfm_host->priv;
-
-       tegra_host->power_gpio = of_get_named_gpio(np, "power-gpios", 0);
-       return mmc_of_parse(host->mmc);
-}
-
 static int sdhci_tegra_probe(struct platform_device *pdev)
 {
        const struct of_device_id *match;
@@ -281,21 +274,18 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
        tegra_host->soc_data = soc_data;
        pltfm_host->priv = tegra_host;
 
-       rc = sdhci_tegra_parse_dt(&pdev->dev);
+       rc = mmc_of_parse(host->mmc);
        if (rc)
                goto err_parse_dt;
 
-       if (gpio_is_valid(tegra_host->power_gpio)) {
-               rc = gpio_request(tegra_host->power_gpio, "sdhci_power");
-               if (rc) {
-                       dev_err(mmc_dev(host->mmc),
-                               "failed to allocate power gpio\n");
-                       goto err_power_req;
-               }
-               gpio_direction_output(tegra_host->power_gpio, 1);
+       tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power",
+                                                        GPIOD_OUT_HIGH);
+       if (IS_ERR(tegra_host->power_gpio)) {
+               rc = PTR_ERR(tegra_host->power_gpio);
+               goto err_power_req;
        }
 
-       clk = clk_get(mmc_dev(host->mmc), NULL);
+       clk = devm_clk_get(mmc_dev(host->mmc), NULL);
        if (IS_ERR(clk)) {
                dev_err(mmc_dev(host->mmc), "clk err\n");
                rc = PTR_ERR(clk);
@@ -312,10 +302,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
 
 err_add_host:
        clk_disable_unprepare(pltfm_host->clk);
-       clk_put(pltfm_host->clk);
 err_clk_get:
-       if (gpio_is_valid(tegra_host->power_gpio))
-               gpio_free(tegra_host->power_gpio);
 err_power_req:
 err_parse_dt:
 err_alloc_tegra_host:
@@ -323,26 +310,6 @@ err_alloc_tegra_host:
        return rc;
 }
 
-static int sdhci_tegra_remove(struct platform_device *pdev)
-{
-       struct sdhci_host *host = platform_get_drvdata(pdev);
-       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
-       struct sdhci_tegra *tegra_host = pltfm_host->priv;
-       int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
-
-       sdhci_remove_host(host, dead);
-
-       if (gpio_is_valid(tegra_host->power_gpio))
-               gpio_free(tegra_host->power_gpio);
-
-       clk_disable_unprepare(pltfm_host->clk);
-       clk_put(pltfm_host->clk);
-
-       sdhci_pltfm_free(pdev);
-
-       return 0;
-}
-
 static struct platform_driver sdhci_tegra_driver = {
        .driver         = {
                .name   = "sdhci-tegra",
@@ -350,7 +317,7 @@ static struct platform_driver sdhci_tegra_driver = {
                .pm     = SDHCI_PLTFM_PMOPS,
        },
        .probe          = sdhci_tegra_probe,
-       .remove         = sdhci_tegra_remove,
+       .remove         = sdhci_pltfm_unregister,
 };
 
 module_platform_driver(sdhci_tegra_driver);
index 0ad412a4876fae403a1a2cdd1a75e7761c809fac..c80287a027356e079e366401c2d5f64d9967461b 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/sdio.h>
 #include <linux/mmc/slot-gpio.h>
 
 #include "sdhci.h"
@@ -56,6 +57,7 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
 static int sdhci_pre_dma_transfer(struct sdhci_host *host,
                                        struct mmc_data *data,
                                        struct sdhci_host_next *next);
+static int sdhci_do_get_cd(struct sdhci_host *host);
 
 #ifdef CONFIG_PM
 static int sdhci_runtime_pm_get(struct sdhci_host *host);
@@ -931,7 +933,8 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
                 * If we are sending CMD23, CMD12 never gets sent
                 * on successful completion (so no Auto-CMD12).
                 */
-               if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12))
+               if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12) &&
+                   (cmd->opcode != SD_IO_RW_EXTENDED))
                        mode |= SDHCI_TRNS_AUTO_CMD12;
                else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
                        mode |= SDHCI_TRNS_AUTO_CMD23;
@@ -1356,7 +1359,8 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
        sdhci_runtime_pm_get(host);
 
-       present = mmc_gpio_get_cd(host->mmc);
+       /* Firstly check card presence */
+       present = sdhci_do_get_cd(host);
 
        spin_lock_irqsave(&host->lock, flags);
 
@@ -1379,22 +1383,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
        host->mrq = mrq;
 
-       /*
-        * Firstly check card presence from cd-gpio.  The return could
-        * be one of the following possibilities:
-        *     negative: cd-gpio is not available
-        *     zero: cd-gpio is used, and card is removed
-        *     one: cd-gpio is used, and card is present
-        */
-       if (present < 0) {
-               /* If polling, assume that the card is always present. */
-               if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
-                       present = 1;
-               else
-                       present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
-                                       SDHCI_CARD_PRESENT;
-       }
-
        if (!present || host->flags & SDHCI_DEVICE_DEAD) {
                host->mrq->cmd->error = -ENOMEDIUM;
                tasklet_schedule(&host->finish_tasklet);
@@ -3164,7 +3152,8 @@ int sdhci_add_host(struct sdhci_host *host)
        /* Auto-CMD23 stuff only works in ADMA or PIO. */
        if ((host->version >= SDHCI_SPEC_300) &&
            ((host->flags & SDHCI_USE_ADMA) ||
-            !(host->flags & SDHCI_USE_SDMA))) {
+            !(host->flags & SDHCI_USE_SDMA)) &&
+            !(host->quirks2 & SDHCI_QUIRK2_ACMD23_BROKEN)) {
                host->flags |= SDHCI_AUTO_CMD23;
                DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc));
        } else {
index 0315e1844330c4d0a70616c7525899eca57204a4..e639b7f435e564f6f8a56dc22a6747d23939c8f2 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/types.h>
 #include <linux/io.h>
 
-#include <linux/mmc/sdhci.h>
+#include <linux/mmc/host.h>
 
 /*
  * Controller registers
@@ -309,6 +309,207 @@ struct sdhci_adma2_64_desc {
  */
 #define SDHCI_MAX_SEGS         128
 
+struct sdhci_host_next {
+       unsigned int    sg_count;
+       s32             cookie;
+};
+
+struct sdhci_host {
+       /* Data set by hardware interface driver */
+       const char *hw_name;    /* Hardware bus name */
+
+       unsigned int quirks;    /* Deviations from spec. */
+
+/* Controller doesn't honor resets unless we touch the clock register */
+#define SDHCI_QUIRK_CLOCK_BEFORE_RESET                 (1<<0)
+/* Controller has bad caps bits, but really supports DMA */
+#define SDHCI_QUIRK_FORCE_DMA                          (1<<1)
+/* Controller doesn't like to be reset when there is no card inserted. */
+#define SDHCI_QUIRK_NO_CARD_NO_RESET                   (1<<2)
+/* Controller doesn't like clearing the power reg before a change */
+#define SDHCI_QUIRK_SINGLE_POWER_WRITE                 (1<<3)
+/* Controller has flaky internal state so reset it on each ios change */
+#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS              (1<<4)
+/* Controller has an unusable DMA engine */
+#define SDHCI_QUIRK_BROKEN_DMA                         (1<<5)
+/* Controller has an unusable ADMA engine */
+#define SDHCI_QUIRK_BROKEN_ADMA                                (1<<6)
+/* Controller can only DMA from 32-bit aligned addresses */
+#define SDHCI_QUIRK_32BIT_DMA_ADDR                     (1<<7)
+/* Controller can only DMA chunk sizes that are a multiple of 32 bits */
+#define SDHCI_QUIRK_32BIT_DMA_SIZE                     (1<<8)
+/* Controller can only ADMA chunks that are a multiple of 32 bits */
+#define SDHCI_QUIRK_32BIT_ADMA_SIZE                    (1<<9)
+/* Controller needs to be reset after each request to stay stable */
+#define SDHCI_QUIRK_RESET_AFTER_REQUEST                        (1<<10)
+/* Controller needs voltage and power writes to happen separately */
+#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER            (1<<11)
+/* Controller provides an incorrect timeout value for transfers */
+#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL                 (1<<12)
+/* Controller has an issue with buffer bits for small transfers */
+#define SDHCI_QUIRK_BROKEN_SMALL_PIO                   (1<<13)
+/* Controller does not provide transfer-complete interrupt when not busy */
+#define SDHCI_QUIRK_NO_BUSY_IRQ                                (1<<14)
+/* Controller has unreliable card detection */
+#define SDHCI_QUIRK_BROKEN_CARD_DETECTION              (1<<15)
+/* Controller reports inverted write-protect state */
+#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT             (1<<16)
+/* Controller does not like fast PIO transfers */
+#define SDHCI_QUIRK_PIO_NEEDS_DELAY                    (1<<18)
+/* Controller has to be forced to use block size of 2048 bytes */
+#define SDHCI_QUIRK_FORCE_BLK_SZ_2048                  (1<<20)
+/* Controller cannot do multi-block transfers */
+#define SDHCI_QUIRK_NO_MULTIBLOCK                      (1<<21)
+/* Controller can only handle 1-bit data transfers */
+#define SDHCI_QUIRK_FORCE_1_BIT_DATA                   (1<<22)
+/* Controller needs 10ms delay between applying power and clock */
+#define SDHCI_QUIRK_DELAY_AFTER_POWER                  (1<<23)
+/* Controller uses SDCLK instead of TMCLK for data timeouts */
+#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK            (1<<24)
+/* Controller reports wrong base clock capability */
+#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN              (1<<25)
+/* Controller cannot support End Attribute in NOP ADMA descriptor */
+#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC              (1<<26)
+/* Controller is missing device caps. Use caps provided by host */
+#define SDHCI_QUIRK_MISSING_CAPS                       (1<<27)
+/* Controller uses Auto CMD12 command to stop the transfer */
+#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12             (1<<28)
+/* Controller doesn't have HISPD bit field in HI-SPEED SD card */
+#define SDHCI_QUIRK_NO_HISPD_BIT                       (1<<29)
+/* Controller treats ADMA descriptors with length 0000h incorrectly */
+#define SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC           (1<<30)
+/* The read-only detection via SDHCI_PRESENT_STATE register is unstable */
+#define SDHCI_QUIRK_UNSTABLE_RO_DETECT                 (1<<31)
+
+       unsigned int quirks2;   /* More deviations from spec. */
+
+#define SDHCI_QUIRK2_HOST_OFF_CARD_ON                  (1<<0)
+#define SDHCI_QUIRK2_HOST_NO_CMD23                     (1<<1)
+/* The system physically doesn't support 1.8v, even if the host does */
+#define SDHCI_QUIRK2_NO_1_8_V                          (1<<2)
+#define SDHCI_QUIRK2_PRESET_VALUE_BROKEN               (1<<3)
+#define SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON              (1<<4)
+/* Controller has a non-standard host control register */
+#define SDHCI_QUIRK2_BROKEN_HOST_CONTROL               (1<<5)
+/* Controller does not support HS200 */
+#define SDHCI_QUIRK2_BROKEN_HS200                      (1<<6)
+/* Controller does not support DDR50 */
+#define SDHCI_QUIRK2_BROKEN_DDR50                      (1<<7)
+/* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */
+#define SDHCI_QUIRK2_STOP_WITH_TC                      (1<<8)
+/* Controller does not support 64-bit DMA */
+#define SDHCI_QUIRK2_BROKEN_64_BIT_DMA                 (1<<9)
+/* need clear transfer mode register before send cmd */
+#define SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD (1<<10)
+/* Capability register bit-63 indicates HS400 support */
+#define SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400              (1<<11)
+/* forced tuned clock */
+#define SDHCI_QUIRK2_TUNING_WORK_AROUND                        (1<<12)
+/* disable the block count for single block transactions */
+#define SDHCI_QUIRK2_SUPPORT_SINGLE                    (1<<13)
+/* Controller broken with using ACMD23 */
+#define SDHCI_QUIRK2_ACMD23_BROKEN                     (1<<14)
+
+       int irq;                /* Device IRQ */
+       void __iomem *ioaddr;   /* Mapped address */
+
+       const struct sdhci_ops *ops;    /* Low level hw interface */
+
+       /* Internal data */
+       struct mmc_host *mmc;   /* MMC structure */
+       u64 dma_mask;           /* custom DMA mask */
+
+#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
+       struct led_classdev led;        /* LED control */
+       char led_name[32];
+#endif
+
+       spinlock_t lock;        /* Mutex */
+
+       int flags;              /* Host attributes */
+#define SDHCI_USE_SDMA         (1<<0)  /* Host is SDMA capable */
+#define SDHCI_USE_ADMA         (1<<1)  /* Host is ADMA capable */
+#define SDHCI_REQ_USE_DMA      (1<<2)  /* Use DMA for this req. */
+#define SDHCI_DEVICE_DEAD      (1<<3)  /* Device unresponsive */
+#define SDHCI_SDR50_NEEDS_TUNING (1<<4)        /* SDR50 needs tuning */
+#define SDHCI_NEEDS_RETUNING   (1<<5)  /* Host needs retuning */
+#define SDHCI_AUTO_CMD12       (1<<6)  /* Auto CMD12 support */
+#define SDHCI_AUTO_CMD23       (1<<7)  /* Auto CMD23 support */
+#define SDHCI_PV_ENABLED       (1<<8)  /* Preset value enabled */
+#define SDHCI_SDIO_IRQ_ENABLED (1<<9)  /* SDIO irq enabled */
+#define SDHCI_SDR104_NEEDS_TUNING (1<<10)      /* SDR104/HS200 needs tuning */
+#define SDHCI_USING_RETUNING_TIMER (1<<11)     /* Host is using a retuning timer for the card */
+#define SDHCI_USE_64_BIT_DMA   (1<<12) /* Use 64-bit DMA */
+#define SDHCI_HS400_TUNING     (1<<13) /* Tuning for HS400 */
+
+       unsigned int version;   /* SDHCI spec. version */
+
+       unsigned int max_clk;   /* Max possible freq (MHz) */
+       unsigned int timeout_clk;       /* Timeout freq (KHz) */
+       unsigned int clk_mul;   /* Clock Muliplier value */
+
+       unsigned int clock;     /* Current clock (MHz) */
+       u8 pwr;                 /* Current voltage */
+
+       bool runtime_suspended; /* Host is runtime suspended */
+       bool bus_on;            /* Bus power prevents runtime suspend */
+       bool preset_enabled;    /* Preset is enabled */
+
+       struct mmc_request *mrq;        /* Current request */
+       struct mmc_command *cmd;        /* Current command */
+       struct mmc_data *data;  /* Current data request */
+       unsigned int data_early:1;      /* Data finished before cmd */
+       unsigned int busy_handle:1;     /* Handling the order of Busy-end */
+
+       struct sg_mapping_iter sg_miter;        /* SG state for PIO */
+       unsigned int blocks;    /* remaining PIO blocks */
+
+       int sg_count;           /* Mapped sg entries */
+
+       void *adma_table;       /* ADMA descriptor table */
+       void *align_buffer;     /* Bounce buffer */
+
+       size_t adma_table_sz;   /* ADMA descriptor table size */
+       size_t align_buffer_sz; /* Bounce buffer size */
+
+       dma_addr_t adma_addr;   /* Mapped ADMA descr. table */
+       dma_addr_t align_addr;  /* Mapped bounce buffer */
+
+       unsigned int desc_sz;   /* ADMA descriptor size */
+       unsigned int align_sz;  /* ADMA alignment */
+       unsigned int align_mask;        /* ADMA alignment mask */
+
+       struct tasklet_struct finish_tasklet;   /* Tasklet structures */
+
+       struct timer_list timer;        /* Timer for timeouts */
+
+       u32 caps;               /* Alternative CAPABILITY_0 */
+       u32 caps1;              /* Alternative CAPABILITY_1 */
+
+       unsigned int            ocr_avail_sdio; /* OCR bit masks */
+       unsigned int            ocr_avail_sd;
+       unsigned int            ocr_avail_mmc;
+       u32 ocr_mask;           /* available voltages */
+
+       unsigned                timing;         /* Current timing */
+
+       u32                     thread_isr;
+
+       /* cached registers */
+       u32                     ier;
+
+       wait_queue_head_t       buf_ready_int;  /* Waitqueue for Buffer Read Ready interrupt */
+       unsigned int            tuning_done;    /* Condition flag set when CMD19 succeeds */
+
+       unsigned int            tuning_count;   /* Timer count for re-tuning */
+       unsigned int            tuning_mode;    /* Re-tuning mode supported by host */
+#define SDHCI_TUNING_MODE_1    0
+       struct timer_list       tuning_timer;   /* Timer for tuning */
+
+       struct sdhci_host_next  next_data;
+       unsigned long private[0] ____cacheline_aligned;
+};
+
 struct sdhci_ops {
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
        u32             (*read_l)(struct sdhci_host *host, int reg);
index 7d9d6a3215210f537b1b6e46070b610320f80ff5..072f67066df38e8d60d4eb0d1f5bc656947fa1fa 100644 (file)
@@ -875,6 +875,7 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
        struct mmc_command *cmd = mrq->cmd;
        u32 opc = cmd->opcode;
        u32 mask;
+       unsigned long flags;
 
        switch (opc) {
        /* response busy check */
@@ -909,10 +910,12 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
        /* set arg */
        sh_mmcif_writel(host->addr, MMCIF_CE_ARG, cmd->arg);
        /* set cmd */
+       spin_lock_irqsave(&host->lock, flags);
        sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc);
 
        host->wait_for = MMCIF_WAIT_FOR_CMD;
        schedule_delayed_work(&host->timeout_work, host->timeout);
+       spin_unlock_irqrestore(&host->lock, flags);
 }
 
 static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
@@ -1171,6 +1174,12 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
        struct sh_mmcif_host *host = dev_id;
        struct mmc_request *mrq;
        bool wait = false;
+       unsigned long flags;
+       int wait_work;
+
+       spin_lock_irqsave(&host->lock, flags);
+       wait_work = host->wait_for;
+       spin_unlock_irqrestore(&host->lock, flags);
 
        cancel_delayed_work_sync(&host->timeout_work);
 
@@ -1188,7 +1197,7 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
         * All handlers return true, if processing continues, and false, if the
         * request has to be completed - successfully or not
         */
-       switch (host->wait_for) {
+       switch (wait_work) {
        case MMCIF_WAIT_FOR_REQUEST:
                /* We're too late, the timeout has already kicked in */
                mutex_unlock(&host->thread_lock);
@@ -1312,15 +1321,15 @@ static void mmcif_timeout_work(struct work_struct *work)
                /* Don't run after mmc_remove_host() */
                return;
 
-       dev_err(&host->pd->dev, "Timeout waiting for %u on CMD%u\n",
-               host->wait_for, mrq->cmd->opcode);
-
        spin_lock_irqsave(&host->lock, flags);
        if (host->state == STATE_IDLE) {
                spin_unlock_irqrestore(&host->lock, flags);
                return;
        }
 
+       dev_err(&host->pd->dev, "Timeout waiting for %u on CMD%u\n",
+               host->wait_for, mrq->cmd->opcode);
+
        host->state = STATE_TIMEOUT;
        spin_unlock_irqrestore(&host->lock, flags);
 
index e8a4218b57267f508eb871f216de112e93707d31..4d3e1ffe5508273fc1f9f91b7b5c3218bed1ea07 100644 (file)
@@ -293,7 +293,7 @@ static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host,
                                    struct mmc_data *data)
 {
        struct sunxi_idma_des *pdes = (struct sunxi_idma_des *)host->sg_cpu;
-       struct sunxi_idma_des *pdes_pa = (struct sunxi_idma_des *)host->sg_dma;
+       dma_addr_t next_desc = host->sg_dma;
        int i, max_len = (1 << host->idma_des_size_bits);
 
        for (i = 0; i < data->sg_len; i++) {
@@ -305,8 +305,9 @@ static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host,
                else
                        pdes[i].buf_size = data->sg[i].length;
 
+               next_desc += sizeof(struct sunxi_idma_des);
                pdes[i].buf_addr_ptr1 = sg_dma_address(&data->sg[i]);
-               pdes[i].buf_addr_ptr2 = (u32)&pdes_pa[i + 1];
+               pdes[i].buf_addr_ptr2 = (u32)next_desc;
        }
 
        pdes[0].config |= SDXC_IDMAC_DES0_FD;
@@ -930,7 +931,9 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
                return PTR_ERR(host->clk_sample);
        }
 
-       host->reset = devm_reset_control_get(&pdev->dev, "ahb");
+       host->reset = devm_reset_control_get_optional(&pdev->dev, "ahb");
+       if (PTR_ERR(host->reset) == -EPROBE_DEFER)
+               return PTR_ERR(host->reset);
 
        ret = clk_prepare_enable(host->clk_ahb);
        if (ret) {
@@ -1028,7 +1031,7 @@ static int sunxi_mmc_probe(struct platform_device *pdev)
        mmc->f_min              =   400000;
        mmc->f_max              = 50000000;
        mmc->caps              |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
-                                 MMC_CAP_ERASE;
+                                 MMC_CAP_ERASE | MMC_CAP_SDIO_IRQ;
 
        ret = mmc_of_parse(mmc);
        if (ret)
index a31c3573d386f8c6f0a9f4e2143a623081d1d636..dba7e1c19dd758e784f31c89afe7dafc66334a06 100644 (file)
@@ -1073,8 +1073,6 @@ EXPORT_SYMBOL(tmio_mmc_host_alloc);
 void tmio_mmc_host_free(struct tmio_mmc_host *host)
 {
        mmc_free_host(host->mmc);
-
-       host->mmc = NULL;
 }
 EXPORT_SYMBOL(tmio_mmc_host_free);
 
index dd2e1aa95ba3fa4c999bfb25dc9fd3a7d3f08982..5af00559e9d6f7f933bccd41db4e3dc334a41673 100644 (file)
@@ -744,7 +744,7 @@ static struct wmt_mci_caps wm8505_caps = {
        .max_blk_size = 2048,
 };
 
-static struct of_device_id wmt_mci_dt_ids[] = {
+static const struct of_device_id wmt_mci_dt_ids[] = {
        { .compatible = "wm,wm8505-sdhc", .data = &wm8505_caps },
        { /* Sentinel */ },
 };
index 160448f920acd443327be8fa4a2c70cd7c736134..de722d4e9d61b9a1e30e4e80f0bb7630acec9459 100644 (file)
@@ -79,7 +79,7 @@ struct mmc_command {
 #define mmc_cmd_type(cmd)      ((cmd)->flags & MMC_CMD_MASK)
 
        unsigned int            retries;        /* max number of retries */
-       unsigned int            error;          /* command error */
+       int                     error;          /* command error */
 
 /*
  * Standard errno values are used for errors, but some have specific
@@ -108,7 +108,7 @@ struct mmc_data {
        unsigned int            timeout_clks;   /* data timeout (in clocks) */
        unsigned int            blksz;          /* data block size */
        unsigned int            blocks;         /* number of blocks */
-       unsigned int            error;          /* data error */
+       int                     error;          /* data error */
        unsigned int            flags;
 
 #define MMC_DATA_WRITE (1 << 8)
index 471fb3116dbee5afb3b9fb89325de6a51699fca3..12111993a3175ede2a43a0c061f5cbaf01b50abf 100644 (file)
@@ -44,6 +44,7 @@ struct mmc_data;
  * struct dw_mci - MMC controller state shared between all slots
  * @lock: Spinlock protecting the queue and associated data.
  * @regs: Pointer to MMIO registers.
+ * @fifo_reg: Pointer to MMIO registers for data FIFO
  * @sg: Scatterlist entry currently being processed by PIO code, if any.
  * @sg_miter: PIO mapping scatterlist iterator.
  * @cur_slot: The slot which is currently using the controller.
@@ -79,7 +80,6 @@ struct mmc_data;
  * @current_speed: Configured rate of the controller.
  * @num_slots: Number of slots available.
  * @verid: Denote Version ID.
- * @data_offset: Set the offset of DATA register according to VERID.
  * @dev: Device associated with the MMC controller.
  * @pdata: Platform data associated with the MMC controller.
  * @drv_data: Driver specific data for identified variant of the controller
@@ -132,6 +132,7 @@ struct dw_mci {
        spinlock_t              lock;
        spinlock_t              irq_lock;
        void __iomem            *regs;
+       void __iomem            *fifo_reg;
 
        struct scatterlist      *sg;
        struct sg_mapping_iter  sg_miter;
@@ -172,7 +173,6 @@ struct dw_mci {
        u32                     num_slots;
        u32                     fifoth_val;
        u16                     verid;
-       u16                     data_offset;
        struct device           *dev;
        struct dw_mci_board     *pdata;
        const struct dw_mci_drv_data    *drv_data;
@@ -202,6 +202,8 @@ struct dw_mci {
        int                     irq;
 
        int                     sdio_id0;
+
+       struct timer_list       cmd11_timer;
 };
 
 /* DMA ops for Internal/External DMAC interface */
index 0c8cbe5d155023358f8fafea9b68caca91802aa2..b5bedaec6223679bc00a25af801c1ae57ff17ad2 100644 (file)
@@ -79,12 +79,6 @@ struct mmc_ios {
 };
 
 struct mmc_host_ops {
-       /*
-        * 'enable' is called when the host is claimed and 'disable' is called
-        * when the host is released. 'enable' and 'disable' are deprecated.
-        */
-       int (*enable)(struct mmc_host *host);
-       int (*disable)(struct mmc_host *host);
        /*
         * It is optional for the host to implement pre_req and post_req in
         * order to support double buffering of requests (prepare one
diff --git a/include/linux/mmc/sdhci-spear.h b/include/linux/mmc/sdhci-spear.h
deleted file mode 100644 (file)
index 8cc095a..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * include/linux/mmc/sdhci-spear.h
- *
- * SDHCI declarations specific to ST SPEAr platform
- *
- * Copyright (C) 2010 ST Microelectronics
- * Viresh Kumar <viresh.linux@gmail.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef LINUX_MMC_SDHCI_SPEAR_H
-#define LINUX_MMC_SDHCI_SPEAR_H
-
-#include <linux/platform_device.h>
-/*
- * struct sdhci_plat_data: spear sdhci platform data structure
- *
- * card_int_gpio: gpio pin used for card detection
- */
-struct sdhci_plat_data {
-       int card_int_gpio;
-};
-
-/* This function is used to set platform_data field of pdev->dev */
-static inline void
-sdhci_set_plat_data(struct platform_device *pdev, struct sdhci_plat_data *data)
-{
-       pdev->dev.platform_data = data;
-}
-
-#endif /* LINUX_MMC_SDHCI_SPEAR_H */
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
deleted file mode 100644 (file)
index c3e3db1..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- *  linux/include/linux/mmc/sdhci.h - Secure Digital Host Controller Interface
- *
- *  Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- */
-#ifndef LINUX_MMC_SDHCI_H
-#define LINUX_MMC_SDHCI_H
-
-#include <linux/scatterlist.h>
-#include <linux/compiler.h>
-#include <linux/types.h>
-#include <linux/io.h>
-#include <linux/mmc/host.h>
-
-struct sdhci_host_next {
-       unsigned int    sg_count;
-       s32             cookie;
-};
-
-struct sdhci_host {
-       /* Data set by hardware interface driver */
-       const char *hw_name;    /* Hardware bus name */
-
-       unsigned int quirks;    /* Deviations from spec. */
-
-/* Controller doesn't honor resets unless we touch the clock register */
-#define SDHCI_QUIRK_CLOCK_BEFORE_RESET                 (1<<0)
-/* Controller has bad caps bits, but really supports DMA */
-#define SDHCI_QUIRK_FORCE_DMA                          (1<<1)
-/* Controller doesn't like to be reset when there is no card inserted. */
-#define SDHCI_QUIRK_NO_CARD_NO_RESET                   (1<<2)
-/* Controller doesn't like clearing the power reg before a change */
-#define SDHCI_QUIRK_SINGLE_POWER_WRITE                 (1<<3)
-/* Controller has flaky internal state so reset it on each ios change */
-#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS              (1<<4)
-/* Controller has an unusable DMA engine */
-#define SDHCI_QUIRK_BROKEN_DMA                         (1<<5)
-/* Controller has an unusable ADMA engine */
-#define SDHCI_QUIRK_BROKEN_ADMA                                (1<<6)
-/* Controller can only DMA from 32-bit aligned addresses */
-#define SDHCI_QUIRK_32BIT_DMA_ADDR                     (1<<7)
-/* Controller can only DMA chunk sizes that are a multiple of 32 bits */
-#define SDHCI_QUIRK_32BIT_DMA_SIZE                     (1<<8)
-/* Controller can only ADMA chunks that are a multiple of 32 bits */
-#define SDHCI_QUIRK_32BIT_ADMA_SIZE                    (1<<9)
-/* Controller needs to be reset after each request to stay stable */
-#define SDHCI_QUIRK_RESET_AFTER_REQUEST                        (1<<10)
-/* Controller needs voltage and power writes to happen separately */
-#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER            (1<<11)
-/* Controller provides an incorrect timeout value for transfers */
-#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL                 (1<<12)
-/* Controller has an issue with buffer bits for small transfers */
-#define SDHCI_QUIRK_BROKEN_SMALL_PIO                   (1<<13)
-/* Controller does not provide transfer-complete interrupt when not busy */
-#define SDHCI_QUIRK_NO_BUSY_IRQ                                (1<<14)
-/* Controller has unreliable card detection */
-#define SDHCI_QUIRK_BROKEN_CARD_DETECTION              (1<<15)
-/* Controller reports inverted write-protect state */
-#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT             (1<<16)
-/* Controller does not like fast PIO transfers */
-#define SDHCI_QUIRK_PIO_NEEDS_DELAY                    (1<<18)
-/* Controller has to be forced to use block size of 2048 bytes */
-#define SDHCI_QUIRK_FORCE_BLK_SZ_2048                  (1<<20)
-/* Controller cannot do multi-block transfers */
-#define SDHCI_QUIRK_NO_MULTIBLOCK                      (1<<21)
-/* Controller can only handle 1-bit data transfers */
-#define SDHCI_QUIRK_FORCE_1_BIT_DATA                   (1<<22)
-/* Controller needs 10ms delay between applying power and clock */
-#define SDHCI_QUIRK_DELAY_AFTER_POWER                  (1<<23)
-/* Controller uses SDCLK instead of TMCLK for data timeouts */
-#define SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK            (1<<24)
-/* Controller reports wrong base clock capability */
-#define SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN              (1<<25)
-/* Controller cannot support End Attribute in NOP ADMA descriptor */
-#define SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC              (1<<26)
-/* Controller is missing device caps. Use caps provided by host */
-#define SDHCI_QUIRK_MISSING_CAPS                       (1<<27)
-/* Controller uses Auto CMD12 command to stop the transfer */
-#define SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12             (1<<28)
-/* Controller doesn't have HISPD bit field in HI-SPEED SD card */
-#define SDHCI_QUIRK_NO_HISPD_BIT                       (1<<29)
-/* Controller treats ADMA descriptors with length 0000h incorrectly */
-#define SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC           (1<<30)
-/* The read-only detection via SDHCI_PRESENT_STATE register is unstable */
-#define SDHCI_QUIRK_UNSTABLE_RO_DETECT                 (1<<31)
-
-       unsigned int quirks2;   /* More deviations from spec. */
-
-#define SDHCI_QUIRK2_HOST_OFF_CARD_ON                  (1<<0)
-#define SDHCI_QUIRK2_HOST_NO_CMD23                     (1<<1)
-/* The system physically doesn't support 1.8v, even if the host does */
-#define SDHCI_QUIRK2_NO_1_8_V                          (1<<2)
-#define SDHCI_QUIRK2_PRESET_VALUE_BROKEN               (1<<3)
-#define SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON              (1<<4)
-/* Controller has a non-standard host control register */
-#define SDHCI_QUIRK2_BROKEN_HOST_CONTROL               (1<<5)
-/* Controller does not support HS200 */
-#define SDHCI_QUIRK2_BROKEN_HS200                      (1<<6)
-/* Controller does not support DDR50 */
-#define SDHCI_QUIRK2_BROKEN_DDR50                      (1<<7)
-/* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */
-#define SDHCI_QUIRK2_STOP_WITH_TC                      (1<<8)
-/* Controller does not support 64-bit DMA */
-#define SDHCI_QUIRK2_BROKEN_64_BIT_DMA                 (1<<9)
-/* need clear transfer mode register before send cmd */
-#define SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD (1<<10)
-/* Capability register bit-63 indicates HS400 support */
-#define SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400              (1<<11)
-/* forced tuned clock */
-#define SDHCI_QUIRK2_TUNING_WORK_AROUND                        (1<<12)
-/* disable the block count for single block transactions */
-#define SDHCI_QUIRK2_SUPPORT_SINGLE                    (1<<13)
-
-       int irq;                /* Device IRQ */
-       void __iomem *ioaddr;   /* Mapped address */
-
-       const struct sdhci_ops *ops;    /* Low level hw interface */
-
-       /* Internal data */
-       struct mmc_host *mmc;   /* MMC structure */
-       u64 dma_mask;           /* custom DMA mask */
-
-#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
-       struct led_classdev led;        /* LED control */
-       char led_name[32];
-#endif
-
-       spinlock_t lock;        /* Mutex */
-
-       int flags;              /* Host attributes */
-#define SDHCI_USE_SDMA         (1<<0)  /* Host is SDMA capable */
-#define SDHCI_USE_ADMA         (1<<1)  /* Host is ADMA capable */
-#define SDHCI_REQ_USE_DMA      (1<<2)  /* Use DMA for this req. */
-#define SDHCI_DEVICE_DEAD      (1<<3)  /* Device unresponsive */
-#define SDHCI_SDR50_NEEDS_TUNING (1<<4)        /* SDR50 needs tuning */
-#define SDHCI_NEEDS_RETUNING   (1<<5)  /* Host needs retuning */
-#define SDHCI_AUTO_CMD12       (1<<6)  /* Auto CMD12 support */
-#define SDHCI_AUTO_CMD23       (1<<7)  /* Auto CMD23 support */
-#define SDHCI_PV_ENABLED       (1<<8)  /* Preset value enabled */
-#define SDHCI_SDIO_IRQ_ENABLED (1<<9)  /* SDIO irq enabled */
-#define SDHCI_SDR104_NEEDS_TUNING (1<<10)      /* SDR104/HS200 needs tuning */
-#define SDHCI_USING_RETUNING_TIMER (1<<11)     /* Host is using a retuning timer for the card */
-#define SDHCI_USE_64_BIT_DMA   (1<<12) /* Use 64-bit DMA */
-#define SDHCI_HS400_TUNING     (1<<13) /* Tuning for HS400 */
-
-       unsigned int version;   /* SDHCI spec. version */
-
-       unsigned int max_clk;   /* Max possible freq (MHz) */
-       unsigned int timeout_clk;       /* Timeout freq (KHz) */
-       unsigned int clk_mul;   /* Clock Muliplier value */
-
-       unsigned int clock;     /* Current clock (MHz) */
-       u8 pwr;                 /* Current voltage */
-
-       bool runtime_suspended; /* Host is runtime suspended */
-       bool bus_on;            /* Bus power prevents runtime suspend */
-       bool preset_enabled;    /* Preset is enabled */
-
-       struct mmc_request *mrq;        /* Current request */
-       struct mmc_command *cmd;        /* Current command */
-       struct mmc_data *data;  /* Current data request */
-       unsigned int data_early:1;      /* Data finished before cmd */
-       unsigned int busy_handle:1;     /* Handling the order of Busy-end */
-
-       struct sg_mapping_iter sg_miter;        /* SG state for PIO */
-       unsigned int blocks;    /* remaining PIO blocks */
-
-       int sg_count;           /* Mapped sg entries */
-
-       void *adma_table;       /* ADMA descriptor table */
-       void *align_buffer;     /* Bounce buffer */
-
-       size_t adma_table_sz;   /* ADMA descriptor table size */
-       size_t align_buffer_sz; /* Bounce buffer size */
-
-       dma_addr_t adma_addr;   /* Mapped ADMA descr. table */
-       dma_addr_t align_addr;  /* Mapped bounce buffer */
-
-       unsigned int desc_sz;   /* ADMA descriptor size */
-       unsigned int align_sz;  /* ADMA alignment */
-       unsigned int align_mask;        /* ADMA alignment mask */
-
-       struct tasklet_struct finish_tasklet;   /* Tasklet structures */
-
-       struct timer_list timer;        /* Timer for timeouts */
-
-       u32 caps;               /* Alternative CAPABILITY_0 */
-       u32 caps1;              /* Alternative CAPABILITY_1 */
-
-       unsigned int            ocr_avail_sdio; /* OCR bit masks */
-       unsigned int            ocr_avail_sd;
-       unsigned int            ocr_avail_mmc;
-       u32 ocr_mask;           /* available voltages */
-
-       unsigned                timing;         /* Current timing */
-
-       u32                     thread_isr;
-
-       /* cached registers */
-       u32                     ier;
-
-       wait_queue_head_t       buf_ready_int;  /* Waitqueue for Buffer Read Ready interrupt */
-       unsigned int            tuning_done;    /* Condition flag set when CMD19 succeeds */
-
-       unsigned int            tuning_count;   /* Timer count for re-tuning */
-       unsigned int            tuning_mode;    /* Re-tuning mode supported by host */
-#define SDHCI_TUNING_MODE_1    0
-       struct timer_list       tuning_timer;   /* Timer for tuning */
-
-       struct sdhci_host_next  next_data;
-       unsigned long private[0] ____cacheline_aligned;
-};
-#endif /* LINUX_MMC_SDHCI_H */
index 67bbcf0785f61da1d4a832e016de1cb99dd313a9..8e981be2e2c2ee8c0472e7824300a6178b474640 100644 (file)
@@ -55,9 +55,6 @@ struct omap_hsmmc_platform_data {
        u32 caps;       /* Used for the MMC driver on 2430 and later */
        u32 pm_caps;    /* PM capabilities of the mmc */
 
-       /* switch pin can be for card detect (default) or card cover */
-       unsigned cover:1;
-
        /* use the internal clock */
        unsigned internal_clock:1;
 
@@ -73,7 +70,8 @@ struct omap_hsmmc_platform_data {
 #define HSMMC_HAS_HSPE_SUPPORT (1 << 2)
        unsigned features;
 
-       int switch_pin;                 /* gpio (card detect) */
+       int gpio_cd;                    /* gpio (card detect) */
+       int gpio_cod;                   /* gpio (cover detect) */
        int gpio_wp;                    /* gpio (write protect) */
 
        int (*set_power)(struct device *dev, int power_on, int vdd);