diff options
author | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2014-12-18 05:48:47 +0100 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2014-12-18 17:20:25 +0100 |
commit | ddcb06fdc59b17a900a7ef61e93fd2ca1f0ced51 (patch) | |
tree | 8541f2f760fdf5d72f47816e9aa86d8345fef33c | |
parent | 629b91fa046df5213ed3312d2e2b8683e6bdd70c (diff) |
apalis_t30: optional mmc uhs support (v1.1a and later hw)Colibri_T30_LinuxImageV2.3Beta5_20141219Colibri_T20_LinuxImageV2.3Beta5_20141219Apalis_T30_LinuxImageV2.3Beta5_20141219
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_defconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/board-apalis_t30-pinmux.c | 28 | ||||
-rw-r--r-- | arch/arm/mach-tegra/board-apalis_t30-power.c | 108 | ||||
-rw-r--r-- | arch/arm/mach-tegra/board-apalis_t30.c | 14 |
4 files changed, 127 insertions, 24 deletions
diff --git a/arch/arm/configs/apalis_t30_defconfig b/arch/arm/configs/apalis_t30_defconfig index 3e22166f9230..6f9194dad295 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 a04a15587129..0f0b5b0ab77c 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 064c438b4b64..eda6d9820847 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 d01f420f33c5..ef709c872d17 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); |