summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Ziswiler <marcel.ziswiler@toradex.com>2014-12-18 05:48:47 +0100
committerMarcel Ziswiler <marcel.ziswiler@toradex.com>2014-12-18 17:20:25 +0100
commitddcb06fdc59b17a900a7ef61e93fd2ca1f0ced51 (patch)
tree8541f2f760fdf5d72f47816e9aa86d8345fef33c
parent629b91fa046df5213ed3312d2e2b8683e6bdd70c (diff)
This patch adds optional UHS support for the 8-bit MMC controller. Please note that this requires V1.1A or later module hardware plus the pull-up resistors on the data as well as the command signal lines of your carrier board need to be removed (e.g. R46 to R54 on our Apalis Evaluation Board V1.1A). If those pre-requisites are met support can be enabled using the following kernel command line parameter: mmc_uhs=1
-rw-r--r--arch/arm/configs/apalis_t30_defconfig1
-rw-r--r--arch/arm/mach-tegra/board-apalis_t30-pinmux.c28
-rw-r--r--arch/arm/mach-tegra/board-apalis_t30-power.c108
-rw-r--r--arch/arm/mach-tegra/board-apalis_t30.c14
4 files changed, 127 insertions, 24 deletions
diff --git a/arch/arm/configs/apalis_t30_defconfig b/arch/arm/configs/apalis_t30_defconfig
index 3e22166..6f9194d 100644
--- a/arch/arm/configs/apalis_t30_defconfig
+++ b/arch/arm/configs/apalis_t30_defconfig
@@ -245,6 +245,7 @@ CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
CONFIG_REGULATOR_USERSPACE_CONSUMER=y
+CONFIG_REGULATOR_GPIO=y
CONFIG_REGULATOR_TPS65910=y
CONFIG_REGULATOR_TPS62360=y
CONFIG_REGULATOR_TPS6591X=y
diff --git a/arch/arm/mach-tegra/board-apalis_t30-pinmux.c b/arch/arm/mach-tegra/board-apalis_t30-pinmux.c
index a04a155..0f0b5b0 100644
--- a/arch/arm/mach-tegra/board-apalis_t30-pinmux.c
+++ b/arch/arm/mach-tegra/board-apalis_t30-pinmux.c
@@ -144,7 +144,7 @@ static __initdata struct tegra_pingroup_config apalis_t30_pinmux[] = {
DEFAULT_PINMUX(CLK3_OUT, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
DEFAULT_PINMUX(CLK3_REQ, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
- DEFAULT_PINMUX(CLK_32K_OUT, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(CLK_32K_OUT, RSVD1, PULL_DOWN, TRISTATE, OUTPUT),/* NC */
DEFAULT_PINMUX(CRT_HSYNC, CRT, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(CRT_VSYNC, CRT, NORMAL, NORMAL, OUTPUT),
@@ -323,7 +323,7 @@ static __initdata struct tegra_pingroup_config apalis_t30_pinmux[] = {
DEFAULT_PINMUX(LCD_PCLK, DISPLAYA, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(LCD_PWR0, DISPLAYB, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ DEFAULT_PINMUX(LCD_PWR0, DISPLAYB, PULL_DOWN, TRISTATE, OUTPUT),/* NC */
DEFAULT_PINMUX(LCD_PWR1, RSVD1, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
DEFAULT_PINMUX(LCD_PWR2, RSVD, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
@@ -351,7 +351,7 @@ static __initdata struct tegra_pingroup_config apalis_t30_pinmux[] = {
DEFAULT_PINMUX(PEX_L2_RST_N, PCIE, NORMAL, NORMAL, OUTPUT),
DEFAULT_PINMUX(PEX_WAKE_N, PCIE, NORMAL, NORMAL, INPUT),
-/* Power I2C pinmux */
+ /* Power I2C pinmux */
I2C_PINMUX(PWR_I2C_SCL, I2CPWR, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE),
I2C_PINMUX(PWR_I2C_SDA, I2CPWR, NORMAL, NORMAL, INPUT, DEFAULT, ENABLE),
@@ -363,15 +363,15 @@ static __initdata struct tegra_pingroup_config apalis_t30_pinmux[] = {
DEFAULT_PINMUX(SDMMC1_DAT3, SDMMC1, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(SDMMC3_CLK, SDMMC3, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC3_CMD, SDMMC3, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC3_DAT0, SDMMC3, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC3_DAT1, SDMMC3, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC3_DAT2, SDMMC3, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC3_DAT3, SDMMC3, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC3_DAT4, SDMMC3, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC3_DAT5, SDMMC3, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC3_DAT6, SDMMC3, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(SDMMC3_DAT7, SDMMC3, NORMAL, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_CMD, SDMMC3, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT0, SDMMC3, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT1, SDMMC3, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT2, SDMMC3, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT3, SDMMC3, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT4, SDMMC3, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT5, SDMMC3, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT6, SDMMC3, PULL_UP, NORMAL, INPUT),
+ DEFAULT_PINMUX(SDMMC3_DAT7, SDMMC3, PULL_UP, NORMAL, INPUT),
DEFAULT_PINMUX(SDMMC4_CLK, SDMMC4, NORMAL, NORMAL, INPUT),
DEFAULT_PINMUX(SDMMC4_CMD, SDMMC4, PULL_UP, NORMAL, INPUT),
@@ -402,7 +402,9 @@ static __initdata struct tegra_pingroup_config apalis_t30_pinmux[] = {
DEFAULT_PINMUX(SYS_CLK_REQ, SYSCLK, NORMAL, NORMAL, INPUT),
- DEFAULT_PINMUX(UART2_CTS_N, GMI, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
+ /* EN_+3.3_SDMMC3 */
+ DEFAULT_PINMUX(UART2_CTS_N, GMI, NORMAL, NORMAL, OUTPUT),
+
DEFAULT_PINMUX(UART2_RTS_N, GMI, PULL_DOWN, TRISTATE, OUTPUT), /* NC */
DEFAULT_PINMUX(UART2_RXD, IRDA, NORMAL, NORMAL, INPUT),
diff --git a/arch/arm/mach-tegra/board-apalis_t30-power.c b/arch/arm/mach-tegra/board-apalis_t30-power.c
index 064c438..eda6d98 100644
--- a/arch/arm/mach-tegra/board-apalis_t30-power.c
+++ b/arch/arm/mach-tegra/board-apalis_t30-power.c
@@ -25,7 +25,9 @@
#include <linux/io.h>
#include <linux/mfd/tps6591x.h>
#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
#include <linux/regulator/fixed.h>
+#include <linux/regulator/gpio-regulator.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/tps62360.h>
#include <linux/regulator/tps6591x-regulator.h>
@@ -91,9 +93,9 @@ static struct regulator_consumer_supply tps6591x_vio_supply_0[] = {
REGULATOR_SUPPLY("avdd_ic_usb", NULL),
};
-/* unused */
+/* 1.8 volt VDDIO_SDMMC3 in case EN_+3.3_SDMMC3 is off */
static struct regulator_consumer_supply tps6591x_ldo1_supply_0[] = {
- REGULATOR_SUPPLY("unused_rail_ldo1", NULL),
+ REGULATOR_SUPPLY("vddio_sdmmc_1v8", NULL),
};
/* EN_+V3.3 switching via FET: +V3.3_AUDIO_AVDD_S, +V3.3 and +V1.8_VDD_LAN
@@ -178,7 +180,7 @@ TPS_PDATA_INIT(vdd2, 0, 1050, 1050, 0, 1, 1, 1, -1, 0, 0, EXT_CTRL_SLEEP
TPS_PDATA_INIT(vddctrl, 0, 800, 1300, 0, 1, 1, 0, -1, 0, 0, EXT_CTRL_EN1, 0);
TPS_PDATA_INIT(vio, 0, 1800, 1800, 0, 1, 1, 0, -1, 0, 0, 0, 0);
-TPS_PDATA_INIT(ldo1, 0, 1000, 3300, tps6591x_rails(VIO), 0, 0, 0, -1, 0, 1, 0, 0);
+TPS_PDATA_INIT(ldo1, 0, 1800, 1800, tps6591x_rails(VIO), 1, 1, 1, -1, 0, 1, 0, 0);
/* Make sure EN_+V3.3 is always on! */
TPS_PDATA_INIT(ldo2, 0, 1200, 1200, tps6591x_rails(VIO), 1, 1, 1, -1, 0, 1, 0, 0);
@@ -373,7 +375,7 @@ VDDIO_GMI_3
VDDIO_UART
VDDIO_SDMMC1
AVDD_USB
-VDDIO_SDMMC3
+VDDIO_SDMMC3 in case EN_+3.3_SDMMC3 is on
74AVCAH164245
VDDIO_PEX_CTL
TPS65911 VDDIO
@@ -386,6 +388,7 @@ static struct regulator_consumer_supply fixed_reg_v3_3_supply[] = {
REGULATOR_SUPPLY("avdd_audio", NULL),
REGULATOR_SUPPLY("avdd_usb", NULL),
REGULATOR_SUPPLY("vddio_sd_slot", "sdhci-tegra.1"),
+ REGULATOR_SUPPLY("vddio_sd_slot", "sdhci-tegra.2"),
REGULATOR_SUPPLY("vddio_sys", NULL),
REGULATOR_SUPPLY("vddio_uart", NULL),
REGULATOR_SUPPLY("pwrdet_uart", NULL),
@@ -397,12 +400,13 @@ static struct regulator_consumer_supply fixed_reg_v3_3_supply[] = {
REGULATOR_SUPPLY("pwrdet_lcd", NULL),
REGULATOR_SUPPLY("vddio_cam", NULL),
REGULATOR_SUPPLY("pwrdet_cam", NULL),
- /* if this supply is defined, the sdhci driver tries
- * to set it to 1.8V */
-// REGULATOR_SUPPLY("vddio_sdmmc", "sdhci-tegra.1"),
+ REGULATOR_SUPPLY("vddio_sdmmc", "sdhci-tegra.1"),
+ REGULATOR_SUPPLY("vddio_sdmmc_3v3", NULL),
REGULATOR_SUPPLY("pwrdet_sdmmc2", NULL),
REGULATOR_SUPPLY("pwrdet_sdmmc1", NULL),
- REGULATOR_SUPPLY("pwrdet_sdmmc3", NULL),
+ /* if this supply is defined, somehow magically LDO1 gets
+ * set to 3.3V resulting in some squeezed out 3.0V */
+// REGULATOR_SUPPLY("pwrdet_sdmmc3", NULL),
REGULATOR_SUPPLY("pwrdet_pex_ctl", NULL),
REGULATOR_SUPPLY("pwrdet_nand", NULL),
@@ -422,6 +426,81 @@ static struct platform_device *fixed_reg_devs_apalis_t30[] = {
ADD_FIXED_REG(v3_3),
};
+/* 1.8 volt resp. 3.3 volt VDDIO_SDMMC3 depending on EN_+3.3_SDMMC3 GPIO */
+static struct regulator_consumer_supply gpio_reg_sdmmc3_vdd_sel_supply[] = {
+ REGULATOR_SUPPLY("vddio_sdmmc_1v8_3v3", NULL),
+ REGULATOR_SUPPLY("vddio_sdmmc", "sdhci-tegra.2"),
+};
+
+static struct gpio_regulator_state gpio_reg_sdmmc3_vdd_sel_states[] = {
+ {
+ .gpios = 0,
+ .value = 1800000,
+ },
+ {
+ .gpios = 1,
+ .value = 3300000,
+ },
+};
+
+static struct gpio gpio_reg_sdmmc3_vdd_sel_gpios[] = {
+ {
+ .gpio = TEGRA_GPIO_PJ5,
+ .flags = 0,
+ .label = "EN_+3.3_SDMMC3",
+ },
+};
+
+/* Macro for defining gpio regulator device data */
+#define GPIO_REG(_id, _name, _input_supply, _active_high, \
+ _boot_state, _delay_us, _minmv, _maxmv) \
+ static struct regulator_init_data ri_data_##_name = \
+ { \
+ .supply_regulator = _input_supply, \
+ .num_consumer_supplies = \
+ ARRAY_SIZE(gpio_reg_##_name##_supply), \
+ .consumer_supplies = gpio_reg_##_name##_supply, \
+ .constraints = { \
+ .name = "gpio_reg_"#_name, \
+ .min_uV = (_minmv)*1000, \
+ .max_uV = (_maxmv)*1000, \
+ .valid_modes_mask = (REGULATOR_MODE_NORMAL | \
+ REGULATOR_MODE_STANDBY), \
+ .valid_ops_mask = (REGULATOR_CHANGE_MODE | \
+ REGULATOR_CHANGE_STATUS | \
+ REGULATOR_CHANGE_VOLTAGE), \
+ }, \
+ }; \
+ static struct gpio_regulator_config gpio_reg_##_name##_pdata = \
+ { \
+ .supply_name = _input_supply, \
+ .enable_gpio = -EINVAL, \
+ .enable_high = _active_high, \
+ .enabled_at_boot = _boot_state, \
+ .startup_delay = _delay_us, \
+ .gpios = gpio_reg_##_name##_gpios, \
+ .nr_gpios = ARRAY_SIZE(gpio_reg_##_name##_gpios), \
+ .states = gpio_reg_##_name##_states, \
+ .nr_states = ARRAY_SIZE(gpio_reg_##_name##_states), \
+ .type = REGULATOR_VOLTAGE, \
+ .init_data = &ri_data_##_name, \
+ }; \
+ static struct platform_device gpio_reg_##_name##_dev = { \
+ .name = "gpio-regulator", \
+ .id = _id, \
+ .dev = { \
+ .platform_data = &gpio_reg_##_name##_pdata, \
+ }, \
+ }
+
+GPIO_REG(4, sdmmc3_vdd_sel, FIXED_SUPPLY(v3_3),
+ true, false, 0, 1800, 3300);
+
+#define ADD_GPIO_REG(_name) (&gpio_reg_##_name##_dev)
+static struct platform_device *gpio_regs_devices[] = {
+ ADD_GPIO_REG(sdmmc3_vdd_sel),
+};
+
#ifdef FORCE_OFF_GPIO
static void apalis_t30_power_off(void)
{
@@ -464,11 +543,18 @@ int __init apalis_t30_regulator_init(void)
return 0;
}
-int __init apalis_t30_fixed_regulator_init(void)
+int __init apalis_t30_fixed_and_gpio_regulator_init(void)
{
- return platform_add_devices(fixed_reg_devs_apalis_t30, ARRAY_SIZE(fixed_reg_devs_apalis_t30));
+ int ret;
+
+ ret = platform_add_devices(fixed_reg_devs_apalis_t30,
+ ARRAY_SIZE(fixed_reg_devs_apalis_t30));
+ if (!ret) ret = platform_add_devices(gpio_regs_devices,
+ ARRAY_SIZE(gpio_regs_devices));
+
+ return ret;
}
-subsys_initcall_sync(apalis_t30_fixed_regulator_init);
+subsys_initcall_sync(apalis_t30_fixed_and_gpio_regulator_init);
static void apalis_t30_board_suspend(int lp_state, enum suspend_stage stg)
{
diff --git a/arch/arm/mach-tegra/board-apalis_t30.c b/arch/arm/mach-tegra/board-apalis_t30.c
index d01f420..ef709c8 100644
--- a/arch/arm/mach-tegra/board-apalis_t30.c
+++ b/arch/arm/mach-tegra/board-apalis_t30.c
@@ -622,6 +622,18 @@ static struct platform_device apalis_t30_keys_device = {
/* MMC/SD */
+/* To limit the 8-bit MMC slot to 3.3 volt only operation (e.g. no UHS) */
+int g_sdmmc3_uhs = 0;
+
+static int __init enable_mmc_uhs(char *s)
+{
+ if (!(*s) || !strcmp(s, "1"))
+ g_sdmmc3_uhs = 1;
+
+ return 0;
+}
+__setup("mmc_uhs=", enable_mmc_uhs);
+
static struct tegra_sdhci_platform_data apalis_t30_emmc_platform_data = {
.cd_gpio = -1,
.ddr_clk_limit = 52000000,
@@ -661,6 +673,8 @@ static void __init apalis_t30_sdhci_init(void)
&apalis_t30_emmc_platform_data;
platform_device_register(&tegra_sdhci_device4);
+ if (g_sdmmc3_uhs)
+ apalis_t30_mmccard_platform_data.no_1v8 = 0;
tegra_sdhci_device3.dev.platform_data =
&apalis_t30_mmccard_platform_data;
platform_device_register(&tegra_sdhci_device3);