diff options
Diffstat (limited to 'arch/arm/mach-exynos/board-smdk5250-mmc.c')
-rw-r--r-- | arch/arm/mach-exynos/board-smdk5250-mmc.c | 271 |
1 files changed, 271 insertions, 0 deletions
diff --git a/arch/arm/mach-exynos/board-smdk5250-mmc.c b/arch/arm/mach-exynos/board-smdk5250-mmc.c new file mode 100644 index 0000000..f04a80a --- /dev/null +++ b/arch/arm/mach-exynos/board-smdk5250-mmc.c @@ -0,0 +1,271 @@ +/* linux/arch/arm/mach-exynos/board-smdk5250-mmc.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/gpio.h> +#include <linux/smsc911x.h> +#include <linux/mmc/host.h> +#include <linux/delay.h> + +#include <plat/gpio-cfg.h> +#include <plat/cpu.h> +#include <plat/clock.h> +#include <plat/devs.h> +#include <plat/sdhci.h> + +#include <mach/dwmci.h> + +#include "board-smdk5250.h" + +#ifdef CONFIG_EXYNOS4_DEV_DWMCI +static void exynos_dwmci_cfg_gpio(int width) +{ + unsigned int gpio; + + for (gpio = EXYNOS5_GPC0(0); gpio < EXYNOS5_GPC0(2); gpio++) { + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); + s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV2); + } + + switch (width) { + case MMC_BUS_WIDTH_8: + for (gpio = EXYNOS5_GPC1(3); gpio <= EXYNOS5_GPC1(6); gpio++) { + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP); + s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV2); + } + case MMC_BUS_WIDTH_4: + for (gpio = EXYNOS5_GPC0(3); gpio <= EXYNOS5_GPC0(6); gpio++) { + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP); + s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV2); + } + break; + case MMC_BUS_WIDTH_1: + gpio = EXYNOS5_GPC0(3); + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(3)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP); + s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV2); + default: + break; + } +} + +static struct dw_mci_board exynos_dwmci_pdata __initdata = { + .num_slots = 1, + .quirks = DW_MCI_QUIRK_BROKEN_CARD_DETECTION | + DW_MCI_QUIRK_HIGHSPEED, + .bus_hz = 66 * 1000 * 1000, + .caps = MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR | + MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23, + .fifo_depth = 0x80, + .detect_delay_ms = 200, + .hclk_name = "dwmci", + .cclk_name = "sclk_dwmci", + .cfg_gpio = exynos_dwmci_cfg_gpio, +}; +#endif + +static void exynos_dwmci0_cfg_gpio(int width) +{ + unsigned int gpio; + + for (gpio = EXYNOS5_GPC0(0); gpio < EXYNOS5_GPC0(2); gpio++) { + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); + s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); + } + + switch (width) { + case MMC_BUS_WIDTH_8: + for (gpio = EXYNOS5_GPC1(0); gpio <= EXYNOS5_GPC1(3); gpio++) { + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP); + s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); + } + case MMC_BUS_WIDTH_4: + for (gpio = EXYNOS5_GPC0(3); gpio <= EXYNOS5_GPC0(6); gpio++) { + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP); + s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); + } + break; + case MMC_BUS_WIDTH_1: + gpio = EXYNOS5_GPC0(3); + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP); + s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV4); + default: + break; + } +} + +static struct dw_mci_board smdk5250_dwmci0_pdata __initdata = { + .num_slots = 1, + .quirks = DW_MCI_QUIRK_BROKEN_CARD_DETECTION | + DW_MCI_QUIRK_HIGHSPEED, + .bus_hz = 100 * 1000 * 1000, + .caps = MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR | + MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23, + .fifo_depth = 0x80, + .detect_delay_ms = 200, + .hclk_name = "dwmci", + .cclk_name = "sclk_dwmci", + .cfg_gpio = exynos_dwmci0_cfg_gpio, +}; + +static int smdk5250_dwmci_get_ro(u32 slot_id) +{ + /* smdk5250 rev1.0 did not support SD/MMC card write pritect. */ + return 0; +} + +static void exynos_dwmci2_cfg_gpio(int width) +{ + unsigned int gpio; + + for (gpio = EXYNOS5_GPC3(0); gpio < EXYNOS5_GPC3(2); gpio++) { + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); + s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV2); + } + + switch (width) { + case MMC_BUS_WIDTH_4: + for (gpio = EXYNOS5_GPC3(3); gpio <= EXYNOS5_GPC3(6); gpio++) { + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP); + s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV2); + } + break; + case MMC_BUS_WIDTH_1: + gpio = EXYNOS5_GPC3(3); + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP); + s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV2); + default: + break; + } + + gpio = EXYNOS5_GPC3(2); + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_UP); + s5p_gpio_set_drvstr(gpio, S5P_GPIO_DRVSTR_LV2); +} + +static struct dw_mci_board smdk5250_dwmci2_pdata __initdata = { + .num_slots = 1, + .quirks = DW_MCI_QUIRK_HIGHSPEED, + .bus_hz = 100 * 1000 * 1000, + .caps = MMC_CAP_CMD23, + .fifo_depth = 0x80, + .detect_delay_ms = 200, + .hclk_name = "dwmci", + .cclk_name = "sclk_dwmci", + .cfg_gpio = exynos_dwmci2_cfg_gpio, + .get_ro = smdk5250_dwmci_get_ro, +}; + +#ifdef CONFIG_S3C_DEV_HSMMC +static struct s3c_sdhci_platdata smdk5250_hsmmc0_pdata __initdata = { + .cd_type = S3C_SDHCI_CD_INTERNAL, + .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, +#ifdef CONFIG_EXYNOS4_SDHCI_CH0_8BIT + .max_width = 8, + .host_caps = MMC_CAP_8_BIT_DATA, +#endif +}; +#endif + +#ifdef CONFIG_S3C_DEV_HSMMC1 +static struct s3c_sdhci_platdata smdk5250_hsmmc1_pdata __initdata = { + .cd_type = S3C_SDHCI_CD_INTERNAL, + .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, +}; +#endif + +#ifdef CONFIG_S3C_DEV_HSMMC2 +static struct s3c_sdhci_platdata smdk5250_hsmmc2_pdata __initdata = { + .cd_type = S3C_SDHCI_CD_INTERNAL, + .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, +#ifdef CONFIG_EXYNOS4_SDHCI_CH2_8BIT + .max_width = 8, + .host_caps = MMC_CAP_8_BIT_DATA, +#endif +}; +#endif + +#ifdef CONFIG_S3C_DEV_HSMMC3 +static struct s3c_sdhci_platdata smdk5250_hsmmc3_pdata __initdata = { + .cd_type = S3C_SDHCI_CD_INTERNAL, + .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, +}; +#endif + +static struct platform_device *smdk5250_mmc_devices[] __initdata = { +#ifdef CONFIG_S3C_DEV_HSMMC + &s3c_device_hsmmc0, +#endif +#ifdef CONFIG_S3C_DEV_HSMMC1 + &s3c_device_hsmmc1, +#endif +#ifdef CONFIG_S3C_DEV_HSMMC2 + &s3c_device_hsmmc2, +#endif +#ifdef CONFIG_S3C_DEV_HSMMC3 + &s3c_device_hsmmc3, +#endif +#ifdef CONFIG_EXYNOS4_DEV_DWMCI + &exynos_device_dwmci, + &exynos_device_dwmci0, + &exynos_device_dwmci2, +#endif +}; + +void __init exynos5_smdk5250_mmc_init(void) +{ +#ifdef CONFIG_EXYNOS4_DEV_DWMCI + if (samsung_rev() >= EXYNOS5250_REV_1_0) { + exynos_dwmci_set_platdata(&smdk5250_dwmci0_pdata, 0); + dev_set_name(&exynos_device_dwmci0.dev, "s3c-sdhci.0"); + clk_add_alias("dwmci", "dw_mmc.0", "hsmmc", + &exynos_device_dwmci0.dev); + clk_add_alias("sclk_dwmci", "dw_mmc.0", "sclk_mmc", + &exynos_device_dwmci0.dev); + + exynos_dwmci_set_platdata(&smdk5250_dwmci2_pdata, 2); + dev_set_name(&exynos_device_dwmci2.dev, "s3c-sdhci.2"); + clk_add_alias("dwmci", "dw_mmc.2", "hsmmc", + &exynos_device_dwmci2.dev); + clk_add_alias("sclk_dwmci", "dw_mmc.2", "sclk_mmc", + &exynos_device_dwmci2.dev); + } else +#endif + { +#ifdef CONFIG_EXYNOS4_DEV_DWMCI + exynos_dwmci_set_platdata(&exynos_dwmci_pdata, 0); +#endif +#ifdef CONFIG_S3C_DEV_HSMMC + s3c_sdhci0_set_platdata(&smdk5250_hsmmc0_pdata); +#endif +#ifdef CONFIG_S3C_DEV_HSMMC1 + s3c_sdhci1_set_platdata(&smdk5250_hsmmc1_pdata); +#endif +#ifdef CONFIG_S3C_DEV_HSMMC2 + s3c_sdhci2_set_platdata(&smdk5250_hsmmc2_pdata); +#endif +#ifdef CONFIG_S3C_DEV_HSMMC3 + s3c_sdhci3_set_platdata(&smdk5250_hsmmc3_pdata); +#endif + } + + platform_add_devices(smdk5250_mmc_devices, + ARRAY_SIZE(smdk5250_mmc_devices)); +} |