diff options
author | Philippe Langlais <philippe.langlais@stericsson.com> | 2012-04-06 11:11:17 +0200 |
---|---|---|
committer | Philippe Langlais <philippe.langlais@stericsson.com> | 2012-04-06 11:11:17 +0200 |
commit | 5d7e606a3696b992df40afaf9b04872320346c41 (patch) | |
tree | 92b060685f1187ae895eb8dc7256445ed455bfa5 /arch/arm/mach-ux500/board-u5500-sdi.c | |
parent | 546c9b21117077f145d59a0168fcb6fd0a3c3b24 (diff) | |
parent | 285f0b3fe3a59c56db9ae68e6a1ae0e2a67b72f9 (diff) |
Merge topic branch 'storage-mmc' into integration-linux-ux500-3.3
Diffstat (limited to 'arch/arm/mach-ux500/board-u5500-sdi.c')
-rw-r--r-- | arch/arm/mach-ux500/board-u5500-sdi.c | 232 |
1 files changed, 207 insertions, 25 deletions
diff --git a/arch/arm/mach-ux500/board-u5500-sdi.c b/arch/arm/mach-ux500/board-u5500-sdi.c index 63c3f8058ff..101a69f2fbc 100644 --- a/arch/arm/mach-ux500/board-u5500-sdi.c +++ b/arch/arm/mach-ux500/board-u5500-sdi.c @@ -5,34 +5,28 @@ * 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/delay.h> -#include <plat/pincfg.h> -#include <plat/gpio-nomadik.h> -#include <mach/db5500-regs.h> +#include <asm/mach-types.h> #include <plat/ste_dma40.h> +#include <mach/devices.h> +#include <mach/hardware.h> +#include <mach/ste-dma40-db5500.h> -#include "pins-db5500.h" #include "devices-db5500.h" -#include "ste-dma40-db5500.h" - -static pin_cfg_t u5500_sdi_pins[] = { - /* SDI0 (POP eMMC) */ - GPIO5_MC0_DAT0 | PIN_DIR_INPUT | PIN_PULL_UP, - GPIO6_MC0_DAT1 | PIN_DIR_INPUT | PIN_PULL_UP, - GPIO7_MC0_DAT2 | PIN_DIR_INPUT | PIN_PULL_UP, - GPIO8_MC0_DAT3 | PIN_DIR_INPUT | PIN_PULL_UP, - GPIO9_MC0_DAT4 | PIN_DIR_INPUT | PIN_PULL_UP, - GPIO10_MC0_DAT5 | PIN_DIR_INPUT | PIN_PULL_UP, - GPIO11_MC0_DAT6 | PIN_DIR_INPUT | PIN_PULL_UP, - GPIO12_MC0_DAT7 | PIN_DIR_INPUT | PIN_PULL_UP, - GPIO13_MC0_CMD | PIN_DIR_INPUT | PIN_PULL_UP, - GPIO14_MC0_CLK | PIN_DIR_OUTPUT | PIN_VAL_LOW, -}; +#include "board-u5500.h" +/* + * SDI 0 (eMMC) + */ #ifdef CONFIG_STE_DMA40 -struct stedma40_chan_cfg u5500_sdi0_dma_cfg_rx = { +static struct stedma40_chan_cfg sdi0_dma_cfg_rx = { .mode = STEDMA40_MODE_LOGICAL, .dir = STEDMA40_PERIPH_TO_MEM, .src_dev_type = DB5500_DMA_DEV24_SDMMC0_RX, @@ -41,7 +35,7 @@ struct stedma40_chan_cfg u5500_sdi0_dma_cfg_rx = { .dst_info.data_width = STEDMA40_WORD_WIDTH, }; -static struct stedma40_chan_cfg u5500_sdi0_dma_cfg_tx = { +static struct stedma40_chan_cfg sdi0_dma_cfg_tx = { .mode = STEDMA40_MODE_LOGICAL, .dir = STEDMA40_MEM_TO_PERIPH, .src_dev_type = STEDMA40_DEV_SRC_MEMORY, @@ -57,18 +51,206 @@ static struct mmci_platform_data u5500_sdi0_data = { .capabilities = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA | MMC_CAP_MMC_HIGHSPEED, + .capabilities2 = MMC_CAP2_NO_SLEEP_CMD, .gpio_cd = -1, .gpio_wp = -1, #ifdef CONFIG_STE_DMA40 .dma_filter = stedma40_filter, - .dma_rx_param = &u5500_sdi0_dma_cfg_rx, - .dma_tx_param = &u5500_sdi0_dma_cfg_tx, + .dma_rx_param = &sdi0_dma_cfg_rx, + .dma_tx_param = &sdi0_dma_cfg_tx, +#endif +}; + +/* + * SDI 1 (MicroSD slot) + */ + +static int u5500_sdi1_ios_handler(struct device *dev, struct mmc_ios *ios) +{ + static int power_mode = -1; + + if (power_mode == ios->power_mode) + return 0; + + switch (ios->power_mode) { + case MMC_POWER_UP: + break; + case MMC_POWER_ON: + /* + * Level shifter voltage should depend on vdd to when deciding + * on either 1.8V or 2.9V. Once the decision has been made the + * level shifter must be disabled and re-enabled with a changed + * select signal in order to switch the voltage. Since there is + * no framework support yet for indicating 1.8V in vdd, use the + * default 2.9V. + */ + gpio_set_value_cansleep(GPIO_MMC_CARD_CTRL, 1); + udelay(100); + break; + case MMC_POWER_OFF: + gpio_set_value_cansleep(GPIO_MMC_CARD_CTRL, 0); + break; + } + + power_mode = ios->power_mode; + return 0; +} + +#ifdef CONFIG_STE_DMA40 +static struct stedma40_chan_cfg sdi1_dma_cfg_rx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB5500_DMA_DEV34_SDMMC1_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct stedma40_chan_cfg sdi1_dma_cfg_tx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB5500_DMA_DEV34_SDMMC1_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; +#endif + +static struct mmci_platform_data u5500_sdi1_data = { + .ios_handler = u5500_sdi1_ios_handler, + .ocr_mask = MMC_VDD_29_30, + .f_max = 50000000, + .capabilities = MMC_CAP_4_BIT_DATA | + MMC_CAP_SD_HIGHSPEED | + MMC_CAP_MMC_HIGHSPEED, + .gpio_cd = GPIO_SDMMC_CD, + .gpio_wp = -1, + .cd_invert = true, +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &sdi1_dma_cfg_rx, + .dma_tx_param = &sdi1_dma_cfg_tx, #endif }; +/* + * SDI2 (EMMC2) + */ + +static struct stedma40_chan_cfg sdi2_dma_cfg_rx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB5500_DMA_DEV26_SDMMC2_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct stedma40_chan_cfg sdi2_dma_cfg_tx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB5500_DMA_DEV26_SDMMC2_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct mmci_platform_data u5500_sdi2_data = { + .ocr_mask = MMC_VDD_165_195, + .f_max = 50000000, + .capabilities = MMC_CAP_4_BIT_DATA | + MMC_CAP_8_BIT_DATA | + MMC_CAP_MMC_HIGHSPEED, + .capabilities2 = MMC_CAP2_NO_SLEEP_CMD, + .gpio_cd = -1, + .gpio_wp = -1, +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &sdi2_dma_cfg_rx, + .dma_tx_param = &sdi2_dma_cfg_tx, +#endif +}; + +/* + * SDI 3 (SDIO WLAN) + */ +#ifdef SDIO_DMA_ON +#ifdef CONFIG_STE_DMA40 +static struct stedma40_chan_cfg sdi3_dma_cfg_rx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_PERIPH_TO_MEM, + .src_dev_type = DB5500_DMA_DEV27_SDMMC3_RX, + .dst_dev_type = STEDMA40_DEV_DST_MEMORY, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; + +static struct stedma40_chan_cfg sdi3_dma_cfg_tx = { + .mode = STEDMA40_MODE_LOGICAL, + .dir = STEDMA40_MEM_TO_PERIPH, + .src_dev_type = STEDMA40_DEV_SRC_MEMORY, + .dst_dev_type = DB5500_DMA_DEV27_SDMMC3_TX, + .src_info.data_width = STEDMA40_WORD_WIDTH, + .dst_info.data_width = STEDMA40_WORD_WIDTH, +}; +#endif +#endif + +static struct mmci_platform_data u5500_sdi3_data = { + .ocr_mask = MMC_VDD_29_30, + .f_max = 50000000, + .capabilities = MMC_CAP_4_BIT_DATA, + .gpio_cd = -1, + .gpio_wp = -1, +#ifdef SDIO_DMA_ON +#ifdef CONFIG_STE_DMA40 + .dma_filter = stedma40_filter, + .dma_rx_param = &sdi3_dma_cfg_rx, + .dma_tx_param = &sdi3_dma_cfg_tx, +#endif +#endif +}; + +static void sdi1_configure(void) +{ + int pin[2]; + int ret; + + /* Level-shifter GPIOs */ + pin[0] = GPIO_MMC_CARD_CTRL; + pin[1] = GPIO_MMC_CARD_VSEL; + + ret = gpio_request(pin[0], "MMC_CARD_CTRL"); + if (!ret) + ret = gpio_request(pin[1], "MMC_CARD_VSEL"); + + if (ret) { + pr_warning("unable to config sdi0 gpios for level shifter.\n"); + return; + } + /* Select the default 2.9V and eanble level shifter */ + gpio_direction_output(pin[0], 1); + gpio_direction_output(pin[1], 0); +} + void __init u5500_sdi_init(void) { - nmk_config_pins(u5500_sdi_pins, ARRAY_SIZE(u5500_sdi_pins)); + u32 periphid = 0x10480180; + + /* + * Fix me in 5500 v2.1 + * Dynamic detection of booting device by reading + * ROM debug register from BACKUP RAM and register the + * corresponding EMMC. + * This is done due to wrong configuration of MMC0 clock + * in ROM code for u5500 v2. + */ + if (u5500_get_boot_mmc() == 2) + db5500_add_sdi2(&u5500_sdi2_data, periphid); + else + db5500_add_sdi0(&u5500_sdi0_data, periphid); - db5500_add_sdi0(&u5500_sdi0_data); + sdi1_configure(); + db5500_add_sdi1(&u5500_sdi1_data, periphid); + db5500_add_sdi3(&u5500_sdi3_data, periphid); } |