aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-exynos/board-smdk5250-mmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-exynos/board-smdk5250-mmc.c')
-rw-r--r--arch/arm/mach-exynos/board-smdk5250-mmc.c271
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));
+}