Commit 8d9095c6 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mmc-v4.1' of git://git.linaro.org/people/ulf.hansson/mmc

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
  ...
parents 1a370f4c 69f0fb2a
...@@ -187,6 +187,10 @@ N: Krishna Balasubramanian ...@@ -187,6 +187,10 @@ N: Krishna Balasubramanian
E: balasub@cis.ohio-state.edu E: balasub@cis.ohio-state.edu
D: Wrote SYS V IPC (part of standard kernel since 0.99.10) 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 N: Dario Ballabio
E: ballabio_dario@emc.com E: ballabio_dario@emc.com
E: dario.ballabio@tiscalinet.it E: dario.ballabio@tiscalinet.it
......
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;
};
...@@ -36,6 +36,8 @@ Required Properties: ...@@ -36,6 +36,8 @@ Required Properties:
in transmit mode and CIU clock phase shift value in receive mode for double 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 data rate mode operation. Refer notes below for the order of the cells and the
valid values. 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: Notes for the sdr-timing and ddr-timing values:
...@@ -50,6 +52,9 @@ Required Properties: ...@@ -50,6 +52,9 @@ Required Properties:
- if CIU clock divider value is 0 (that is divide by 1), both tx and rx - if CIU clock divider value is 0 (that is divide by 1), both tx and rx
phase shift clocks should be 0. 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): 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 * gpios: specifies a list of gpios used for command, clock and data bus. The
...@@ -82,5 +87,7 @@ Example: ...@@ -82,5 +87,7 @@ Example:
samsung,dw-mshc-ciu-div = <3>; samsung,dw-mshc-ciu-div = <3>;
samsung,dw-mshc-sdr-timing = <2 3>; samsung,dw-mshc-sdr-timing = <2 3>;
samsung,dw-mshc-ddr-timing = <1 2>; samsung,dw-mshc-ddr-timing = <1 2>;
samsung,dw-mshc-hs400-timing = <0 2>;
samsung,read-strobe-delay = <90>;
bus-width = <8>; bus-width = <8>;
}; };
...@@ -17,6 +17,10 @@ Optional properties: ...@@ -17,6 +17,10 @@ Optional properties:
to select a proper data sampling window in case the clock quality is not good 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 due to signal path is too long on the board. Please refer to eSDHC/uSDHC
chapter, DLL (Delay Line) section in RM for details. 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: Examples:
......
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;
};
};
...@@ -5,20 +5,62 @@ Documentation/devicetree/bindings/mmc/mmc.txt and the properties ...@@ -5,20 +5,62 @@ Documentation/devicetree/bindings/mmc/mmc.txt and the properties
used by the sdhci-st driver. used by the sdhci-st driver.
Required properties: Required properties:
- compatible : Must be "st,sdhci" - compatible: Must be "st,sdhci" and it can be compatible to "st,sdhci-stih407"
- clock-names : Should be "mmc" to set the internal glue logic used for configuring the MMC
See: Documentation/devicetree/bindings/resource-names.txt subsystem (mmcss) inside the FlashSS (available in STiH407 SoC
- clocks : Phandle of the clock used by the sdhci controler family).
See: Documentation/devicetree/bindings/clock/clock-bindings.txt
- 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: Optional properties:
- non-removable: non-removable slot - reg-names: Should be "mmc" and "top-mmc-delay". "top-mmc-delay" is optional
See: Documentation/devicetree/bindings/mmc/mmc.txt for eMMC on stih407 family silicon to configure DLL inside FlashSS.
- bus-width: Number of data lines
See: Documentation/devicetree/bindings/mmc/mmc.txt - 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:
/* Example stih416e eMMC configuration */
mmc0: sdhci@fe81e000 { mmc0: sdhci@fe81e000 {
compatible = "st,sdhci"; compatible = "st,sdhci";
status = "disabled"; status = "disabled";
...@@ -29,5 +71,43 @@ mmc0: sdhci@fe81e000 { ...@@ -29,5 +71,43 @@ mmc0: sdhci@fe81e000 {
pinctrl-0 = <&pinctrl_mmc0>; pinctrl-0 = <&pinctrl_mmc0>;
clock-names = "mmc"; clock-names = "mmc";
clocks = <&clk_s_a1_ls 1>; 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;
}; };
...@@ -6566,10 +6566,8 @@ F: drivers/mfd/ ...@@ -6566,10 +6566,8 @@ F: drivers/mfd/
F: include/linux/mfd/ F: include/linux/mfd/
MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
M: Chris Ball <chris@printf.net>
M: Ulf Hansson <ulf.hansson@linaro.org> M: Ulf Hansson <ulf.hansson@linaro.org>
L: linux-mmc@vger.kernel.org L: linux-mmc@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git
T: git git://git.linaro.org/people/ulf.hansson/mmc.git T: git git://git.linaro.org/people/ulf.hansson/mmc.git
S: Maintained S: Maintained
F: drivers/mmc/ F: drivers/mmc/
...@@ -8670,10 +8668,8 @@ S: Maintained ...@@ -8670,10 +8668,8 @@ S: Maintained
F: drivers/mmc/host/sdricoh_cs.c F: drivers/mmc/host/sdricoh_cs.c
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) DRIVER
M: Chris Ball <chris@printf.net>
L: linux-mmc@vger.kernel.org L: linux-mmc@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git S: Orphan
S: Maintained
F: drivers/mmc/host/sdhci.* F: drivers/mmc/host/sdhci.*
F: drivers/mmc/host/sdhci-pltfm.[ch] F: drivers/mmc/host/sdhci-pltfm.[ch]
...@@ -8689,18 +8685,12 @@ F: include/linux/seccomp.h ...@@ -8689,18 +8685,12 @@ F: include/linux/seccomp.h
K: \bsecure_computing K: \bsecure_computing
K: \bTIF_SECCOMP\b 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 SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) SAMSUNG DRIVER
M: Ben Dooks <ben-linux@fluff.org> M: Ben Dooks <ben-linux@fluff.org>
M: Jaehoon Chung <jh80.chung@samsung.com>
L: linux-mmc@vger.kernel.org L: linux-mmc@vger.kernel.org
S: Maintained S: Maintained
F: drivers/mmc/host/sdhci-s3c.c F: drivers/mmc/host/sdhci-s3c*
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) ST SPEAR DRIVER SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) ST SPEAR DRIVER
M: Viresh Kumar <viresh.linux@gmail.com> M: Viresh Kumar <viresh.linux@gmail.com>
......
...@@ -150,9 +150,13 @@ static int nop_mmc_set_power(struct device *dev, int power_on, int vdd) ...@@ -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 static inline void omap_hsmmc_mux(struct omap_hsmmc_platform_data
*mmc_controller, int controller_nr) *mmc_controller, int controller_nr)
{ {
if (gpio_is_valid(mmc_controller->switch_pin) && if (gpio_is_valid(mmc_controller->gpio_cd) &&
(mmc_controller->switch_pin < OMAP_MAX_GPIO_LINES)) (mmc_controller->gpio_cd < OMAP_MAX_GPIO_LINES))
omap_mux_init_gpio(mmc_controller->switch_pin, 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); OMAP_PIN_INPUT_PULLUP);
if (gpio_is_valid(mmc_controller->gpio_wp) && if (gpio_is_valid(mmc_controller->gpio_wp) &&
(mmc_controller->gpio_wp < OMAP_MAX_GPIO_LINES)) (mmc_controller->gpio_wp < OMAP_MAX_GPIO_LINES))
...@@ -250,15 +254,20 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c, ...@@ -250,15 +254,20 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
mmc->internal_clock = !c->ext_clock; mmc->internal_clock = !c->ext_clock;
mmc->reg_offset = 0; 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->gpio_wp = c->gpio_wp;
mmc->remux = c->remux; mmc->remux = c->remux;
mmc->init_card = c->init_card; mmc->init_card = c->init_card;
if (c->cover_only)
mmc->cover = 1;
if (c->nonremovable) if (c->nonremovable)
mmc->nonremovable = 1; mmc->nonremovable = 1;
...@@ -358,7 +367,15 @@ void omap_hsmmc_late_init(struct omap2_hsmmc_info *c) ...@@ -358,7 +367,15 @@ void omap_hsmmc_late_init(struct omap2_hsmmc_info *c)
if (!mmc_pdata) if (!mmc_pdata)
continue; 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; mmc_pdata->gpio_wp = c->gpio_wp;
res = omap_device_register(pdev); res = omap_device_register(pdev);
......
...@@ -897,6 +897,7 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort) ...@@ -897,6 +897,7 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
unsigned long flags; unsigned long flags;
int stop; int stop;
bool pm = false;
might_sleep(); might_sleep();
...@@ -916,15 +917,18 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort) ...@@ -916,15 +917,18 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
host->claimed = 1; host->claimed = 1;
host->claimer = current; host->claimer = current;
host->claim_cnt += 1; host->claim_cnt += 1;
if (host->claim_cnt == 1)
pm = true;
} else } else
wake_up(&host->wq); wake_up(&host->wq);
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait); 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; return stop;
} }
EXPORT_SYMBOL(__mmc_claim_host); EXPORT_SYMBOL(__mmc_claim_host);
/** /**
...@@ -940,9 +944,6 @@ void mmc_release_host(struct mmc_host *host) ...@@ -940,9 +944,6 @@ void mmc_release_host(struct mmc_host *host)
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
if (host->ops->disable && host->claim_cnt == 1)
host->ops->disable(host);
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
if (--host->claim_cnt) { if (--host->claim_cnt) {
/* Release for nested claim */ /* Release for nested claim */
...@@ -952,6 +953,8 @@ void mmc_release_host(struct mmc_host *host) ...@@ -952,6 +953,8 @@ void mmc_release_host(struct mmc_host *host)
host->claimer = NULL; host->claimer = NULL;
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
wake_up(&host->wq); wake_up(&host->wq);
pm_runtime_mark_last_busy(mmc_dev(host));
pm_runtime_put_autosuspend(mmc_dev(host));
} }
} }
EXPORT_SYMBOL(mmc_release_host); EXPORT_SYMBOL(mmc_release_host);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
*/ */
#include <linux/err.h> #include <linux/err.h>
#include <linux/of.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
...@@ -336,6 +337,8 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) ...@@ -336,6 +337,8 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
{ {
int err = 0, idx; int err = 0, idx;
unsigned int part_size; 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 */ /* 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]; 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) ...@@ -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 * The EXT_CSD format is meant to be forward compatible. As long
* as CSD_STRUCTURE does not change, all values for EXT_CSD_REV * 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) ...@@ -494,7 +502,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
} }
/* check whether the eMMC card supports HPI */ /* 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; card->ext_csd.hpi = 1;
if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2) if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION; card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION;
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
struct mmc_pwrseq_match { struct mmc_pwrseq_match {
const char *compatible; 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[] = { static struct mmc_pwrseq_match pwrseq_match[] = {
...@@ -52,6 +52,7 @@ int mmc_pwrseq_alloc(struct mmc_host *host) ...@@ -52,6 +52,7 @@ int mmc_pwrseq_alloc(struct mmc_host *host)
struct platform_device *pdev; struct platform_device *pdev;
struct device_node *np; struct device_node *np;
struct mmc_pwrseq_match *match; struct mmc_pwrseq_match *match;
struct mmc_pwrseq *pwrseq;
int ret = 0; int ret = 0;
np = of_parse_phandle(host->parent->of_node, "mmc-pwrseq", 0); np = of_parse_phandle(host->parent->of_node, "mmc-pwrseq", 0);
...@@ -70,9 +71,14 @@ int mmc_pwrseq_alloc(struct mmc_host *host) ...@@ -70,9 +71,14 @@ int mmc_pwrseq_alloc(struct mmc_host *host)
goto err; goto err;
} }
ret = match->alloc(host, &pdev->dev); pwrseq = match->alloc(host, &pdev->dev);
if (!ret) if (IS_ERR(pwrseq)) {
dev_info(host->parent, "allocated mmc-pwrseq\n"); ret = PTR_ERR(host->pwrseq);
goto err;
}
host->pwrseq = pwrseq;
dev_info(host->parent, "allocated mmc-pwrseq\n");
err: err:
of_node_put(np); of_node_put(np);
...@@ -109,4 +115,6 @@ void mmc_pwrseq_free(struct mmc_host *host) ...@@ -109,4 +115,6 @@ void mmc_pwrseq_free(struct mmc_host *host)
if (pwrseq && pwrseq->ops && pwrseq->ops->free) if (pwrseq && pwrseq->ops && pwrseq->ops->free)
pwrseq->ops->free(host); pwrseq->ops->free(host);
host->pwrseq = NULL;
} }
...@@ -27,8 +27,10 @@ void mmc_pwrseq_post_power_on(struct mmc_host *host); ...@@ -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_power_off(struct mmc_host *host);
void mmc_pwrseq_free(struct mmc_host *host); void mmc_pwrseq_free(struct mmc_host *host);
int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev); struct mmc_pwrseq *mmc_pwrseq_simple_alloc(struct mmc_host *host,
int mmc_pwrseq_emmc_alloc(struct mmc_host *host, struct device *dev); struct device *dev);
struct mmc_pwrseq *mmc_pwrseq_emmc_alloc(struct mmc_host *host,
struct device *dev);
#else #else
......
...@@ -49,7 +49,6 @@ static void mmc_pwrseq_emmc_free(struct mmc_host *host) ...@@ -49,7 +49,6 @@ static void mmc_pwrseq_emmc_free(struct mmc_host *host)
unregister_restart_handler(&pwrseq->reset_nb); unregister_restart_handler(&pwrseq->reset_nb);
gpiod_put(pwrseq->reset_gpio); gpiod_put(pwrseq->reset_gpio);
kfree(pwrseq); kfree(pwrseq);
host->pwrseq = NULL;
} }
static struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = { static struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = {
...@@ -67,14 +66,15 @@ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this, ...@@ -67,14 +66,15 @@ static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,
return NOTIFY_DONE; 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; struct mmc_pwrseq_emmc *pwrseq;
int ret = 0; int ret = 0;
pwrseq = kzalloc(sizeof(struct mmc_pwrseq_emmc), GFP_KERNEL); pwrseq = kzalloc(sizeof(struct mmc_pwrseq_emmc), GFP_KERNEL);
if (!pwrseq) if (!pwrseq)
return -ENOMEM; return ERR_PTR(-ENOMEM);
pwrseq->reset_gpio = gpiod_get_index(dev, "reset", 0, GPIOD_OUT_LOW); pwrseq->reset_gpio = gpiod_get_index(dev, "reset", 0, GPIOD_OUT_LOW);
if (IS_ERR(pwrseq->reset_gpio)) { if (IS_ERR(pwrseq->reset_gpio)) {
...@@ -92,10 +92,9 @@ int mmc_pwrseq_emmc_alloc(struct mmc_host *host, struct device *dev) ...@@ -92,10 +92,9 @@ int mmc_pwrseq_emmc_alloc(struct mmc_host *host, struct device *dev)
register_restart_handler(&pwrseq->reset_nb); register_restart_handler(&pwrseq->reset_nb);
pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops; pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops;
host->pwrseq = &pwrseq->pwrseq;
return 0; return &pwrseq->pwrseq;
free: free:
kfree(pwrseq); kfree(pwrseq);
return ret; return ERR_PTR(ret);
} }
...@@ -85,7 +85,6 @@ static void mmc_pwrseq_simple_free(struct mmc_host *host) ...@@ -85,7 +85,6 @@ static void mmc_pwrseq_simple_free(struct mmc_host *host)
clk_put(pwrseq->ext_clk); clk_put(pwrseq->ext_clk);
kfree(pwrseq); kfree(pwrseq);
host->pwrseq = NULL;
} }
static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = { static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
...@@ -95,7 +94,8 @@ 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, .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; struct mmc_pwrseq_simple *pwrseq;
int i, nr_gpios, ret = 0; int i, nr_gpios, ret = 0;
...@@ -107,7 +107,7 @@ int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev) ...@@ -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 * pwrseq = kzalloc(sizeof(struct mmc_pwrseq_simple) + nr_gpios *
sizeof(struct gpio_desc *), GFP_KERNEL); sizeof(struct gpio_desc *), GFP_KERNEL);
if (!pwrseq) if (!pwrseq)
return -ENOMEM; return ERR_PTR(-ENOMEM);
pwrseq->ext_clk = clk_get(dev, "ext_clock"); pwrseq->ext_clk = clk_get(dev, "ext_clock");
if (IS_ERR(pwrseq->ext_clk) && if (IS_ERR(pwrseq->ext_clk) &&
...@@ -133,13 +133,12 @@ int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev) ...@@ -133,13 +133,12 @@ int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev)
pwrseq->nr_gpios = nr_gpios; pwrseq->nr_gpios = nr_gpios;
pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops; pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops;
host->pwrseq = &pwrseq->pwrseq;
return 0; return &pwrseq->pwrseq;
clk_put: clk_put:
if (!IS_ERR(pwrseq->ext_clk)) if (!IS_ERR(pwrseq->ext_clk))
clk_put(pwrseq->ext_clk); clk_put(pwrseq->ext_clk);
free: free:
kfree(pwrseq); kfree(pwrseq);
return ret; return ERR_PTR(ret);
} }
...@@ -293,19 +293,22 @@ static int sdio_enable_4bit_bus(struct mmc_card *card) ...@@ -293,19 +293,22 @@ static int sdio_enable_4bit_bus(struct mmc_card *card)
int err; int err;
if (card->type == MMC_TYPE_SDIO) if (card->type == MMC_TYPE_SDIO)
return sdio_enable_wide(card); err = sdio_enable_wide(card);
else if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
if ((card->host->caps & MMC_CAP_4_BIT_DATA) && (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
if (err) if (err)
return err; return err;
err = sdio_enable_wide(card);
if (err <= 0)
mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1);
} else } else
return 0; return 0;
err = sdio_enable_wide(card); if (err > 0) {
if (err <= 0) mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
mmc_app_set_bus_width(card, MMC_BUS_WIDTH_1); err = 0;
}
return err; return err;
} }
...@@ -547,13 +550,8 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card) ...@@ -547,13 +550,8 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card)
/* /*
* Switch to wider bus (if supported). * 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); 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 */ /* Set the driver strength for the card */
sdio_select_driver_type(card); sdio_select_driver_type(card);
...@@ -803,9 +801,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, ...@@ -803,9 +801,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
* Switch to wider bus (if supported). * Switch to wider bus (if supported).
*/ */
err = sdio_enable_4bit_bus(card); err = sdio_enable_4bit_bus(card);
if (err > 0) if (err)
mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
else if (err)
goto remove; goto remove;
} }
finish: finish:
...@@ -983,10 +979,6 @@ static int mmc_sdio_resume(struct mmc_host *host) ...@@ -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)) { } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
/* We may have switched to 1-bit mode during suspend */ /* We may have switched to 1-bit mode during suspend */
err = sdio_enable_4bit_bus(host->card); 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) { if (!err && host->sdio_irqs) {
......
...@@ -132,7 +132,7 @@ config MMC_SDHCI_OF_ARASAN ...@@ -132,7 +132,7 @@ config MMC_SDHCI_OF_ARASAN
config MMC_SDHCI_OF_ESDHC config MMC_SDHCI_OF_ESDHC
tristate "SDHCI OF support for the Freescale eSDHC controller" tristate "SDHCI OF support for the Freescale eSDHC controller"
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
depends on PPC_OF depends on PPC
select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
help help
This selects the Freescale eSDHC controller support. This selects the Freescale eSDHC controller support.
...@@ -144,7 +144,7 @@ config MMC_SDHCI_OF_ESDHC ...@@ -144,7 +144,7 @@ config MMC_SDHCI_OF_ESDHC
config MMC_SDHCI_OF_HLWD config MMC_SDHCI_OF_HLWD
tristate "SDHCI OF support for the Nintendo Wii SDHCI controllers" tristate "SDHCI OF support for the Nintendo Wii SDHCI controllers"
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
depends on PPC_OF depends on PPC
select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
help help
This selects the Secure Digital Host Controller Interface (SDHCI) This selects the Secure Digital Host Controller Interface (SDHCI)
...@@ -230,7 +230,7 @@ config MMC_SDHCI_PXAV3 ...@@ -230,7 +230,7 @@ config MMC_SDHCI_PXAV3
tristate "Marvell MMP2 SD Host Controller support (PXAV3)" tristate "Marvell MMP2 SD Host Controller support (PXAV3)"
depends on CLKDEV_LOOKUP depends on CLKDEV_LOOKUP
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
depends on ARCH_MMP || COMPILE_TEST depends on ARCH_BERLIN || ARCH_MMP || ARCH_MVEBU || COMPILE_TEST
default CPU_MMP2 default CPU_MMP2
help help
This selects the Marvell(R) PXAV3 SD Host Controller. This selects the Marvell(R) PXAV3 SD Host Controller.
...@@ -255,6 +255,7 @@ config MMC_SDHCI_PXAV2 ...@@ -255,6 +255,7 @@ config MMC_SDHCI_PXAV2
config MMC_SDHCI_SPEAR config MMC_SDHCI_SPEAR
tristate "SDHCI support on ST SPEAr platform" tristate "SDHCI support on ST SPEAr platform"
depends on MMC_SDHCI && PLAT_SPEAR depends on MMC_SDHCI && PLAT_SPEAR
depends on OF
help help
This selects the Secure Digital Host Controller Interface (SDHCI) This selects the Secure Digital Host Controller Interface (SDHCI)
often referrered to as the HSMMC block in some of the ST SPEAR range often referrered to as the HSMMC block in some of the ST SPEAR range
...@@ -307,6 +308,20 @@ config MMC_SDHCI_F_SDH30 ...@@ -307,6 +308,20 @@ config MMC_SDHCI_F_SDH30
If unsure, say N. 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 config MMC_MOXART
tristate "MOXART SD/MMC Host Controller support" tristate "MOXART SD/MMC Host Controller support"
depends on ARCH_MOXART && MMC depends on ARCH_MOXART && MMC
......
...@@ -71,6 +71,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o ...@@ -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_OF_HLWD) += sdhci-of-hlwd.o
obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o
obj-$(CONFIG_MMC_SDHCI_BCM2835) += sdhci-bcm2835.o obj-$(CONFIG_MMC_SDHCI_BCM2835) += sdhci-bcm2835.o
obj-$(CONFIG_MMC_SDHCI_IPROC) += sdhci-iproc.o
obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o obj-$(CONFIG_MMC_SDHCI_MSM) += sdhci-msm.o
obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o obj-$(CONFIG_MMC_SDHCI_ST) += sdhci-st.o
......
...@@ -135,10 +135,17 @@ ...@@ -135,10 +135,17 @@
#define ATMCI_REGS_SIZE 0x100 #define ATMCI_REGS_SIZE 0x100
/* Register access macros */ /* Register access macros */
#define atmci_readl(port,reg) \ #ifdef CONFIG_AVR32
#define atmci_readl(port, reg) \
__raw_readl((port)->regs + reg) __raw_readl((port)->regs + reg)
#define atmci_writel(port,reg,value) \ #define atmci_writel(port, reg, value) \
__raw_writel((value), (port)->regs + reg) __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. */ /* On AVR chips the Peripheral DMA Controller is not connected to MCI. */
#ifdef CONFIG_AVR32 #ifdef CONFIG_AVR32
......
...@@ -40,7 +40,12 @@ struct dw_mci_exynos_priv_data { ...@@ -40,7 +40,12 @@ struct dw_mci_exynos_priv_data {
u8 ciu_div; u8 ciu_div;
u32 sdr_timing; u32 sdr_timing;
u32 ddr_timing; u32 ddr_timing;
u32 hs400_timing;
u32 tuned_sample;
u32 cur_speed; u32 cur_speed;
u32 dqs_delay;
u32 saved_dqs_en;
u32 saved_strobe_ctrl;
}; };
static struct dw_mci_exynos_compatible { static struct dw_mci_exynos_compatible {
...@@ -71,6 +76,21 @@ 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) static int dw_mci_exynos_priv_init(struct dw_mci *host)
{ {
struct dw_mci_exynos_priv_data *priv = host->priv; struct dw_mci_exynos_priv_data *priv = host->priv;
...@@ -85,6 +105,16 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host) ...@@ -85,6 +105,16 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT); 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; return 0;
} }
...@@ -97,6 +127,26 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host) ...@@ -97,6 +127,26 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
return 0; 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 #ifdef CONFIG_PM_SLEEP
static int dw_mci_exynos_suspend(struct device *dev) 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) ...@@ -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; struct dw_mci_exynos_priv_data *priv = host->priv;
unsigned int wanted = ios->clock; u32 dqs, strobe;
unsigned long actual;
u8 div = priv->ciu_div + 1;
if (ios->timing == MMC_TIMING_MMC_DDR52) { /*
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || * Not supported to configure register
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) * related to HS400
mci_writel(host, CLKSEL64, priv->ddr_timing); */
else if (priv->ctrl_type < DW_MCI_TYPE_EXYNOS5420)
mci_writel(host, CLKSEL, priv->ddr_timing); return;
/* Should be double rate for DDR mode */
if (ios->bus_width == MMC_BUS_WIDTH_8) dqs = priv->saved_dqs_en;
wanted <<= 1; 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 { } else {
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || dqs &= ~DATA_STROBE_EN;
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
mci_writel(host, CLKSEL64, priv->sdr_timing);
else
mci_writel(host, CLKSEL, priv->sdr_timing);
} }
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 * Don't care if wanted clock is zero or
* ciu clock is unavailable * ciu clock is unavailable
...@@ -207,17 +265,52 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) ...@@ -207,17 +265,52 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
if (wanted < EXYNOS_CCLKIN_MIN) if (wanted < EXYNOS_CCLKIN_MIN)
wanted = EXYNOS_CCLKIN_MIN; wanted = EXYNOS_CCLKIN_MIN;
if (wanted != priv->cur_speed) { if (wanted == priv->cur_speed)
int ret = clk_set_rate(host->ciu_clk, wanted * div); return;
if (ret)
dev_warn(host->dev, div = dw_mci_exynos_get_ciu_div(host);
"failed to set clk-rate %u error: %d\n", ret = clk_set_rate(host->ciu_clk, wanted * div);
wanted * div, ret); if (ret)
actual = clk_get_rate(host->ciu_clk); dev_warn(host->dev,
host->bus_hz = actual / div; "failed to set clk-rate %u error: %d\n",
priv->cur_speed = wanted; wanted * div, ret);
host->current_speed = 0; 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) 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) ...@@ -260,6 +353,16 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
return ret; return ret;
priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div); 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; host->priv = priv;
return 0; return 0;
} }
...@@ -285,7 +388,7 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample) ...@@ -285,7 +388,7 @@ static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
clksel = mci_readl(host, CLKSEL64); clksel = mci_readl(host, CLKSEL64);
else else
clksel = mci_readl(host, CLKSEL); 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 || if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
mci_writel(host, CLKSEL64, clksel); mci_writel(host, CLKSEL64, clksel);
...@@ -304,13 +407,16 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host) ...@@ -304,13 +407,16 @@ static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
clksel = mci_readl(host, CLKSEL64); clksel = mci_readl(host, CLKSEL64);
else else
clksel = mci_readl(host, CLKSEL); clksel = mci_readl(host, CLKSEL);
sample = (clksel + 1) & 0x7; sample = (clksel + 1) & 0x7;
clksel = (clksel & ~0x7) | sample; clksel = SDMMC_CLKSEL_UP_SAMPLE(clksel, sample);
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 || if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
mci_writel(host, CLKSEL64, clksel); mci_writel(host, CLKSEL64, clksel);
else else
mci_writel(host, CLKSEL, clksel); mci_writel(host, CLKSEL, clksel);
return sample; return sample;
} }
...@@ -343,6 +449,7 @@ static s8 dw_mci_exynos_get_best_clksmpl(u8 candiates) ...@@ -343,6 +449,7 @@ static s8 dw_mci_exynos_get_best_clksmpl(u8 candiates)
static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot) static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
{ {
struct dw_mci *host = slot->host; struct dw_mci *host = slot->host;
struct dw_mci_exynos_priv_data *priv = host->priv;
struct mmc_host *mmc = slot->mmc; struct mmc_host *mmc = slot->mmc;
u8 start_smpl, smpl, candiates = 0; u8 start_smpl, smpl, candiates = 0;
s8 found = -1; s8 found = -1;
...@@ -360,14 +467,27 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot) ...@@ -360,14 +467,27 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
} while (start_smpl != smpl); } while (start_smpl != smpl);
found = dw_mci_exynos_get_best_clksmpl(candiates); found = dw_mci_exynos_get_best_clksmpl(candiates);
if (found >= 0) if (found >= 0) {
dw_mci_exynos_set_clksmpl(host, found); dw_mci_exynos_set_clksmpl(host, found);
else priv->tuned_sample = found;
} else {
ret = -EIO; ret = -EIO;
}
return ret; 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 */ /* Common capabilities of Exynos4/Exynos5 SoC */
static unsigned long exynos_dwmmc_caps[4] = { static unsigned long exynos_dwmmc_caps[4] = {
MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23, 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 = { ...@@ -384,6 +504,7 @@ static const struct dw_mci_drv_data exynos_drv_data = {
.set_ios = dw_mci_exynos_set_ios, .set_ios = dw_mci_exynos_set_ios,
.parse_dt = dw_mci_exynos_parse_dt, .parse_dt = dw_mci_exynos_parse_dt,
.execute_tuning = dw_mci_exynos_execute_tuning, .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[] = { static const struct of_device_id dw_mci_exynos_match[] = {
......
...@@ -12,20 +12,36 @@ ...@@ -12,20 +12,36 @@
#ifndef _DW_MMC_EXYNOS_H_ #ifndef _DW_MMC_EXYNOS_H_
#define _DW_MMC_EXYNOS_H_ #define _DW_MMC_EXYNOS_H_
/* Extended Register's Offset */
#define SDMMC_CLKSEL 0x09C #define SDMMC_CLKSEL 0x09C
#define SDMMC_CLKSEL64 0x0A8 #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 */ /* CLKSEL register defines */
#define SDMMC_CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0) #define SDMMC_CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0)
#define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16) #define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16)
#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24) #define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24)
#define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7) #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) | \ #define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
SDMMC_CLKSEL_CCLK_DRIVE(y) | \ SDMMC_CLKSEL_CCLK_DRIVE(y) | \
SDMMC_CLKSEL_CCLK_DIVIDER(z)) SDMMC_CLKSEL_CCLK_DIVIDER(z))
#define SDMMC_CLKSEL_TIMING_MASK SDMMC_CLKSEL_TIMING(0x7, 0x7, 0x7)
#define SDMMC_CLKSEL_WAKEUP_INT BIT(11) #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 */ /* Protector Register */
#define SDMMC_EMMCP_BASE 0x1000 #define SDMMC_EMMCP_BASE 0x1000
#define SDMMC_MPSECURITY (SDMMC_EMMCP_BASE + 0x0010) #define SDMMC_MPSECURITY (SDMMC_EMMCP_BASE + 0x0010)
...@@ -49,6 +65,7 @@ ...@@ -49,6 +65,7 @@
/* Fixed clock divider */ /* Fixed clock divider */
#define EXYNOS4210_FIXED_CIU_CLK_DIV 2 #define EXYNOS4210_FIXED_CIU_CLK_DIV 2
#define EXYNOS4412_FIXED_CIU_CLK_DIV 4 #define EXYNOS4412_FIXED_CIU_CLK_DIV 4
#define HS400_FIXED_CIU_CLK_DIV 1
/* Minimal required clock frequency for cclkin, unit: HZ */ /* Minimal required clock frequency for cclkin, unit: HZ */
#define EXYNOS_CCLKIN_MIN 50000000 #define EXYNOS_CCLKIN_MIN 50000000
......
...@@ -76,12 +76,20 @@ static int dw_mci_rockchip_init(struct dw_mci *host) ...@@ -76,12 +76,20 @@ static int dw_mci_rockchip_init(struct dw_mci *host)
return 0; 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 = { static const struct dw_mci_drv_data rk2928_drv_data = {
.prepare_command = dw_mci_rockchip_prepare_command, .prepare_command = dw_mci_rockchip_prepare_command,
.init = dw_mci_rockchip_init, .init = dw_mci_rockchip_init,
}; };
static const struct dw_mci_drv_data rk3288_drv_data = { static const struct dw_mci_drv_data rk3288_drv_data = {
.caps = dw_mci_rk3288_dwmmc_caps,
.prepare_command = dw_mci_rockchip_prepare_command, .prepare_command = dw_mci_rockchip_prepare_command,
.set_ios = dw_mci_rk3288_set_ios, .set_ios = dw_mci_rk3288_set_ios,
.setup_clock = dw_mci_rk3288_setup_clock, .setup_clock = dw_mci_rk3288_setup_clock,
......
This diff is collapsed.
...@@ -169,24 +169,34 @@ ...@@ -169,24 +169,34 @@
#define SDMMC_CTRL_ALL_RESET_FLAGS \ #define SDMMC_CTRL_ALL_RESET_FLAGS \
(SDMMC_CTRL_RESET | SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) (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 */ /* Register access macros */
#define mci_readl(dev, reg) \ #define mci_readl(dev, reg) \
__raw_readl((dev)->regs + SDMMC_##reg) readl_relaxed((dev)->regs + SDMMC_##reg)
#define mci_writel(dev, reg, value) \ #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 */ /* 16-bit FIFO access macros */
#define mci_readw(dev, reg) \ #define mci_readw(dev, reg) \
__raw_readw((dev)->regs + SDMMC_##reg) readw_relaxed((dev)->regs + SDMMC_##reg)
#define mci_writew(dev, reg, value) \ #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 */ /* 64-bit FIFO access macros */
#ifdef readq #ifdef readq
#define mci_readq(dev, reg) \ #define mci_readq(dev, reg) \
__raw_readq((dev)->regs + SDMMC_##reg) readq_relaxed((dev)->regs + SDMMC_##reg)
#define mci_writeq(dev, reg, value) \ #define mci_writeq(dev, reg, value) \
__raw_writeq((value), (dev)->regs + SDMMC_##reg) writeq_relaxed((value), (dev)->regs + SDMMC_##reg)
#else #else
/* /*
* Dummy readq implementation for architectures that don't define it. * Dummy readq implementation for architectures that don't define it.
...@@ -200,6 +210,10 @@ ...@@ -200,6 +210,10 @@
(*(volatile u64 __force *)((dev)->regs + SDMMC_##reg)) (*(volatile u64 __force *)((dev)->regs + SDMMC_##reg))
#define mci_writeq(dev, reg, value) \ #define mci_writeq(dev, reg, value) \
(*(volatile u64 __force *)((dev)->regs + SDMMC_##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 #endif
extern int dw_mci_probe(struct dw_mci *host); extern int dw_mci_probe(struct dw_mci *host);
...@@ -271,5 +285,7 @@ struct dw_mci_drv_data { ...@@ -271,5 +285,7 @@ struct dw_mci_drv_data {
void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
int (*parse_dt)(struct dw_mci *host); int (*parse_dt)(struct dw_mci *host);
int (*execute_tuning)(struct dw_mci_slot *slot); int (*execute_tuning)(struct dw_mci_slot *slot);
int (*prepare_hs400_tuning)(struct dw_mci *host,
struct mmc_ios *ios);
}; };
#endif /* _DW_MMC_H_ */ #endif /* _DW_MMC_H_ */
...@@ -1507,7 +1507,7 @@ static int mmc_spi_remove(struct spi_device *spi) ...@@ -1507,7 +1507,7 @@ static int mmc_spi_remove(struct spi_device *spi)
return 0; 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", }, { .compatible = "mmc-spi-slot", },
{}, {},
}; };
......
...@@ -1613,7 +1613,10 @@ static int mmci_probe(struct amba_device *dev, ...@@ -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); dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max);
/* Get regulators and the supported OCR mask */ /* 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) if (!mmc->ocr_avail)
mmc->ocr_avail = plat->ocr_mask; mmc->ocr_avail = plat->ocr_mask;
else if (plat->ocr_mask) else if (plat->ocr_mask)
......
...@@ -222,10 +222,6 @@ struct omap_hsmmc_host { ...@@ -222,10 +222,6 @@ struct omap_hsmmc_host {
struct omap_hsmmc_next next_data; struct omap_hsmmc_next next_data;
struct omap_hsmmc_platform_data *pdata; 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. /* return MMC cover switch state, can be NULL if not supported.
* *
* possible return values: * possible return values:
...@@ -234,12 +230,7 @@ struct omap_hsmmc_host { ...@@ -234,12 +230,7 @@ struct omap_hsmmc_host {
*/ */
int (*get_cover_state)(struct device *dev); int (*get_cover_state)(struct device *dev);
/* Card detection IRQs */
int card_detect_irq;
int (*card_detect)(struct device *dev); int (*card_detect)(struct device *dev);
int (*get_ro)(struct device *dev);
}; };
struct omap_mmc_of_data { struct omap_mmc_of_data {
...@@ -256,13 +247,6 @@ static int omap_hsmmc_card_detect(struct device *dev) ...@@ -256,13 +247,6 @@ static int omap_hsmmc_card_detect(struct device *dev)
return mmc_gpio_get_cd(host->mmc); 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) static int omap_hsmmc_get_cover_state(struct device *dev)
{ {
struct omap_hsmmc_host *host = dev_get_drvdata(dev); struct omap_hsmmc_host *host = dev_get_drvdata(dev);
...@@ -434,7 +418,7 @@ static inline int omap_hsmmc_have_reg(void) ...@@ -434,7 +418,7 @@ static inline int omap_hsmmc_have_reg(void)
#endif #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, static int omap_hsmmc_gpio_init(struct mmc_host *mmc,
struct omap_hsmmc_host *host, struct omap_hsmmc_host *host,
...@@ -442,29 +426,25 @@ static int omap_hsmmc_gpio_init(struct mmc_host *mmc, ...@@ -442,29 +426,25 @@ static int omap_hsmmc_gpio_init(struct mmc_host *mmc,
{ {
int ret; int ret;
if (gpio_is_valid(pdata->switch_pin)) { if (gpio_is_valid(pdata->gpio_cod)) {
if (pdata->cover) ret = mmc_gpio_request_cd(mmc, pdata->gpio_cod, 0);
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 (ret) if (ret)
return 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)) { if (gpio_is_valid(pdata->gpio_wp)) {
host->get_ro = omap_hsmmc_get_wp;
ret = mmc_gpio_request_ro(mmc, pdata->gpio_wp); ret = mmc_gpio_request_ro(mmc, pdata->gpio_wp);
if (ret) if (ret)
return ret; return ret;
} else {
pdata->gpio_wp = -EINVAL;
} }
return 0; return 0;
...@@ -882,6 +862,8 @@ static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_req ...@@ -882,6 +862,8 @@ static void omap_hsmmc_request_done(struct omap_hsmmc_host *host, struct mmc_req
return; return;
host->mrq = NULL; host->mrq = NULL;
mmc_request_done(host->mmc, mrq); 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) ...@@ -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; struct omap_hsmmc_host *host = dev_id;
int carddetect;
sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
if (host->card_detect) omap_hsmmc_protect_card(host);
carddetect = host->card_detect(host->dev); mmc_detect_change(host->mmc, (HZ * 200) / 1000);
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);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -1305,6 +1277,8 @@ static void omap_hsmmc_dma_callback(void *param) ...@@ -1305,6 +1277,8 @@ static void omap_hsmmc_dma_callback(void *param)
host->mrq = NULL; host->mrq = NULL;
mmc_request_done(host->mmc, mrq); 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) ...@@ -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->req_in_progress);
BUG_ON(host->dma_ch != -1); BUG_ON(host->dma_ch != -1);
pm_runtime_get_sync(host->dev);
if (host->protect_card) { if (host->protect_card) {
if (host->reqs_blocked < 3) { if (host->reqs_blocked < 3) {
/* /*
...@@ -1553,6 +1528,8 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req) ...@@ -1553,6 +1528,8 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
req->data->error = -EBADF; req->data->error = -EBADF;
req->cmd->retries = 0; req->cmd->retries = 0;
mmc_request_done(mmc, req); mmc_request_done(mmc, req);
pm_runtime_mark_last_busy(host->dev);
pm_runtime_put_autosuspend(host->dev);
return; return;
} else if (host->reqs_blocked) } else if (host->reqs_blocked)
host->reqs_blocked = 0; host->reqs_blocked = 0;
...@@ -1566,6 +1543,8 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req) ...@@ -1566,6 +1543,8 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
req->data->error = err; req->data->error = err;
host->mrq = NULL; host->mrq = NULL;
mmc_request_done(mmc, req); mmc_request_done(mmc, req);
pm_runtime_mark_last_busy(host->dev);
pm_runtime_put_autosuspend(host->dev);
return; return;
} }
if (req->sbc && !(host->flags & AUTO_CMD23)) { if (req->sbc && !(host->flags & AUTO_CMD23)) {
...@@ -1641,15 +1620,6 @@ static int omap_hsmmc_get_cd(struct mmc_host *mmc) ...@@ -1641,15 +1620,6 @@ static int omap_hsmmc_get_cd(struct mmc_host *mmc)
return host->card_detect(host->dev); 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) static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
{ {
struct omap_hsmmc_host *host = mmc_priv(mmc); struct omap_hsmmc_host *host = mmc_priv(mmc);
...@@ -1778,25 +1748,6 @@ static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host) ...@@ -1778,25 +1748,6 @@ static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
set_sd_bus_power(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, static int omap_hsmmc_multi_io_quirk(struct mmc_card *card,
unsigned int direction, int blk_size) unsigned int direction, int blk_size)
{ {
...@@ -1808,14 +1759,12 @@ static int omap_hsmmc_multi_io_quirk(struct mmc_card *card, ...@@ -1808,14 +1759,12 @@ static int omap_hsmmc_multi_io_quirk(struct mmc_card *card,
} }
static struct mmc_host_ops omap_hsmmc_ops = { static struct mmc_host_ops omap_hsmmc_ops = {
.enable = omap_hsmmc_enable_fclk,
.disable = omap_hsmmc_disable_fclk,
.post_req = omap_hsmmc_post_req, .post_req = omap_hsmmc_post_req,
.pre_req = omap_hsmmc_pre_req, .pre_req = omap_hsmmc_pre_req,
.request = omap_hsmmc_request, .request = omap_hsmmc_request,
.set_ios = omap_hsmmc_set_ios, .set_ios = omap_hsmmc_set_ios,
.get_cd = omap_hsmmc_get_cd, .get_cd = omap_hsmmc_get_cd,
.get_ro = omap_hsmmc_get_ro, .get_ro = mmc_gpio_get_ro,
.init_card = omap_hsmmc_init_card, .init_card = omap_hsmmc_init_card,
.enable_sdio_irq = omap_hsmmc_enable_sdio_irq, .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) ...@@ -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)) if (of_find_property(np, "ti,dual-volt", NULL))
pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT; pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
pdata->switch_pin = -EINVAL; pdata->gpio_cd = -EINVAL;
pdata->gpio_cod = -EINVAL;
pdata->gpio_wp = -EINVAL; pdata->gpio_wp = -EINVAL;
if (of_find_property(np, "ti,non-removable", NULL)) { if (of_find_property(np, "ti,non-removable", NULL)) {
...@@ -2179,9 +2129,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev) ...@@ -2179,9 +2129,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
if (ret < 0) if (ret < 0)
goto err_slot_name; 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, ret = device_create_file(&mmc->class_dev,
&dev_attr_cover_switch); &dev_attr_cover_switch);
if (ret < 0) if (ret < 0)
goto err_slot_name; goto err_slot_name;
} }
...@@ -2236,7 +2186,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev) ...@@ -2236,7 +2186,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
static int omap_hsmmc_suspend(struct device *dev) static int omap_hsmmc_suspend(struct device *dev)
{ {
struct omap_hsmmc_host *host = dev_get_drvdata(dev); struct omap_hsmmc_host *host = dev_get_drvdata(dev);
...@@ -2292,10 +2242,6 @@ static int omap_hsmmc_resume(struct device *dev) ...@@ -2292,10 +2242,6 @@ static int omap_hsmmc_resume(struct device *dev)
pm_runtime_put_autosuspend(host->dev); pm_runtime_put_autosuspend(host->dev);
return 0; return 0;
} }
#else
#define omap_hsmmc_suspend NULL
#define omap_hsmmc_resume NULL
#endif #endif
static int omap_hsmmc_runtime_suspend(struct device *dev) static int omap_hsmmc_runtime_suspend(struct device *dev)
...@@ -2376,8 +2322,7 @@ static int omap_hsmmc_runtime_resume(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 = { static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
.suspend = omap_hsmmc_suspend, SET_SYSTEM_SLEEP_PM_OPS(omap_hsmmc_suspend, omap_hsmmc_resume)
.resume = omap_hsmmc_resume,
.runtime_suspend = omap_hsmmc_runtime_suspend, .runtime_suspend = omap_hsmmc_runtime_suspend,
.runtime_resume = omap_hsmmc_runtime_resume, .runtime_resume = omap_hsmmc_runtime_resume,
}; };
......
...@@ -40,7 +40,6 @@ ...@@ -40,7 +40,6 @@
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/pm.h> #include <linux/mmc/pm.h>
#include <linux/mmc/slot-gpio.h> #include <linux/mmc/slot-gpio.h>
#include <linux/mmc/sdhci.h>
#include "sdhci.h" #include "sdhci.h"
......
...@@ -54,7 +54,6 @@ ...@@ -54,7 +54,6 @@
struct sdhci_bcm_kona_dev { struct sdhci_bcm_kona_dev {
struct mutex write_lock; /* protect back to back writes */ struct mutex write_lock; /* protect back to back writes */
struct clk *external_clk;
}; };
...@@ -175,24 +174,6 @@ static void sdhci_bcm_kona_card_event(struct sdhci_host *host) ...@@ -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, static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host,
u8 power_mode) u8 power_mode)
{ {
...@@ -207,8 +188,8 @@ static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host, ...@@ -207,8 +188,8 @@ static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host,
static struct sdhci_ops sdhci_bcm_kona_ops = { static struct sdhci_ops sdhci_bcm_kona_ops = {
.set_clock = sdhci_set_clock, .set_clock = sdhci_set_clock,
.get_max_clock = sdhci_bcm_kona_get_max_clk, .get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_bcm_kona_get_timeout_clock, .get_timeout_clock = sdhci_pltfm_clk_get_max_clock,
.platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks, .platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks,
.set_bus_width = sdhci_set_bus_width, .set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset, .reset = sdhci_reset,
...@@ -264,21 +245,21 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev) ...@@ -264,21 +245,21 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
goto err_pltfm_free; goto err_pltfm_free;
} }
/* Get and enable the external clock */ /* Get and enable the core clock */
kona_dev->external_clk = devm_clk_get(dev, NULL); pltfm_priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(kona_dev->external_clk)) { if (IS_ERR(pltfm_priv->clk)) {
dev_err(dev, "Failed to get external clock\n"); dev_err(dev, "Failed to get core clock\n");
ret = PTR_ERR(kona_dev->external_clk); ret = PTR_ERR(pltfm_priv->clk);
goto err_pltfm_free; goto err_pltfm_free;
} }
if (clk_set_rate(kona_dev->external_clk, host->mmc->f_max) != 0) { if (clk_set_rate(pltfm_priv->clk, host->mmc->f_max) != 0) {
dev_err(dev, "Failed to set rate external clock\n"); dev_err(dev, "Failed to set rate core clock\n");
goto err_pltfm_free; goto err_pltfm_free;
} }
if (clk_prepare_enable(kona_dev->external_clk) != 0) { if (clk_prepare_enable(pltfm_priv->clk) != 0) {
dev_err(dev, "Failed to enable external clock\n"); dev_err(dev, "Failed to enable core clock\n");
goto err_pltfm_free; goto err_pltfm_free;
} }
...@@ -333,7 +314,7 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev) ...@@ -333,7 +314,7 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
sdhci_bcm_kona_sd_reset(host); sdhci_bcm_kona_sd_reset(host);
err_clk_disable: err_clk_disable:
clk_disable_unprepare(kona_dev->external_clk); clk_disable_unprepare(pltfm_priv->clk);
err_pltfm_free: err_pltfm_free:
sdhci_pltfm_free(pdev); sdhci_pltfm_free(pdev);
...@@ -342,22 +323,6 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev) ...@@ -342,22 +323,6 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
return ret; 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 = { static struct platform_driver sdhci_bcm_kona_driver = {
.driver = { .driver = {
.name = "sdhci-kona", .name = "sdhci-kona",
...@@ -365,7 +330,7 @@ static struct platform_driver sdhci_bcm_kona_driver = { ...@@ -365,7 +330,7 @@ static struct platform_driver sdhci_bcm_kona_driver = {
.of_match_table = sdhci_bcm_kona_of_match, .of_match_table = sdhci_bcm_kona_of_match,
}, },
.probe = sdhci_bcm_kona_probe, .probe = sdhci_bcm_kona_probe,
.remove = sdhci_bcm_kona_remove, .remove = sdhci_pltfm_unregister,
}; };
module_platform_driver(sdhci_bcm_kona_driver); module_platform_driver(sdhci_bcm_kona_driver);
......
...@@ -180,11 +180,6 @@ static int bcm2835_sdhci_probe(struct platform_device *pdev) ...@@ -180,11 +180,6 @@ static int bcm2835_sdhci_probe(struct platform_device *pdev)
return ret; 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[] = { static const struct of_device_id bcm2835_sdhci_of_match[] = {
{ .compatible = "brcm,bcm2835-sdhci" }, { .compatible = "brcm,bcm2835-sdhci" },
{ } { }
...@@ -198,7 +193,7 @@ static struct platform_driver bcm2835_sdhci_driver = { ...@@ -198,7 +193,7 @@ static struct platform_driver bcm2835_sdhci_driver = {
.pm = SDHCI_PLTFM_PMOPS, .pm = SDHCI_PLTFM_PMOPS,
}, },
.probe = bcm2835_sdhci_probe, .probe = bcm2835_sdhci_probe,
.remove = bcm2835_sdhci_remove, .remove = sdhci_pltfm_unregister,
}; };
module_platform_driver(bcm2835_sdhci_driver); module_platform_driver(bcm2835_sdhci_driver);
......
...@@ -98,18 +98,13 @@ static int sdhci_cns3xxx_probe(struct platform_device *pdev) ...@@ -98,18 +98,13 @@ static int sdhci_cns3xxx_probe(struct platform_device *pdev)
return sdhci_pltfm_register(pdev, &sdhci_cns3xxx_pdata, 0); 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 = { static struct platform_driver sdhci_cns3xxx_driver = {
.driver = { .driver = {
.name = "sdhci-cns3xxx", .name = "sdhci-cns3xxx",
.pm = SDHCI_PLTFM_PMOPS, .pm = SDHCI_PLTFM_PMOPS,
}, },
.probe = sdhci_cns3xxx_probe, .probe = sdhci_cns3xxx_probe,
.remove = sdhci_cns3xxx_remove, .remove = sdhci_pltfm_unregister,
}; };
module_platform_driver(sdhci_cns3xxx_driver); module_platform_driver(sdhci_cns3xxx_driver);
......
...@@ -28,10 +28,6 @@ ...@@ -28,10 +28,6 @@
#include "sdhci-pltfm.h" #include "sdhci-pltfm.h"
struct sdhci_dove_priv {
struct clk *clk;
};
static u16 sdhci_dove_readw(struct sdhci_host *host, int reg) static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)
{ {
u16 ret; u16 ret;
...@@ -84,27 +80,17 @@ static int sdhci_dove_probe(struct platform_device *pdev) ...@@ -84,27 +80,17 @@ static int sdhci_dove_probe(struct platform_device *pdev)
{ {
struct sdhci_host *host; struct sdhci_host *host;
struct sdhci_pltfm_host *pltfm_host; struct sdhci_pltfm_host *pltfm_host;
struct sdhci_dove_priv *priv;
int ret; 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); host = sdhci_pltfm_init(pdev, &sdhci_dove_pdata, 0);
if (IS_ERR(host)) if (IS_ERR(host))
return PTR_ERR(host); return PTR_ERR(host);
pltfm_host = sdhci_priv(host); pltfm_host = sdhci_priv(host);
pltfm_host->priv = priv; pltfm_host->clk = devm_clk_get(&pdev->dev, NULL);
if (!IS_ERR(priv->clk)) if (!IS_ERR(pltfm_host->clk))
clk_prepare_enable(priv->clk); clk_prepare_enable(pltfm_host->clk);
ret = mmc_of_parse(host->mmc); ret = mmc_of_parse(host->mmc);
if (ret) if (ret)
...@@ -117,26 +103,11 @@ static int sdhci_dove_probe(struct platform_device *pdev) ...@@ -117,26 +103,11 @@ static int sdhci_dove_probe(struct platform_device *pdev)
return 0; return 0;
err_sdhci_add: err_sdhci_add:
if (!IS_ERR(priv->clk)) clk_disable_unprepare(pltfm_host->clk);
clk_disable_unprepare(priv->clk);
sdhci_pltfm_free(pdev); sdhci_pltfm_free(pdev);
return ret; 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[] = { static const struct of_device_id sdhci_dove_of_match_table[] = {
{ .compatible = "marvell,dove-sdhci", }, { .compatible = "marvell,dove-sdhci", },
{} {}
...@@ -150,7 +121,7 @@ static struct platform_driver sdhci_dove_driver = { ...@@ -150,7 +121,7 @@ static struct platform_driver sdhci_dove_driver = {
.of_match_table = sdhci_dove_of_match_table, .of_match_table = sdhci_dove_of_match_table,
}, },
.probe = sdhci_dove_probe, .probe = sdhci_dove_probe,
.remove = sdhci_dove_remove, .remove = sdhci_pltfm_unregister,
}; };
module_platform_driver(sdhci_dove_driver); module_platform_driver(sdhci_dove_driver);
......
...@@ -416,7 +416,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) ...@@ -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; new_val |= ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;
else else
new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON; 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; return;
case SDHCI_HOST_CONTROL2: case SDHCI_HOST_CONTROL2:
new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
...@@ -864,6 +864,7 @@ static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { ...@@ -864,6 +864,7 @@ static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
#ifdef CONFIG_OF #ifdef CONFIG_OF
static int static int
sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
struct sdhci_host *host,
struct esdhc_platform_data *boarddata) struct esdhc_platform_data *boarddata)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
...@@ -900,11 +901,14 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, ...@@ -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)) if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line))
boarddata->delay_line = 0; boarddata->delay_line = 0;
mmc_of_parse_voltage(np, &host->ocr_mask);
return 0; return 0;
} }
#else #else
static inline int static inline int
sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
struct sdhci_host *host,
struct esdhc_platform_data *boarddata) struct esdhc_platform_data *boarddata)
{ {
return -ENODEV; return -ENODEV;
...@@ -999,7 +1003,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) ...@@ -999,7 +1003,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
host->ioaddr + ESDHC_TUNING_CTRL); host->ioaddr + ESDHC_TUNING_CTRL);
boarddata = &imx_data->boarddata; 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) { if (!host->mmc->parent->platform_data) {
dev_err(mmc_dev(host->mmc), "no board data!\n"); dev_err(mmc_dev(host->mmc), "no board data!\n");
err = -EINVAL; err = -EINVAL;
...@@ -1009,40 +1013,9 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) ...@@ -1009,40 +1013,9 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
host->mmc->parent->platform_data); 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 */ /* card_detect */
switch (boarddata->cd_type) { if (boarddata->cd_type == ESDHC_CD_CONTROLLER)
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 */
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; 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) { switch (boarddata->max_bus_width) {
case 8: case 8:
...@@ -1075,6 +1048,11 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) ...@@ -1075,6 +1048,11 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; 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); err = sdhci_add_host(host);
if (err) if (err)
goto disable_clk; goto disable_clk;
......
/*
* 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");
...@@ -22,6 +22,11 @@ ...@@ -22,6 +22,11 @@
#include "sdhci-pltfm.h" #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 CORE_HC_MODE 0x78
#define HC_MODE_EN 0x1 #define HC_MODE_EN 0x1
#define CORE_POWER 0x0 #define CORE_POWER 0x0
...@@ -41,6 +46,8 @@ ...@@ -41,6 +46,8 @@
#define CORE_VENDOR_SPEC 0x10c #define CORE_VENDOR_SPEC 0x10c
#define CORE_CLK_PWRSAVE BIT(1) #define CORE_CLK_PWRSAVE BIT(1)
#define CORE_VENDOR_SPEC_CAPABILITIES0 0x11c
#define CDR_SELEXT_SHIFT 20 #define CDR_SELEXT_SHIFT 20
#define CDR_SELEXT_MASK (0xf << CDR_SELEXT_SHIFT) #define CDR_SELEXT_MASK (0xf << CDR_SELEXT_SHIFT)
#define CMUX_SHIFT_PHASE_SHIFT 24 #define CMUX_SHIFT_PHASE_SHIFT 24
...@@ -426,7 +433,9 @@ static int sdhci_msm_probe(struct platform_device *pdev) ...@@ -426,7 +433,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)
struct sdhci_msm_host *msm_host; struct sdhci_msm_host *msm_host;
struct resource *core_memres; struct resource *core_memres;
int ret; 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); msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL);
if (!msm_host) if (!msm_host)
...@@ -516,6 +525,24 @@ static int sdhci_msm_probe(struct platform_device *pdev) ...@@ -516,6 +525,24 @@ static int sdhci_msm_probe(struct platform_device *pdev)
host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >> host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
SDHCI_VENDOR_VER_SHIFT)); 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); ret = sdhci_add_host(host);
if (ret) if (ret)
goto clk_disable; goto clk_disable;
......
...@@ -173,6 +173,12 @@ static int sdhci_arasan_probe(struct platform_device *pdev) ...@@ -173,6 +173,12 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
pltfm_host->priv = sdhci_arasan; pltfm_host->priv = sdhci_arasan;
pltfm_host->clk = clk_xin; 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); ret = sdhci_add_host(host);
if (ret) if (ret)
goto err_pltfm_free; goto err_pltfm_free;
...@@ -195,7 +201,6 @@ static int sdhci_arasan_remove(struct platform_device *pdev) ...@@ -195,7 +201,6 @@ static int sdhci_arasan_remove(struct platform_device *pdev)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_arasan_data *sdhci_arasan = pltfm_host->priv; struct sdhci_arasan_data *sdhci_arasan = pltfm_host->priv;
clk_disable_unprepare(pltfm_host->clk);
clk_disable_unprepare(sdhci_arasan->clk_ahb); clk_disable_unprepare(sdhci_arasan->clk_ahb);
return sdhci_pltfm_unregister(pdev); return sdhci_pltfm_unregister(pdev);
......
...@@ -386,11 +386,6 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) ...@@ -386,11 +386,6 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
return ret; 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[] = { static const struct of_device_id sdhci_esdhc_of_match[] = {
{ .compatible = "fsl,mpc8379-esdhc" }, { .compatible = "fsl,mpc8379-esdhc" },
{ .compatible = "fsl,mpc8536-esdhc" }, { .compatible = "fsl,mpc8536-esdhc" },
...@@ -406,7 +401,7 @@ static struct platform_driver sdhci_esdhc_driver = { ...@@ -406,7 +401,7 @@ static struct platform_driver sdhci_esdhc_driver = {
.pm = ESDHC_PMOPS, .pm = ESDHC_PMOPS,
}, },
.probe = sdhci_esdhc_probe, .probe = sdhci_esdhc_probe,
.remove = sdhci_esdhc_remove, .remove = sdhci_pltfm_unregister,
}; };
module_platform_driver(sdhci_esdhc_driver); module_platform_driver(sdhci_esdhc_driver);
......
...@@ -75,11 +75,6 @@ static int sdhci_hlwd_probe(struct platform_device *pdev) ...@@ -75,11 +75,6 @@ static int sdhci_hlwd_probe(struct platform_device *pdev)
return sdhci_pltfm_register(pdev, &sdhci_hlwd_pdata, 0); 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[] = { static const struct of_device_id sdhci_hlwd_of_match[] = {
{ .compatible = "nintendo,hollywood-sdhci" }, { .compatible = "nintendo,hollywood-sdhci" },
{ } { }
...@@ -93,7 +88,7 @@ static struct platform_driver sdhci_hlwd_driver = { ...@@ -93,7 +88,7 @@ static struct platform_driver sdhci_hlwd_driver = {
.pm = SDHCI_PLTFM_PMOPS, .pm = SDHCI_PLTFM_PMOPS,
}, },
.probe = sdhci_hlwd_probe, .probe = sdhci_hlwd_probe,
.remove = sdhci_hlwd_remove, .remove = sdhci_pltfm_unregister,
}; };
module_platform_driver(sdhci_hlwd_driver); module_platform_driver(sdhci_hlwd_driver);
......
...@@ -650,6 +650,7 @@ static int rtsx_probe_slot(struct sdhci_pci_slot *slot) ...@@ -650,6 +650,7 @@ static int rtsx_probe_slot(struct sdhci_pci_slot *slot)
static const struct sdhci_pci_fixes sdhci_rtsx = { static const struct sdhci_pci_fixes sdhci_rtsx = {
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
SDHCI_QUIRK2_BROKEN_64_BIT_DMA |
SDHCI_QUIRK2_BROKEN_DDR50, SDHCI_QUIRK2_BROKEN_DDR50,
.probe_slot = rtsx_probe_slot, .probe_slot = rtsx_probe_slot,
}; };
......
...@@ -75,43 +75,41 @@ void sdhci_get_of_property(struct platform_device *pdev) ...@@ -75,43 +75,41 @@ void sdhci_get_of_property(struct platform_device *pdev)
u32 bus_width; u32 bus_width;
int size; int size;
if (of_device_is_available(np)) { if (of_get_property(np, "sdhci,auto-cmd12", NULL))
if (of_get_property(np, "sdhci,auto-cmd12", NULL)) host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
host->quirks |= SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12;
if (of_get_property(np, "sdhci,1-bit-only", NULL) || if (of_get_property(np, "sdhci,1-bit-only", NULL) ||
(of_property_read_u32(np, "bus-width", &bus_width) == 0 && (of_property_read_u32(np, "bus-width", &bus_width) == 0 &&
bus_width == 1)) bus_width == 1))
host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA; host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
if (sdhci_of_wp_inverted(np)) if (sdhci_of_wp_inverted(np))
host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT; host->quirks |= SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
if (of_get_property(np, "broken-cd", NULL)) if (of_get_property(np, "broken-cd", NULL))
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION; host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
if (of_get_property(np, "no-1-8-v", NULL)) if (of_get_property(np, "no-1-8-v", NULL))
host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc")) if (of_device_is_compatible(np, "fsl,p2020-rev1-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_DMA; host->quirks |= SDHCI_QUIRK_BROKEN_DMA;
if (of_device_is_compatible(np, "fsl,p2020-esdhc") || if (of_device_is_compatible(np, "fsl,p2020-esdhc") ||
of_device_is_compatible(np, "fsl,p1010-esdhc") || of_device_is_compatible(np, "fsl,p1010-esdhc") ||
of_device_is_compatible(np, "fsl,t4240-esdhc") || of_device_is_compatible(np, "fsl,t4240-esdhc") ||
of_device_is_compatible(np, "fsl,mpc8536-esdhc")) of_device_is_compatible(np, "fsl,mpc8536-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
clk = of_get_property(np, "clock-frequency", &size); clk = of_get_property(np, "clock-frequency", &size);
if (clk && size == sizeof(*clk) && *clk) if (clk && size == sizeof(*clk) && *clk)
pltfm_host->clock = be32_to_cpup(clk); pltfm_host->clock = be32_to_cpup(clk);
if (of_find_property(np, "keep-power-in-suspend", NULL)) if (of_find_property(np, "keep-power-in-suspend", NULL))
host->mmc->pm_caps |= MMC_PM_KEEP_POWER; host->mmc->pm_caps |= MMC_PM_KEEP_POWER;
if (of_find_property(np, "enable-sdio-wakeup", NULL)) if (of_find_property(np, "enable-sdio-wakeup", NULL))
host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
}
} }
#else #else
void sdhci_get_of_property(struct platform_device *pdev) {} void sdhci_get_of_property(struct platform_device *pdev) {}
...@@ -225,9 +223,11 @@ EXPORT_SYMBOL_GPL(sdhci_pltfm_register); ...@@ -225,9 +223,11 @@ EXPORT_SYMBOL_GPL(sdhci_pltfm_register);
int sdhci_pltfm_unregister(struct platform_device *pdev) int sdhci_pltfm_unregister(struct platform_device *pdev)
{ {
struct sdhci_host *host = platform_get_drvdata(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); int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
sdhci_remove_host(host, dead); sdhci_remove_host(host, dead);
clk_disable_unprepare(pltfm_host->clk);
sdhci_pltfm_free(pdev); sdhci_pltfm_free(pdev);
return 0; return 0;
......
...@@ -20,17 +20,9 @@ ...@@ -20,17 +20,9 @@
#define SIRF_TUNING_COUNT 128 #define SIRF_TUNING_COUNT 128
struct sdhci_sirf_priv { struct sdhci_sirf_priv {
struct clk *clk;
int gpio_cd; 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) static void sdhci_sirf_set_bus_width(struct sdhci_host *host, int width)
{ {
u8 ctrl; u8 ctrl;
...@@ -56,7 +48,7 @@ static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode) ...@@ -56,7 +48,7 @@ static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode)
int tuning_seq_cnt = 3; int tuning_seq_cnt = 3;
u8 phase, tuned_phases[SIRF_TUNING_COUNT]; u8 phase, tuned_phases[SIRF_TUNING_COUNT];
u8 tuned_phase_cnt = 0; 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; int start = -1, end = 0, tuning_value = -1, range = 0;
u16 clock_setting; u16 clock_setting;
struct mmc_host *mmc = host->mmc; struct mmc_host *mmc = host->mmc;
...@@ -68,7 +60,7 @@ static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode) ...@@ -68,7 +60,7 @@ static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode)
phase = 0; phase = 0;
do { do {
sdhci_writel(host, sdhci_writel(host,
clock_setting | phase | (phase << 7) | (phase << 16), clock_setting | phase,
SDHCI_CLK_DELAY_SETTING); SDHCI_CLK_DELAY_SETTING);
if (!mmc_send_tuning(mmc)) { if (!mmc_send_tuning(mmc)) {
...@@ -102,7 +94,7 @@ static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode) ...@@ -102,7 +94,7 @@ static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode)
*/ */
phase = tuning_value; phase = tuning_value;
sdhci_writel(host, sdhci_writel(host,
clock_setting | phase | (phase << 7) | (phase << 16), clock_setting | phase,
SDHCI_CLK_DELAY_SETTING); SDHCI_CLK_DELAY_SETTING);
dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n", dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
...@@ -122,7 +114,7 @@ static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode) ...@@ -122,7 +114,7 @@ static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode)
static struct sdhci_ops sdhci_sirf_ops = { static struct sdhci_ops sdhci_sirf_ops = {
.platform_execute_tuning = sdhci_sirf_execute_tuning, .platform_execute_tuning = sdhci_sirf_execute_tuning,
.set_clock = sdhci_set_clock, .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, .set_bus_width = sdhci_sirf_set_bus_width,
.reset = sdhci_reset, .reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling, .set_uhs_signaling = sdhci_set_uhs_signaling,
...@@ -162,13 +154,13 @@ static int sdhci_sirf_probe(struct platform_device *pdev) ...@@ -162,13 +154,13 @@ static int sdhci_sirf_probe(struct platform_device *pdev)
return PTR_ERR(host); return PTR_ERR(host);
pltfm_host = sdhci_priv(host); pltfm_host = sdhci_priv(host);
pltfm_host->clk = clk;
priv = sdhci_pltfm_priv(pltfm_host); priv = sdhci_pltfm_priv(pltfm_host);
priv->clk = clk;
priv->gpio_cd = gpio_cd; priv->gpio_cd = gpio_cd;
sdhci_get_of_property(pdev); sdhci_get_of_property(pdev);
ret = clk_prepare_enable(priv->clk); ret = clk_prepare_enable(pltfm_host->clk);
if (ret) if (ret)
goto err_clk_prepare; goto err_clk_prepare;
...@@ -195,37 +187,24 @@ static int sdhci_sirf_probe(struct platform_device *pdev) ...@@ -195,37 +187,24 @@ static int sdhci_sirf_probe(struct platform_device *pdev)
err_request_cd: err_request_cd:
sdhci_remove_host(host, 0); sdhci_remove_host(host, 0);
err_sdhci_add: err_sdhci_add:
clk_disable_unprepare(priv->clk); clk_disable_unprepare(pltfm_host->clk);
err_clk_prepare: err_clk_prepare:
sdhci_pltfm_free(pdev); sdhci_pltfm_free(pdev);
return ret; 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 #ifdef CONFIG_PM_SLEEP
static int sdhci_sirf_suspend(struct device *dev) static int sdhci_sirf_suspend(struct device *dev)
{ {
struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
int ret; int ret;
ret = sdhci_suspend_host(host); ret = sdhci_suspend_host(host);
if (ret) if (ret)
return ret; return ret;
clk_disable(priv->clk); clk_disable(pltfm_host->clk);
return 0; return 0;
} }
...@@ -234,10 +213,9 @@ static int sdhci_sirf_resume(struct device *dev) ...@@ -234,10 +213,9 @@ static int sdhci_sirf_resume(struct device *dev)
{ {
struct sdhci_host *host = dev_get_drvdata(dev); struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_sirf_priv *priv = sdhci_pltfm_priv(pltfm_host);
int ret; int ret;
ret = clk_enable(priv->clk); ret = clk_enable(pltfm_host->clk);
if (ret) { if (ret) {
dev_dbg(dev, "Resume: Error enabling clock\n"); dev_dbg(dev, "Resume: Error enabling clock\n");
return ret; return ret;
...@@ -264,7 +242,7 @@ static struct platform_driver sdhci_sirf_driver = { ...@@ -264,7 +242,7 @@ static struct platform_driver sdhci_sirf_driver = {
#endif #endif
}, },
.probe = sdhci_sirf_probe, .probe = sdhci_sirf_probe,
.remove = sdhci_sirf_remove, .remove = sdhci_pltfm_unregister,
}; };
module_platform_driver(sdhci_sirf_driver); module_platform_driver(sdhci_sirf_driver);
......
...@@ -26,14 +26,13 @@ ...@@ -26,14 +26,13 @@
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/sdhci-spear.h>
#include <linux/mmc/slot-gpio.h> #include <linux/mmc/slot-gpio.h>
#include <linux/io.h> #include <linux/io.h>
#include "sdhci.h" #include "sdhci.h"
struct spear_sdhci { struct spear_sdhci {
struct clk *clk; struct clk *clk;
struct sdhci_plat_data *data; int card_int_gpio;
}; };
/* sdhci ops */ /* sdhci ops */
...@@ -44,38 +43,20 @@ static const struct sdhci_ops sdhci_pltfm_ops = { ...@@ -44,38 +43,20 @@ static const struct sdhci_ops sdhci_pltfm_ops = {
.set_uhs_signaling = sdhci_set_uhs_signaling, .set_uhs_signaling = sdhci_set_uhs_signaling,
}; };
#ifdef CONFIG_OF static void sdhci_probe_config_dt(struct device_node *np,
static struct sdhci_plat_data *sdhci_probe_config_dt(struct platform_device *pdev) struct spear_sdhci *host)
{ {
struct device_node *np = pdev->dev.of_node;
struct sdhci_plat_data *pdata = NULL;
int cd_gpio; int cd_gpio;
cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
if (!gpio_is_valid(cd_gpio)) if (!gpio_is_valid(cd_gpio))
cd_gpio = -1; cd_gpio = -1;
/* If pdata is required */ host->card_int_gpio = cd_gpio;
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);
} }
#endif
static int sdhci_probe(struct platform_device *pdev) static int sdhci_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node;
struct sdhci_host *host; struct sdhci_host *host;
struct resource *iomem; struct resource *iomem;
struct spear_sdhci *sdhci; struct spear_sdhci *sdhci;
...@@ -124,28 +105,18 @@ static int sdhci_probe(struct platform_device *pdev) ...@@ -124,28 +105,18 @@ static int sdhci_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "Error setting desired clk, clk=%lu\n", dev_dbg(&pdev->dev, "Error setting desired clk, clk=%lu\n",
clk_get_rate(sdhci->clk)); clk_get_rate(sdhci->clk));
if (np) { sdhci_probe_config_dt(pdev->dev.of_node, sdhci);
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);
}
/* /*
* It is optional to use GPIOs for sdhci card detection. If * 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. * GPIO lines. We use the built-in GPIO support for this.
*/ */
if (sdhci->data && sdhci->data->card_int_gpio >= 0) { if (sdhci->card_int_gpio >= 0) {
ret = mmc_gpio_request_cd(host->mmc, ret = mmc_gpio_request_cd(host->mmc, sdhci->card_int_gpio, 0);
sdhci->data->card_int_gpio, 0);
if (ret < 0) { if (ret < 0) {
dev_dbg(&pdev->dev, dev_dbg(&pdev->dev,
"failed to request card-detect gpio%d\n", "failed to request card-detect gpio%d\n",
sdhci->data->card_int_gpio); sdhci->card_int_gpio);
goto disable_clk; goto disable_clk;
} }
} }
......
This diff is collapsed.
...@@ -20,11 +20,10 @@ ...@@ -20,11 +20,10 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/mmc/card.h> #include <linux/mmc/card.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/slot-gpio.h> #include <linux/mmc/slot-gpio.h>
#include <linux/gpio/consumer.h>
#include "sdhci-pltfm.h" #include "sdhci-pltfm.h"
...@@ -41,7 +40,6 @@ ...@@ -41,7 +40,6 @@
#define NVQUIRK_DISABLE_SDR50 BIT(3) #define NVQUIRK_DISABLE_SDR50 BIT(3)
#define NVQUIRK_DISABLE_SDR104 BIT(4) #define NVQUIRK_DISABLE_SDR104 BIT(4)
#define NVQUIRK_DISABLE_DDR50 BIT(5) #define NVQUIRK_DISABLE_DDR50 BIT(5)
#define NVQUIRK_SHADOW_XFER_MODE_REG BIT(6)
struct sdhci_tegra_soc_data { struct sdhci_tegra_soc_data {
const struct sdhci_pltfm_data *pdata; const struct sdhci_pltfm_data *pdata;
...@@ -50,7 +48,7 @@ struct sdhci_tegra_soc_data { ...@@ -50,7 +48,7 @@ struct sdhci_tegra_soc_data {
struct sdhci_tegra { struct sdhci_tegra {
const struct sdhci_tegra_soc_data *soc_data; 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) 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) ...@@ -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) static void tegra_sdhci_writew(struct sdhci_host *host, u16 val, int reg)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 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) {
switch (reg) { case SDHCI_TRANSFER_MODE:
case SDHCI_TRANSFER_MODE: /*
/* * Postpone this write, we must do it together with a
* Postpone this write, we must do it together with a * command write that is down below.
* command write that is down below. */
*/ pltfm_host->xfer_mode_shadow = val;
pltfm_host->xfer_mode_shadow = val; return;
return; case SDHCI_COMMAND:
case SDHCI_COMMAND: writel((val << 16) | pltfm_host->xfer_mode_shadow,
writel((val << 16) | pltfm_host->xfer_mode_shadow, host->ioaddr + SDHCI_TRANSFER_MODE);
host->ioaddr + SDHCI_TRANSFER_MODE); return;
return;
}
} }
writew(val, host->ioaddr + reg); writew(val, host->ioaddr + reg);
...@@ -173,7 +167,6 @@ static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width) ...@@ -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 = { static const struct sdhci_ops tegra_sdhci_ops = {
.get_ro = tegra_sdhci_get_ro, .get_ro = tegra_sdhci_get_ro,
.read_w = tegra_sdhci_readw, .read_w = tegra_sdhci_readw,
.write_w = tegra_sdhci_writew,
.write_l = tegra_sdhci_writel, .write_l = tegra_sdhci_writel,
.set_clock = sdhci_set_clock, .set_clock = sdhci_set_clock,
.set_bus_width = tegra_sdhci_set_bus_width, .set_bus_width = tegra_sdhci_set_bus_width,
...@@ -214,6 +207,18 @@ static struct sdhci_tegra_soc_data soc_data_tegra30 = { ...@@ -214,6 +207,18 @@ static struct sdhci_tegra_soc_data soc_data_tegra30 = {
NVQUIRK_DISABLE_SDR104, 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 = { static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
...@@ -221,15 +226,14 @@ static const struct sdhci_pltfm_data sdhci_tegra114_pdata = { ...@@ -221,15 +226,14 @@ static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {
SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN, SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
.ops = &tegra_sdhci_ops, .ops = &tegra114_sdhci_ops,
}; };
static struct sdhci_tegra_soc_data soc_data_tegra114 = { static struct sdhci_tegra_soc_data soc_data_tegra114 = {
.pdata = &sdhci_tegra114_pdata, .pdata = &sdhci_tegra114_pdata,
.nvquirks = NVQUIRK_DISABLE_SDR50 | .nvquirks = NVQUIRK_DISABLE_SDR50 |
NVQUIRK_DISABLE_DDR50 | NVQUIRK_DISABLE_DDR50 |
NVQUIRK_DISABLE_SDR104 | NVQUIRK_DISABLE_SDR104,
NVQUIRK_SHADOW_XFER_MODE_REG,
}; };
static const struct of_device_id sdhci_tegra_dt_match[] = { static const struct of_device_id sdhci_tegra_dt_match[] = {
...@@ -241,17 +245,6 @@ 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); 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) static int sdhci_tegra_probe(struct platform_device *pdev)
{ {
const struct of_device_id *match; const struct of_device_id *match;
...@@ -281,21 +274,18 @@ static int sdhci_tegra_probe(struct platform_device *pdev) ...@@ -281,21 +274,18 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
tegra_host->soc_data = soc_data; tegra_host->soc_data = soc_data;
pltfm_host->priv = tegra_host; pltfm_host->priv = tegra_host;
rc = sdhci_tegra_parse_dt(&pdev->dev); rc = mmc_of_parse(host->mmc);
if (rc) if (rc)
goto err_parse_dt; goto err_parse_dt;
if (gpio_is_valid(tegra_host->power_gpio)) { tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power",
rc = gpio_request(tegra_host->power_gpio, "sdhci_power"); GPIOD_OUT_HIGH);
if (rc) { if (IS_ERR(tegra_host->power_gpio)) {
dev_err(mmc_dev(host->mmc), rc = PTR_ERR(tegra_host->power_gpio);
"failed to allocate power gpio\n"); goto err_power_req;
goto err_power_req;
}
gpio_direction_output(tegra_host->power_gpio, 1);
} }
clk = clk_get(mmc_dev(host->mmc), NULL); clk = devm_clk_get(mmc_dev(host->mmc), NULL);
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
dev_err(mmc_dev(host->mmc), "clk err\n"); dev_err(mmc_dev(host->mmc), "clk err\n");
rc = PTR_ERR(clk); rc = PTR_ERR(clk);
...@@ -312,10 +302,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev) ...@@ -312,10 +302,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
err_add_host: err_add_host:
clk_disable_unprepare(pltfm_host->clk); clk_disable_unprepare(pltfm_host->clk);
clk_put(pltfm_host->clk);
err_clk_get: err_clk_get:
if (gpio_is_valid(tegra_host->power_gpio))
gpio_free(tegra_host->power_gpio);
err_power_req: err_power_req:
err_parse_dt: err_parse_dt:
err_alloc_tegra_host: err_alloc_tegra_host:
...@@ -323,26 +310,6 @@ static int sdhci_tegra_probe(struct platform_device *pdev) ...@@ -323,26 +310,6 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
return rc; 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 = { static struct platform_driver sdhci_tegra_driver = {
.driver = { .driver = {
.name = "sdhci-tegra", .name = "sdhci-tegra",
...@@ -350,7 +317,7 @@ static struct platform_driver sdhci_tegra_driver = { ...@@ -350,7 +317,7 @@ static struct platform_driver sdhci_tegra_driver = {
.pm = SDHCI_PLTFM_PMOPS, .pm = SDHCI_PLTFM_PMOPS,
}, },
.probe = sdhci_tegra_probe, .probe = sdhci_tegra_probe,
.remove = sdhci_tegra_remove, .remove = sdhci_pltfm_unregister,
}; };
module_platform_driver(sdhci_tegra_driver); module_platform_driver(sdhci_tegra_driver);
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/mmc/mmc.h> #include <linux/mmc/mmc.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/card.h> #include <linux/mmc/card.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/slot-gpio.h> #include <linux/mmc/slot-gpio.h>
#include "sdhci.h" #include "sdhci.h"
...@@ -56,6 +57,7 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); ...@@ -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, static int sdhci_pre_dma_transfer(struct sdhci_host *host,
struct mmc_data *data, struct mmc_data *data,
struct sdhci_host_next *next); struct sdhci_host_next *next);
static int sdhci_do_get_cd(struct sdhci_host *host);
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int sdhci_runtime_pm_get(struct sdhci_host *host); static int sdhci_runtime_pm_get(struct sdhci_host *host);
...@@ -931,7 +933,8 @@ static void sdhci_set_transfer_mode(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 * If we are sending CMD23, CMD12 never gets sent
* on successful completion (so no Auto-CMD12). * 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; mode |= SDHCI_TRNS_AUTO_CMD12;
else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) { else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
mode |= SDHCI_TRNS_AUTO_CMD23; mode |= SDHCI_TRNS_AUTO_CMD23;
...@@ -1356,7 +1359,8 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -1356,7 +1359,8 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
sdhci_runtime_pm_get(host); 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); spin_lock_irqsave(&host->lock, flags);
...@@ -1379,22 +1383,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -1379,22 +1383,6 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
host->mrq = 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) { if (!present || host->flags & SDHCI_DEVICE_DEAD) {
host->mrq->cmd->error = -ENOMEDIUM; host->mrq->cmd->error = -ENOMEDIUM;
tasklet_schedule(&host->finish_tasklet); tasklet_schedule(&host->finish_tasklet);
...@@ -3164,7 +3152,8 @@ int sdhci_add_host(struct sdhci_host *host) ...@@ -3164,7 +3152,8 @@ int sdhci_add_host(struct sdhci_host *host)
/* Auto-CMD23 stuff only works in ADMA or PIO. */ /* Auto-CMD23 stuff only works in ADMA or PIO. */
if ((host->version >= SDHCI_SPEC_300) && if ((host->version >= SDHCI_SPEC_300) &&
((host->flags & SDHCI_USE_ADMA) || ((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; host->flags |= SDHCI_AUTO_CMD23;
DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc)); DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc));
} else { } else {
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/mmc/sdhci.h> #include <linux/mmc/host.h>
/* /*
* Controller registers * Controller registers
...@@ -309,6 +309,207 @@ struct sdhci_adma2_64_desc { ...@@ -309,6 +309,207 @@ struct sdhci_adma2_64_desc {
*/ */
#define SDHCI_MAX_SEGS 128 #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 { struct sdhci_ops {
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
u32 (*read_l)(struct sdhci_host *host, int reg); u32 (*read_l)(struct sdhci_host *host, int reg);
......
...@@ -875,6 +875,7 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, ...@@ -875,6 +875,7 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
struct mmc_command *cmd = mrq->cmd; struct mmc_command *cmd = mrq->cmd;
u32 opc = cmd->opcode; u32 opc = cmd->opcode;
u32 mask; u32 mask;
unsigned long flags;
switch (opc) { switch (opc) {
/* response busy check */ /* response busy check */
...@@ -909,10 +910,12 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host, ...@@ -909,10 +910,12 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
/* set arg */ /* set arg */
sh_mmcif_writel(host->addr, MMCIF_CE_ARG, cmd->arg); sh_mmcif_writel(host->addr, MMCIF_CE_ARG, cmd->arg);
/* set cmd */ /* set cmd */
spin_lock_irqsave(&host->lock, flags);
sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc); sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc);
host->wait_for = MMCIF_WAIT_FOR_CMD; host->wait_for = MMCIF_WAIT_FOR_CMD;
schedule_delayed_work(&host->timeout_work, host->timeout); 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, 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) ...@@ -1171,6 +1174,12 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
struct sh_mmcif_host *host = dev_id; struct sh_mmcif_host *host = dev_id;
struct mmc_request *mrq; struct mmc_request *mrq;
bool wait = false; 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); cancel_delayed_work_sync(&host->timeout_work);
...@@ -1188,7 +1197,7 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id) ...@@ -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 * All handlers return true, if processing continues, and false, if the
* request has to be completed - successfully or not * request has to be completed - successfully or not
*/ */
switch (host->wait_for) { switch (wait_work) {
case MMCIF_WAIT_FOR_REQUEST: case MMCIF_WAIT_FOR_REQUEST:
/* We're too late, the timeout has already kicked in */ /* We're too late, the timeout has already kicked in */
mutex_unlock(&host->thread_lock); mutex_unlock(&host->thread_lock);
...@@ -1312,15 +1321,15 @@ static void mmcif_timeout_work(struct work_struct *work) ...@@ -1312,15 +1321,15 @@ static void mmcif_timeout_work(struct work_struct *work)
/* Don't run after mmc_remove_host() */ /* Don't run after mmc_remove_host() */
return; 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); spin_lock_irqsave(&host->lock, flags);
if (host->state == STATE_IDLE) { if (host->state == STATE_IDLE) {
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
return; return;
} }
dev_err(&host->pd->dev, "Timeout waiting for %u on CMD%u\n",
host->wait_for, mrq->cmd->opcode);
host->state = STATE_TIMEOUT; host->state = STATE_TIMEOUT;
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
......
...@@ -293,7 +293,7 @@ static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host, ...@@ -293,7 +293,7 @@ static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host,
struct mmc_data *data) struct mmc_data *data)
{ {
struct sunxi_idma_des *pdes = (struct sunxi_idma_des *)host->sg_cpu; 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); int i, max_len = (1 << host->idma_des_size_bits);
for (i = 0; i < data->sg_len; i++) { for (i = 0; i < data->sg_len; i++) {
...@@ -305,8 +305,9 @@ static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host, ...@@ -305,8 +305,9 @@ static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host,
else else
pdes[i].buf_size = data->sg[i].length; 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_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; pdes[0].config |= SDXC_IDMAC_DES0_FD;
...@@ -930,7 +931,9 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host, ...@@ -930,7 +931,9 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
return PTR_ERR(host->clk_sample); 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); ret = clk_prepare_enable(host->clk_ahb);
if (ret) { if (ret) {
...@@ -1028,7 +1031,7 @@ static int sunxi_mmc_probe(struct platform_device *pdev) ...@@ -1028,7 +1031,7 @@ static int sunxi_mmc_probe(struct platform_device *pdev)
mmc->f_min = 400000; mmc->f_min = 400000;
mmc->f_max = 50000000; mmc->f_max = 50000000;
mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | 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); ret = mmc_of_parse(mmc);
if (ret) if (ret)
......
...@@ -1073,8 +1073,6 @@ EXPORT_SYMBOL(tmio_mmc_host_alloc); ...@@ -1073,8 +1073,6 @@ EXPORT_SYMBOL(tmio_mmc_host_alloc);
void tmio_mmc_host_free(struct tmio_mmc_host *host) void tmio_mmc_host_free(struct tmio_mmc_host *host)
{ {
mmc_free_host(host->mmc); mmc_free_host(host->mmc);
host->mmc = NULL;
} }
EXPORT_SYMBOL(tmio_mmc_host_free); EXPORT_SYMBOL(tmio_mmc_host_free);
......
...@@ -744,7 +744,7 @@ static struct wmt_mci_caps wm8505_caps = { ...@@ -744,7 +744,7 @@ static struct wmt_mci_caps wm8505_caps = {
.max_blk_size = 2048, .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 }, { .compatible = "wm,wm8505-sdhc", .data = &wm8505_caps },
{ /* Sentinel */ }, { /* Sentinel */ },
}; };
......
...@@ -79,7 +79,7 @@ struct mmc_command { ...@@ -79,7 +79,7 @@ struct mmc_command {
#define mmc_cmd_type(cmd) ((cmd)->flags & MMC_CMD_MASK) #define mmc_cmd_type(cmd) ((cmd)->flags & MMC_CMD_MASK)
unsigned int retries; /* max number of retries */ 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 * Standard errno values are used for errors, but some have specific
...@@ -108,7 +108,7 @@ struct mmc_data { ...@@ -108,7 +108,7 @@ struct mmc_data {
unsigned int timeout_clks; /* data timeout (in clocks) */ unsigned int timeout_clks; /* data timeout (in clocks) */
unsigned int blksz; /* data block size */ unsigned int blksz; /* data block size */
unsigned int blocks; /* number of blocks */ unsigned int blocks; /* number of blocks */
unsigned int error; /* data error */ int error; /* data error */
unsigned int flags; unsigned int flags;
#define MMC_DATA_WRITE (1 << 8) #define MMC_DATA_WRITE (1 << 8)
......
...@@ -44,6 +44,7 @@ struct mmc_data; ...@@ -44,6 +44,7 @@ struct mmc_data;
* struct dw_mci - MMC controller state shared between all slots * struct dw_mci - MMC controller state shared between all slots
* @lock: Spinlock protecting the queue and associated data. * @lock: Spinlock protecting the queue and associated data.
* @regs: Pointer to MMIO registers. * @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: Scatterlist entry currently being processed by PIO code, if any.
* @sg_miter: PIO mapping scatterlist iterator. * @sg_miter: PIO mapping scatterlist iterator.
* @cur_slot: The slot which is currently using the controller. * @cur_slot: The slot which is currently using the controller.
...@@ -79,7 +80,6 @@ struct mmc_data; ...@@ -79,7 +80,6 @@ struct mmc_data;
* @current_speed: Configured rate of the controller. * @current_speed: Configured rate of the controller.
* @num_slots: Number of slots available. * @num_slots: Number of slots available.
* @verid: Denote Version ID. * @verid: Denote Version ID.
* @data_offset: Set the offset of DATA register according to VERID.
* @dev: Device associated with the MMC controller. * @dev: Device associated with the MMC controller.
* @pdata: Platform data associated with the MMC controller. * @pdata: Platform data associated with the MMC controller.
* @drv_data: Driver specific data for identified variant of the controller * @drv_data: Driver specific data for identified variant of the controller
...@@ -132,6 +132,7 @@ struct dw_mci { ...@@ -132,6 +132,7 @@ struct dw_mci {
spinlock_t lock; spinlock_t lock;
spinlock_t irq_lock; spinlock_t irq_lock;
void __iomem *regs; void __iomem *regs;
void __iomem *fifo_reg;
struct scatterlist *sg; struct scatterlist *sg;
struct sg_mapping_iter sg_miter; struct sg_mapping_iter sg_miter;
...@@ -172,7 +173,6 @@ struct dw_mci { ...@@ -172,7 +173,6 @@ struct dw_mci {
u32 num_slots; u32 num_slots;
u32 fifoth_val; u32 fifoth_val;
u16 verid; u16 verid;
u16 data_offset;
struct device *dev; struct device *dev;
struct dw_mci_board *pdata; struct dw_mci_board *pdata;
const struct dw_mci_drv_data *drv_data; const struct dw_mci_drv_data *drv_data;
...@@ -202,6 +202,8 @@ struct dw_mci { ...@@ -202,6 +202,8 @@ struct dw_mci {
int irq; int irq;
int sdio_id0; int sdio_id0;
struct timer_list cmd11_timer;
}; };
/* DMA ops for Internal/External DMAC interface */ /* DMA ops for Internal/External DMAC interface */
......
...@@ -79,12 +79,6 @@ struct mmc_ios { ...@@ -79,12 +79,6 @@ struct mmc_ios {
}; };
struct mmc_host_ops { 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 * It is optional for the host to implement pre_req and post_req in
* order to support double buffering of requests (prepare one * order to support double buffering of requests (prepare one
......
/*
* 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 */
/*
* 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 */
...@@ -55,9 +55,6 @@ struct omap_hsmmc_platform_data { ...@@ -55,9 +55,6 @@ struct omap_hsmmc_platform_data {
u32 caps; /* Used for the MMC driver on 2430 and later */ u32 caps; /* Used for the MMC driver on 2430 and later */
u32 pm_caps; /* PM capabilities of the mmc */ 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 */ /* use the internal clock */
unsigned internal_clock:1; unsigned internal_clock:1;
...@@ -73,7 +70,8 @@ struct omap_hsmmc_platform_data { ...@@ -73,7 +70,8 @@ struct omap_hsmmc_platform_data {
#define HSMMC_HAS_HSPE_SUPPORT (1 << 2) #define HSMMC_HAS_HSPE_SUPPORT (1 << 2)
unsigned features; 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 gpio_wp; /* gpio (write protect) */
int (*set_power)(struct device *dev, int power_on, int vdd); int (*set_power)(struct device *dev, int power_on, int vdd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment