diff options
-rw-r--r-- | Documentation/devicetree/bindings/mmc/mmci.txt | 54 | ||||
-rw-r--r-- | arch/arm/boot/dts/ste-ccu9540.dts | 6 | ||||
-rw-r--r-- | arch/arm/boot/dts/ste-href.dtsi | 19 | ||||
-rw-r--r-- | arch/arm/boot/dts/ste-nomadik-stn8815.dtsi | 4 | ||||
-rw-r--r-- | arch/arm/boot/dts/ste-snowball.dts | 4 | ||||
-rw-r--r-- | arch/arm/boot/dts/ste-u300.dts | 4 | ||||
-rw-r--r-- | arch/arm/mach-lpc32xx/phy3250.c | 3 | ||||
-rw-r--r-- | arch/arm/mach-ux500/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/mach-ux500/board-mop500-sdi.c | 166 | ||||
-rw-r--r-- | arch/arm/mach-ux500/board-mop500.h | 5 | ||||
-rw-r--r-- | arch/arm/mach-ux500/cpu-db8500.c | 4 | ||||
-rw-r--r-- | drivers/mmc/host/mmci.c | 324 | ||||
-rw-r--r-- | drivers/mmc/host/mmci.h | 14 | ||||
-rw-r--r-- | include/linux/amba/mmci.h | 42 |
14 files changed, 169 insertions, 483 deletions
diff --git a/Documentation/devicetree/bindings/mmc/mmci.txt b/Documentation/devicetree/bindings/mmc/mmci.txt index 2b584cae352a..03796cf2d3e7 100644 --- a/Documentation/devicetree/bindings/mmc/mmci.txt +++ b/Documentation/devicetree/bindings/mmc/mmci.txt @@ -4,12 +4,58 @@ The ARM PrimeCell MMCI PL180 and PL181 provides an interface for reading and writing to MultiMedia and SD cards alike. This file documents differences between the core properties described -by mmc.txt and the properties used by the mmci driver. +by mmc.txt and the properties used by the mmci driver. Using "st" as +the prefix for a property, indicates support by the ST Micro variant. Required properties: - compatible : contains "arm,pl18x", "arm,primecell". -- arm,primecell-periphid : contains the PrimeCell Peripheral ID. +- vmmc-supply : phandle to the regulator device tree node, mentioned + as the VCC/VDD supply in the eMMC/SD specs. Optional properties: -- mmc-cap-mmc-highspeed : indicates whether MMC is high speed capable -- mmc-cap-sd-highspeed : indicates whether SD is high speed capable +- arm,primecell-periphid : contains the PrimeCell Peripheral ID, it overrides + the ID provided by the HW +- vqmmc-supply : phandle to the regulator device tree node, mentioned + as the VCCQ/VDD_IO supply in the eMMC/SD specs. +- st,sig-dir-dat0 : bus signal direction pin used for DAT[0]. +- st,sig-dir-dat2 : bus signal direction pin used for DAT[2]. +- st,sig-dir-dat31 : bus signal direction pin used for DAT[3] and DAT[1]. +- st,sig-dir-dat74 : bus signal direction pin used for DAT[4] to DAT[7]. +- st,sig-dir-cmd : cmd signal direction pin used for CMD. +- st,sig-pin-fbclk : feedback clock signal pin used. + +Deprecated properties: +- mmc-cap-mmc-highspeed : indicates whether MMC is high speed capable. +- mmc-cap-sd-highspeed : indicates whether SD is high speed capable. + +Example: + +sdi0_per1@80126000 { + compatible = "arm,pl18x", "arm,primecell"; + reg = <0x80126000 0x1000>; + interrupts = <0 60 IRQ_TYPE_LEVEL_HIGH>; + + dmas = <&dma 29 0 0x2>, /* Logical - DevToMem */ + <&dma 29 0 0x0>; /* Logical - MemToDev */ + dma-names = "rx", "tx"; + + clocks = <&prcc_kclk 1 5>, <&prcc_pclk 1 5>; + clock-names = "sdi", "apb_pclk"; + + max-frequency = <100000000>; + bus-width = <4>; + cap-sd-highspeed; + cap-mmc-highspeed; + cd-gpios = <&gpio2 31 0x4>; // 95 + st,sig-dir-dat0; + st,sig-dir-dat2; + st,sig-dir-cmd; + st,sig-pin-fbclk; + + vmmc-supply = <&ab8500_ldo_aux3_reg>; + vqmmc-supply = <&vmmci>; + + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&sdi0_default_mode>; + pinctrl-1 = <&sdi0_sleep_mode>; +}; diff --git a/arch/arm/boot/dts/ste-ccu9540.dts b/arch/arm/boot/dts/ste-ccu9540.dts index 229508750890..651c56d400a4 100644 --- a/arch/arm/boot/dts/ste-ccu9540.dts +++ b/arch/arm/boot/dts/ste-ccu9540.dts @@ -38,8 +38,8 @@ arm,primecell-periphid = <0x10480180>; max-frequency = <100000000>; bus-width = <4>; - mmc-cap-sd-highspeed; - mmc-cap-mmc-highspeed; + cap-sd-highspeed; + cap-mmc-highspeed; vmmc-supply = <&ab8500_ldo_aux3_reg>; cd-gpios = <&gpio7 6 0x4>; // 230 @@ -63,7 +63,7 @@ arm,primecell-periphid = <0x10480180>; max-frequency = <100000000>; bus-width = <8>; - mmc-cap-mmc-highspeed; + cap-mmc-highspeed; vmmc-supply = <&ab8500_ldo_aux2_reg>; status = "okay"; diff --git a/arch/arm/boot/dts/ste-href.dtsi b/arch/arm/boot/dts/ste-href.dtsi index 6cb9b68e2188..bf8f0eddc2c0 100644 --- a/arch/arm/boot/dts/ste-href.dtsi +++ b/arch/arm/boot/dts/ste-href.dtsi @@ -116,8 +116,15 @@ arm,primecell-periphid = <0x10480180>; max-frequency = <100000000>; bus-width = <4>; - mmc-cap-sd-highspeed; - mmc-cap-mmc-highspeed; + cap-sd-highspeed; + cap-mmc-highspeed; + sd-uhs-sdr12; + sd-uhs-sdr25; + full-pwr-cycle; + st,sig-dir-dat0; + st,sig-dir-dat2; + st,sig-dir-cmd; + st,sig-pin-fbclk; vmmc-supply = <&ab8500_ldo_aux3_reg>; vqmmc-supply = <&vmmci>; pinctrl-names = "default", "sleep"; @@ -132,6 +139,7 @@ arm,primecell-periphid = <0x10480180>; max-frequency = <100000000>; bus-width = <4>; + non-removable; pinctrl-names = "default", "sleep"; pinctrl-0 = <&sdi1_default_mode>; pinctrl-1 = <&sdi1_sleep_mode>; @@ -144,7 +152,9 @@ arm,primecell-periphid = <0x10480180>; max-frequency = <100000000>; bus-width = <8>; - mmc-cap-mmc-highspeed; + cap-mmc-highspeed; + non-removable; + vmmc-supply = <&db8500_vsmps2_reg>; pinctrl-names = "default", "sleep"; pinctrl-0 = <&sdi2_default_mode>; pinctrl-1 = <&sdi2_sleep_mode>; @@ -157,7 +167,8 @@ arm,primecell-periphid = <0x10480180>; max-frequency = <100000000>; bus-width = <8>; - mmc-cap-mmc-highspeed; + cap-mmc-highspeed; + non-removable; vmmc-supply = <&ab8500_ldo_aux2_reg>; pinctrl-names = "default", "sleep"; pinctrl-0 = <&sdi4_default_mode>; diff --git a/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi index 5acc0449676a..d316c955bd5f 100644 --- a/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi +++ b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi @@ -840,8 +840,8 @@ interrupts = <22>; max-frequency = <48000000>; bus-width = <4>; - mmc-cap-mmc-highspeed; - mmc-cap-sd-highspeed; + cap-mmc-highspeed; + cap-sd-highspeed; cd-gpios = <&gpio3 15 0x1>; cd-inverted; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/ste-snowball.dts b/arch/arm/boot/dts/ste-snowball.dts index a2f632d0be2a..474ef83229cd 100644 --- a/arch/arm/boot/dts/ste-snowball.dts +++ b/arch/arm/boot/dts/ste-snowball.dts @@ -156,7 +156,7 @@ arm,primecell-periphid = <0x10480180>; max-frequency = <100000000>; bus-width = <4>; - mmc-cap-mmc-highspeed; + cap-mmc-highspeed; vmmc-supply = <&ab8500_ldo_aux3_reg>; vqmmc-supply = <&vmmci>; pinctrl-names = "default", "sleep"; @@ -195,7 +195,7 @@ arm,primecell-periphid = <0x10480180>; max-frequency = <100000000>; bus-width = <8>; - mmc-cap-mmc-highspeed; + cap-mmc-highspeed; vmmc-supply = <&ab8500_ldo_aux2_reg>; pinctrl-names = "default", "sleep"; pinctrl-0 = <&sdi4_default_mode>; diff --git a/arch/arm/boot/dts/ste-u300.dts b/arch/arm/boot/dts/ste-u300.dts index 6fe688e9e4da..82a661677e97 100644 --- a/arch/arm/boot/dts/ste-u300.dts +++ b/arch/arm/boot/dts/ste-u300.dts @@ -442,8 +442,8 @@ clock-names = "apb_pclk", "mclk"; max-frequency = <24000000>; bus-width = <4>; // SD-card slot - mmc-cap-mmc-highspeed; - mmc-cap-sd-highspeed; + cap-mmc-highspeed; + cap-sd-highspeed; cd-gpios = <&gpio 12 0x4>; cd-inverted; vmmc-supply = <&ab3100_ldo_g_reg>; diff --git a/arch/arm/mach-lpc32xx/phy3250.c b/arch/arm/mach-lpc32xx/phy3250.c index 34932e0e31fa..7858d5b6f6ce 100644 --- a/arch/arm/mach-lpc32xx/phy3250.c +++ b/arch/arm/mach-lpc32xx/phy3250.c @@ -202,9 +202,6 @@ static struct mmci_platform_data lpc32xx_mmci_data = { .ocr_mask = MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 | MMC_VDD_33_34, .ios_handler = mmc_handle_ios, - .dma_filter = NULL, - /* No DMA for now since AMBA PL080 dmaengine driver only does scatter - * gather, and the MMCI driver doesn't do it this way */ }; static struct lpc32xx_slc_platform_data lpc32xx_slc_data = { diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile index de544aabf292..9741de956b3e 100644 --- a/arch/arm/mach-ux500/Makefile +++ b/arch/arm/mach-ux500/Makefile @@ -5,8 +5,7 @@ obj-y := cpu.o id.o timer.o pm.o obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o -obj-$(CONFIG_MACH_MOP500) += board-mop500-sdi.o \ - board-mop500-regulators.o \ +obj-$(CONFIG_MACH_MOP500) += board-mop500-regulators.o \ board-mop500-audio.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o diff --git a/arch/arm/mach-ux500/board-mop500-sdi.c b/arch/arm/mach-ux500/board-mop500-sdi.c deleted file mode 100644 index fcbf3a13a539..000000000000 --- a/arch/arm/mach-ux500/board-mop500-sdi.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) ST-Ericsson SA 2010 - * - * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> - * License terms: GNU General Public License (GPL) version 2 - */ - -#include <linux/kernel.h> -#include <linux/gpio.h> -#include <linux/amba/bus.h> -#include <linux/amba/mmci.h> -#include <linux/mmc/host.h> -#include <linux/platform_device.h> -#include <linux/platform_data/dma-ste-dma40.h> - -#include <asm/mach-types.h> - -#include "db8500-regs.h" -#include "board-mop500.h" -#include "ste-dma40-db8500.h" - -/* - * v2 has a new version of this block that need to be forced, the number found - * in hardware is incorrect - */ -#define U8500_SDI_V2_PERIPHID 0x10480180 - -/* - * SDI 0 (MicroSD slot) - */ - -#ifdef CONFIG_STE_DMA40 -struct stedma40_chan_cfg mop500_sdi0_dma_cfg_rx = { - .mode = STEDMA40_MODE_LOGICAL, - .dir = DMA_DEV_TO_MEM, - .dev_type = DB8500_DMA_DEV29_SD_MM0, -}; - -static struct stedma40_chan_cfg mop500_sdi0_dma_cfg_tx = { - .mode = STEDMA40_MODE_LOGICAL, - .dir = DMA_MEM_TO_DEV, - .dev_type = DB8500_DMA_DEV29_SD_MM0, -}; -#endif - -struct mmci_platform_data mop500_sdi0_data = { - .f_max = 100000000, - .capabilities = MMC_CAP_4_BIT_DATA | - MMC_CAP_SD_HIGHSPEED | - MMC_CAP_MMC_HIGHSPEED | - MMC_CAP_ERASE | - MMC_CAP_UHS_SDR12 | - MMC_CAP_UHS_SDR25, - .gpio_wp = -1, - .sigdir = MCI_ST_FBCLKEN | - MCI_ST_CMDDIREN | - MCI_ST_DATA0DIREN | - MCI_ST_DATA2DIREN, -#ifdef CONFIG_STE_DMA40 - .dma_filter = stedma40_filter, - .dma_rx_param = &mop500_sdi0_dma_cfg_rx, - .dma_tx_param = &mop500_sdi0_dma_cfg_tx, -#endif -}; - -/* - * SDI1 (SDIO WLAN) - */ -#ifdef CONFIG_STE_DMA40 -static struct stedma40_chan_cfg sdi1_dma_cfg_rx = { - .mode = STEDMA40_MODE_LOGICAL, - .dir = DMA_DEV_TO_MEM, - .dev_type = DB8500_DMA_DEV32_SD_MM1, -}; - -static struct stedma40_chan_cfg sdi1_dma_cfg_tx = { - .mode = STEDMA40_MODE_LOGICAL, - .dir = DMA_MEM_TO_DEV, - .dev_type = DB8500_DMA_DEV32_SD_MM1, -}; -#endif - -struct mmci_platform_data mop500_sdi1_data = { - .ocr_mask = MMC_VDD_29_30, - .f_max = 100000000, - .capabilities = MMC_CAP_4_BIT_DATA | - MMC_CAP_NONREMOVABLE, - .gpio_cd = -1, - .gpio_wp = -1, -#ifdef CONFIG_STE_DMA40 - .dma_filter = stedma40_filter, - .dma_rx_param = &sdi1_dma_cfg_rx, - .dma_tx_param = &sdi1_dma_cfg_tx, -#endif -}; - -/* - * SDI 2 (POP eMMC, not on DB8500ed) - */ - -#ifdef CONFIG_STE_DMA40 -struct stedma40_chan_cfg mop500_sdi2_dma_cfg_rx = { - .mode = STEDMA40_MODE_LOGICAL, - .dir = DMA_DEV_TO_MEM, - .dev_type = DB8500_DMA_DEV28_SD_MM2, -}; - -static struct stedma40_chan_cfg mop500_sdi2_dma_cfg_tx = { - .mode = STEDMA40_MODE_LOGICAL, - .dir = DMA_MEM_TO_DEV, - .dev_type = DB8500_DMA_DEV28_SD_MM2, -}; -#endif - -struct mmci_platform_data mop500_sdi2_data = { - .ocr_mask = MMC_VDD_165_195, - .f_max = 100000000, - .capabilities = MMC_CAP_4_BIT_DATA | - MMC_CAP_8_BIT_DATA | - MMC_CAP_NONREMOVABLE | - MMC_CAP_MMC_HIGHSPEED | - MMC_CAP_ERASE | - MMC_CAP_CMD23, - .gpio_cd = -1, - .gpio_wp = -1, -#ifdef CONFIG_STE_DMA40 - .dma_filter = stedma40_filter, - .dma_rx_param = &mop500_sdi2_dma_cfg_rx, - .dma_tx_param = &mop500_sdi2_dma_cfg_tx, -#endif -}; - -/* - * SDI 4 (on-board eMMC) - */ - -#ifdef CONFIG_STE_DMA40 -struct stedma40_chan_cfg mop500_sdi4_dma_cfg_rx = { - .mode = STEDMA40_MODE_LOGICAL, - .dir = DMA_DEV_TO_MEM, - .dev_type = DB8500_DMA_DEV42_SD_MM4, -}; - -static struct stedma40_chan_cfg mop500_sdi4_dma_cfg_tx = { - .mode = STEDMA40_MODE_LOGICAL, - .dir = DMA_MEM_TO_DEV, - .dev_type = DB8500_DMA_DEV42_SD_MM4, -}; -#endif - -struct mmci_platform_data mop500_sdi4_data = { - .f_max = 100000000, - .capabilities = MMC_CAP_4_BIT_DATA | - MMC_CAP_8_BIT_DATA | - MMC_CAP_NONREMOVABLE | - MMC_CAP_MMC_HIGHSPEED | - MMC_CAP_ERASE | - MMC_CAP_CMD23, - .gpio_cd = -1, - .gpio_wp = -1, -#ifdef CONFIG_STE_DMA40 - .dma_filter = stedma40_filter, - .dma_rx_param = &mop500_sdi4_dma_cfg_rx, - .dma_tx_param = &mop500_sdi4_dma_cfg_tx, -#endif -}; diff --git a/arch/arm/mach-ux500/board-mop500.h b/arch/arm/mach-ux500/board-mop500.h index 32cc0d8d8a0e..7c7b0adca582 100644 --- a/arch/arm/mach-ux500/board-mop500.h +++ b/arch/arm/mach-ux500/board-mop500.h @@ -8,12 +8,7 @@ #define __BOARD_MOP500_H #include <linux/platform_data/asoc-ux500-msp.h> -#include <linux/amba/mmci.h> -extern struct mmci_platform_data mop500_sdi0_data; -extern struct mmci_platform_data mop500_sdi1_data; -extern struct mmci_platform_data mop500_sdi2_data; -extern struct mmci_platform_data mop500_sdi4_data; extern struct msp_i2s_platform_data msp0_platform_data; extern struct msp_i2s_platform_data msp1_platform_data; extern struct msp_i2s_platform_data msp2_platform_data; diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c index 8820f602fcd2..fa308f07fae5 100644 --- a/arch/arm/mach-ux500/cpu-db8500.c +++ b/arch/arm/mach-ux500/cpu-db8500.c @@ -146,10 +146,6 @@ static struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = { /* Requires call-back bindings. */ OF_DEV_AUXDATA("arm,cortex-a9-pmu", 0, "arm-pmu", &db8500_pmu_platdata), /* Requires DMA bindings. */ - OF_DEV_AUXDATA("arm,pl18x", 0x80126000, "sdi0", &mop500_sdi0_data), - OF_DEV_AUXDATA("arm,pl18x", 0x80118000, "sdi1", &mop500_sdi1_data), - OF_DEV_AUXDATA("arm,pl18x", 0x80005000, "sdi2", &mop500_sdi2_data), - OF_DEV_AUXDATA("arm,pl18x", 0x80114000, "sdi4", &mop500_sdi4_data), OF_DEV_AUXDATA("stericsson,ux500-msp-i2s", 0x80123000, "ux500-msp-i2s.0", &msp0_platform_data), OF_DEV_AUXDATA("stericsson,ux500-msp-i2s", 0x80124000, diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 771c60ab4a32..a084edd37af5 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -13,6 +13,7 @@ #include <linux/init.h> #include <linux/ioport.h> #include <linux/device.h> +#include <linux/io.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -23,6 +24,7 @@ #include <linux/mmc/pm.h> #include <linux/mmc/host.h> #include <linux/mmc/card.h> +#include <linux/mmc/slot-gpio.h> #include <linux/amba/bus.h> #include <linux/clk.h> #include <linux/scatterlist.h> @@ -364,7 +366,6 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) #ifdef CONFIG_DMA_ENGINE static void mmci_dma_setup(struct mmci_host *host) { - struct mmci_platform_data *plat = host->plat; const char *rxname, *txname; dma_cap_mask_t mask; @@ -378,25 +379,6 @@ static void mmci_dma_setup(struct mmci_host *host) dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - if (plat && plat->dma_filter) { - if (!host->dma_rx_channel && plat->dma_rx_param) { - host->dma_rx_channel = dma_request_channel(mask, - plat->dma_filter, - plat->dma_rx_param); - /* E.g if no DMA hardware is present */ - if (!host->dma_rx_channel) - dev_err(mmc_dev(host->mmc), "no RX DMA channel\n"); - } - - if (!host->dma_tx_channel && plat->dma_tx_param) { - host->dma_tx_channel = dma_request_channel(mask, - plat->dma_filter, - plat->dma_tx_param); - if (!host->dma_tx_channel) - dev_warn(mmc_dev(host->mmc), "no TX DMA channel\n"); - } - } - /* * If only an RX channel is specified, the driver will * attempt to use it bidirectionally, however if it is @@ -444,11 +426,9 @@ static void mmci_dma_setup(struct mmci_host *host) */ static inline void mmci_dma_release(struct mmci_host *host) { - struct mmci_platform_data *plat = host->plat; - if (host->dma_rx_channel) dma_release_channel(host->dma_rx_channel); - if (host->dma_tx_channel && plat->dma_tx_param) + if (host->dma_tx_channel) dma_release_channel(host->dma_tx_channel); host->dma_rx_channel = host->dma_tx_channel = NULL; } @@ -1285,7 +1265,7 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) * indicating signal direction for the signals in * the SD/MMC bus and feedback-clock usage. */ - pwr |= host->plat->sigdir; + pwr |= host->pwr_reg_add; if (ios->bus_width == MMC_BUS_WIDTH_4) pwr &= ~MCI_ST_DATA74DIREN; @@ -1326,35 +1306,18 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) pm_runtime_put_autosuspend(mmc_dev(mmc)); } -static int mmci_get_ro(struct mmc_host *mmc) -{ - struct mmci_host *host = mmc_priv(mmc); - - if (host->gpio_wp == -ENOSYS) - return -ENOSYS; - - return gpio_get_value_cansleep(host->gpio_wp); -} - static int mmci_get_cd(struct mmc_host *mmc) { struct mmci_host *host = mmc_priv(mmc); struct mmci_platform_data *plat = host->plat; - unsigned int status; + unsigned int status = mmc_gpio_get_cd(mmc); - if (host->gpio_cd == -ENOSYS) { + if (status == -ENOSYS) { if (!plat->status) return 1; /* Assume always present */ status = plat->status(mmc_dev(host->mmc)); - } else - status = !!gpio_get_value_cansleep(host->gpio_cd) - ^ plat->cd_invert; - - /* - * Use positive logic throughout - status is zero for no card, - * non-zero for card inserted. - */ + } return status; } @@ -1391,70 +1354,44 @@ static int mmci_sig_volt_switch(struct mmc_host *mmc, struct mmc_ios *ios) return ret; } -static irqreturn_t mmci_cd_irq(int irq, void *dev_id) -{ - struct mmci_host *host = dev_id; - - mmc_detect_change(host->mmc, msecs_to_jiffies(500)); - - return IRQ_HANDLED; -} - static struct mmc_host_ops mmci_ops = { .request = mmci_request, .pre_req = mmci_pre_request, .post_req = mmci_post_request, .set_ios = mmci_set_ios, - .get_ro = mmci_get_ro, + .get_ro = mmc_gpio_get_ro, .get_cd = mmci_get_cd, .start_signal_voltage_switch = mmci_sig_volt_switch, }; -#ifdef CONFIG_OF -static void mmci_dt_populate_generic_pdata(struct device_node *np, - struct mmci_platform_data *pdata) +static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc) { - int bus_width = 0; - - pdata->gpio_wp = of_get_named_gpio(np, "wp-gpios", 0); - pdata->gpio_cd = of_get_named_gpio(np, "cd-gpios", 0); + struct mmci_host *host = mmc_priv(mmc); + int ret = mmc_of_parse(mmc); - if (of_get_property(np, "cd-inverted", NULL)) - pdata->cd_invert = true; - else - pdata->cd_invert = false; + if (ret) + return ret; - of_property_read_u32(np, "max-frequency", &pdata->f_max); - if (!pdata->f_max) - pr_warn("%s has no 'max-frequency' property\n", np->full_name); + if (of_get_property(np, "st,sig-dir-dat0", NULL)) + host->pwr_reg_add |= MCI_ST_DATA0DIREN; + if (of_get_property(np, "st,sig-dir-dat2", NULL)) + host->pwr_reg_add |= MCI_ST_DATA2DIREN; + if (of_get_property(np, "st,sig-dir-dat31", NULL)) + host->pwr_reg_add |= MCI_ST_DATA31DIREN; + if (of_get_property(np, "st,sig-dir-dat74", NULL)) + host->pwr_reg_add |= MCI_ST_DATA74DIREN; + if (of_get_property(np, "st,sig-dir-cmd", NULL)) + host->pwr_reg_add |= MCI_ST_CMDDIREN; + if (of_get_property(np, "st,sig-pin-fbclk", NULL)) + host->pwr_reg_add |= MCI_ST_FBCLKEN; if (of_get_property(np, "mmc-cap-mmc-highspeed", NULL)) - pdata->capabilities |= MMC_CAP_MMC_HIGHSPEED; + mmc->caps |= MMC_CAP_MMC_HIGHSPEED; if (of_get_property(np, "mmc-cap-sd-highspeed", NULL)) - pdata->capabilities |= MMC_CAP_SD_HIGHSPEED; + mmc->caps |= MMC_CAP_SD_HIGHSPEED; - of_property_read_u32(np, "bus-width", &bus_width); - switch (bus_width) { - case 0 : - /* No bus-width supplied. */ - break; - case 4 : - pdata->capabilities |= MMC_CAP_4_BIT_DATA; - break; - case 8 : - pdata->capabilities |= MMC_CAP_8_BIT_DATA; - break; - default : - pr_warn("%s: Unsupported bus width\n", np->full_name); - } -} -#else -static void mmci_dt_populate_generic_pdata(struct device_node *np, - struct mmci_platform_data *pdata) -{ - return; + return 0; } -#endif static int mmci_probe(struct amba_device *dev, const struct amba_id *id) @@ -1478,26 +1415,17 @@ static int mmci_probe(struct amba_device *dev, return -ENOMEM; } - if (np) - mmci_dt_populate_generic_pdata(np, plat); + mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev); + if (!mmc) + return -ENOMEM; - ret = amba_request_regions(dev, DRIVER_NAME); + ret = mmci_of_parse(np, mmc); if (ret) - goto out; - - mmc = mmc_alloc_host(sizeof(struct mmci_host), &dev->dev); - if (!mmc) { - ret = -ENOMEM; - goto rel_regions; - } + goto host_free; host = mmc_priv(mmc); host->mmc = mmc; - host->gpio_wp = -ENOSYS; - host->gpio_cd = -ENOSYS; - host->gpio_cd_irq = -1; - host->hw_designer = amba_manf(dev); host->hw_revision = amba_rev(dev); dev_dbg(mmc_dev(mmc), "designer ID = 0x%02x\n", host->hw_designer); @@ -1529,10 +1457,11 @@ static int mmci_probe(struct amba_device *dev, dev_dbg(mmc_dev(mmc), "eventual mclk rate: %u Hz\n", host->mclk); } + host->phybase = dev->res.start; - host->base = ioremap(dev->res.start, resource_size(&dev->res)); - if (!host->base) { - ret = -ENOMEM; + host->base = devm_ioremap_resource(&dev->dev, &dev->res); + if (IS_ERR(host->base)) { + ret = PTR_ERR(host->base); goto clk_disable; } @@ -1546,15 +1475,13 @@ static int mmci_probe(struct amba_device *dev, else mmc->f_min = DIV_ROUND_UP(host->mclk, 512); /* - * If the platform data supplies a maximum operating - * frequency, this takes precedence. Else, we fall back - * to using the module parameter, which has a (low) - * default value in case it is not specified. Either - * value must not exceed the clock rate into the block, - * of course. + * If no maximum operating frequency is supplied, fall back to use + * the module parameter, which has a (low) default value in case it + * is not specified. Either value must not exceed the clock rate into + * the block, of course. */ - if (plat->f_max) - mmc->f_max = min(host->mclk, plat->f_max); + if (mmc->f_max) + mmc->f_max = min(host->mclk, mmc->f_max); else mmc->f_max = min(host->mclk, fmax); dev_dbg(mmc_dev(mmc), "clocking block at %u Hz\n", mmc->f_max); @@ -1566,8 +1493,15 @@ static int mmci_probe(struct amba_device *dev, else if (plat->ocr_mask) dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n"); - mmc->caps = plat->capabilities; - mmc->caps2 = plat->capabilities2; + /* DT takes precedence over platform data. */ + if (!np) { + if (!plat->cd_invert) + mmc->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH; + mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; + } + + /* We support these capabilities. */ + mmc->caps |= MMC_CAP_CMD23; if (variant->busy_detect) { mmci_ops.card_busy = mmci_card_busy; @@ -1579,7 +1513,7 @@ static int mmci_probe(struct amba_device *dev, mmc->ops = &mmci_ops; /* We support these PM capabilities. */ - mmc->pm_caps = MMC_PM_KEEP_POWER; + mmc->pm_caps |= MMC_PM_KEEP_POWER; /* * We can do SGIO @@ -1616,62 +1550,30 @@ static int mmci_probe(struct amba_device *dev, writel(0, host->base + MMCIMASK1); writel(0xfff, host->base + MMCICLEAR); - if (plat->gpio_cd == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; - goto err_gpio_cd; - } - if (gpio_is_valid(plat->gpio_cd)) { - ret = gpio_request(plat->gpio_cd, DRIVER_NAME " (cd)"); - if (ret == 0) - ret = gpio_direction_input(plat->gpio_cd); - if (ret == 0) - host->gpio_cd = plat->gpio_cd; - else if (ret != -ENOSYS) - goto err_gpio_cd; - - /* - * A gpio pin that will detect cards when inserted and removed - * will most likely want to trigger on the edges if it is - * 0 when ejected and 1 when inserted (or mutatis mutandis - * for the inverted case) so we request triggers on both - * edges. - */ - ret = request_any_context_irq(gpio_to_irq(plat->gpio_cd), - mmci_cd_irq, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - DRIVER_NAME " (cd)", host); - if (ret >= 0) - host->gpio_cd_irq = gpio_to_irq(plat->gpio_cd); - } - if (plat->gpio_wp == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; - goto err_gpio_wp; + /* If DT, cd/wp gpios must be supplied through it. */ + if (!np && gpio_is_valid(plat->gpio_cd)) { + ret = mmc_gpio_request_cd(mmc, plat->gpio_cd, 0); + if (ret) + goto clk_disable; } - if (gpio_is_valid(plat->gpio_wp)) { - ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)"); - if (ret == 0) - ret = gpio_direction_input(plat->gpio_wp); - if (ret == 0) - host->gpio_wp = plat->gpio_wp; - else if (ret != -ENOSYS) - goto err_gpio_wp; + if (!np && gpio_is_valid(plat->gpio_wp)) { + ret = mmc_gpio_request_ro(mmc, plat->gpio_wp); + if (ret) + goto clk_disable; } - if ((host->plat->status || host->gpio_cd != -ENOSYS) - && host->gpio_cd_irq < 0) - mmc->caps |= MMC_CAP_NEEDS_POLL; - - ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host); + ret = devm_request_irq(&dev->dev, dev->irq[0], mmci_irq, IRQF_SHARED, + DRIVER_NAME " (cmd)", host); if (ret) - goto unmap; + goto clk_disable; if (!dev->irq[1]) host->singleirq = true; else { - ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, - DRIVER_NAME " (pio)", host); + ret = devm_request_irq(&dev->dev, dev->irq[1], mmci_pio_irq, + IRQF_SHARED, DRIVER_NAME " (pio)", host); if (ret) - goto irq0_free; + goto clk_disable; } writel(MCI_IRQENABLE, host->base + MMCIMASK0); @@ -1693,25 +1595,10 @@ static int mmci_probe(struct amba_device *dev, return 0; - irq0_free: - free_irq(dev->irq[0], host); - unmap: - if (host->gpio_wp != -ENOSYS) - gpio_free(host->gpio_wp); - err_gpio_wp: - if (host->gpio_cd_irq >= 0) - free_irq(host->gpio_cd_irq, host); - if (host->gpio_cd != -ENOSYS) - gpio_free(host->gpio_cd); - err_gpio_cd: - iounmap(host->base); clk_disable: clk_disable_unprepare(host->clk); host_free: mmc_free_host(mmc); - rel_regions: - amba_release_regions(dev); - out: return ret; } @@ -1737,92 +1624,46 @@ static int mmci_remove(struct amba_device *dev) writel(0, host->base + MMCIDATACTRL); mmci_dma_release(host); - free_irq(dev->irq[0], host); - if (!host->singleirq) - free_irq(dev->irq[1], host); - - if (host->gpio_wp != -ENOSYS) - gpio_free(host->gpio_wp); - if (host->gpio_cd_irq >= 0) - free_irq(host->gpio_cd_irq, host); - if (host->gpio_cd != -ENOSYS) - gpio_free(host->gpio_cd); - - iounmap(host->base); clk_disable_unprepare(host->clk); - mmc_free_host(mmc); - - amba_release_regions(dev); - } - - return 0; -} - -#ifdef CONFIG_SUSPEND -static int mmci_suspend(struct device *dev) -{ - struct amba_device *adev = to_amba_device(dev); - struct mmc_host *mmc = amba_get_drvdata(adev); - - if (mmc) { - struct mmci_host *host = mmc_priv(mmc); - pm_runtime_get_sync(dev); - writel(0, host->base + MMCIMASK0); } return 0; } -static int mmci_resume(struct device *dev) -{ - struct amba_device *adev = to_amba_device(dev); - struct mmc_host *mmc = amba_get_drvdata(adev); - - if (mmc) { - struct mmci_host *host = mmc_priv(mmc); - writel(MCI_IRQENABLE, host->base + MMCIMASK0); - pm_runtime_put(dev); - } - - return 0; -} -#endif - -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static void mmci_save(struct mmci_host *host) { unsigned long flags; - if (host->variant->pwrreg_nopower) { - spin_lock_irqsave(&host->lock, flags); + spin_lock_irqsave(&host->lock, flags); - writel(0, host->base + MMCIMASK0); + writel(0, host->base + MMCIMASK0); + if (host->variant->pwrreg_nopower) { writel(0, host->base + MMCIDATACTRL); writel(0, host->base + MMCIPOWER); writel(0, host->base + MMCICLOCK); - mmci_reg_delay(host); - - spin_unlock_irqrestore(&host->lock, flags); } + mmci_reg_delay(host); + spin_unlock_irqrestore(&host->lock, flags); } static void mmci_restore(struct mmci_host *host) { unsigned long flags; - if (host->variant->pwrreg_nopower) { - spin_lock_irqsave(&host->lock, flags); + spin_lock_irqsave(&host->lock, flags); + if (host->variant->pwrreg_nopower) { writel(host->clk_reg, host->base + MMCICLOCK); writel(host->datactrl_reg, host->base + MMCIDATACTRL); writel(host->pwr_reg, host->base + MMCIPOWER); - writel(MCI_IRQENABLE, host->base + MMCIMASK0); - mmci_reg_delay(host); - - spin_unlock_irqrestore(&host->lock, flags); } + writel(MCI_IRQENABLE, host->base + MMCIMASK0); + mmci_reg_delay(host); + + spin_unlock_irqrestore(&host->lock, flags); } static int mmci_runtime_suspend(struct device *dev) @@ -1857,8 +1698,9 @@ static int mmci_runtime_resume(struct device *dev) #endif static const struct dev_pm_ops mmci_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(mmci_suspend, mmci_resume) - SET_RUNTIME_PM_OPS(mmci_runtime_suspend, mmci_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_PM_RUNTIME_PM_OPS(mmci_runtime_suspend, mmci_runtime_resume, NULL) }; static struct amba_id mmci_ids[] = { diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h index 58b1b8896bf2..347d942d740b 100644 --- a/drivers/mmc/host/mmci.h +++ b/drivers/mmc/host/mmci.h @@ -13,6 +13,16 @@ #define MCI_PWR_ON 0x03 #define MCI_OD (1 << 6) #define MCI_ROD (1 << 7) +/* + * The ST Micro version does not have ROD and reuse the voltage registers for + * direction settings. + */ +#define MCI_ST_DATA2DIREN (1 << 2) +#define MCI_ST_CMDDIREN (1 << 3) +#define MCI_ST_DATA0DIREN (1 << 4) +#define MCI_ST_DATA31DIREN (1 << 5) +#define MCI_ST_FBCLKEN (1 << 7) +#define MCI_ST_DATA74DIREN (1 << 8) #define MMCICLOCK 0x004 #define MCI_CLK_ENABLE (1 << 8) @@ -176,9 +186,6 @@ struct mmci_host { struct mmc_data *data; struct mmc_host *mmc; struct clk *clk; - int gpio_cd; - int gpio_wp; - int gpio_cd_irq; bool singleirq; spinlock_t lock; @@ -186,6 +193,7 @@ struct mmci_host { unsigned int mclk; unsigned int cclk; u32 pwr_reg; + u32 pwr_reg_add; u32 clk_reg; u32 datactrl_reg; u32 busy_status; diff --git a/include/linux/amba/mmci.h b/include/linux/amba/mmci.h index 32a89cf5ec45..8c98113069ce 100644 --- a/include/linux/amba/mmci.h +++ b/include/linux/amba/mmci.h @@ -6,28 +6,9 @@ #include <linux/mmc/host.h> - -/* - * These defines is places here due to access is needed from machine - * configuration files. The ST Micro version does not have ROD and - * reuse the voltage registers for direction settings. - */ -#define MCI_ST_DATA2DIREN (1 << 2) -#define MCI_ST_CMDDIREN (1 << 3) -#define MCI_ST_DATA0DIREN (1 << 4) -#define MCI_ST_DATA31DIREN (1 << 5) -#define MCI_ST_FBCLKEN (1 << 7) -#define MCI_ST_DATA74DIREN (1 << 8) - -/* Just some dummy forwarding */ -struct dma_chan; - /** * struct mmci_platform_data - platform configuration for the MMCI * (also known as PL180) block. - * @f_max: the maximum operational frequency for this host in this - * platform configuration. When this is specified it takes precedence - * over the module parameter for the same frequency. * @ocr_mask: available voltages on the 4 pins from the block, this * is ignored if a regulator is used, see the MMC_VDD_* masks in * mmc/host.h @@ -42,37 +23,14 @@ struct dma_chan; * @gpio_wp: read this GPIO pin to see if the card is write protected * @gpio_cd: read this GPIO pin to detect card insertion * @cd_invert: true if the gpio_cd pin value is active low - * @capabilities: the capabilities of the block as implemented in - * this platform, signify anything MMC_CAP_* from mmc/host.h - * @capabilities2: more capabilities, MMC_CAP2_* from mmc/host.h - * @sigdir: a bit field indicating for what bits in the MMC bus the host - * should enable signal direction indication. - * @dma_filter: function used to select an appropriate RX and TX - * DMA channel to be used for DMA, if and only if you're deploying the - * generic DMA engine - * @dma_rx_param: parameter passed to the DMA allocation - * filter in order to select an appropriate RX channel. If - * there is a bidirectional RX+TX channel, then just specify - * this and leave dma_tx_param set to NULL - * @dma_tx_param: parameter passed to the DMA allocation - * filter in order to select an appropriate TX channel. If this - * is NULL the driver will attempt to use the RX channel as a - * bidirectional channel */ struct mmci_platform_data { - unsigned int f_max; unsigned int ocr_mask; int (*ios_handler)(struct device *, struct mmc_ios *); unsigned int (*status)(struct device *); int gpio_wp; int gpio_cd; bool cd_invert; - unsigned long capabilities; - unsigned long capabilities2; - u32 sigdir; - bool (*dma_filter)(struct dma_chan *chan, void *filter_param); - void *dma_rx_param; - void *dma_tx_param; }; #endif |