diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpio/s5p_gpio.c | 204 | ||||
-rw-r--r-- | drivers/gpio/tegra_gpio.c | 20 | ||||
-rw-r--r-- | drivers/mmc/tegra_mmc.c | 13 |
3 files changed, 199 insertions, 38 deletions
diff --git a/drivers/gpio/s5p_gpio.c b/drivers/gpio/s5p_gpio.c index 11a0472..db7b673 100644 --- a/drivers/gpio/s5p_gpio.c +++ b/drivers/gpio/s5p_gpio.c @@ -8,11 +8,9 @@ #include <common.h> #include <asm/io.h> #include <asm/gpio.h> +#include <asm/arch/gpio.h> -#define S5P_GPIO_GET_BANK(x) ((x >> S5P_GPIO_BANK_SHIFT) \ - & S5P_GPIO_BANK_MASK) - -#define S5P_GPIO_GET_PIN(x) (x & S5P_GPIO_PIN_MASK) +#define S5P_GPIO_GET_PIN(x) (x % GPIO_PER_BANK) #define CON_MASK(x) (0xf << ((x) << 2)) #define CON_SFR(x, v) ((v) << ((x) << 2)) @@ -28,7 +26,103 @@ #define RATE_MASK(x) (0x1 << (x + 16)) #define RATE_SET(x) (0x1 << (x + 16)) -void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg) +#define name_to_gpio(n) s5p_name_to_gpio(n) +static inline int s5p_name_to_gpio(const char *name) +{ + unsigned num, irregular_set_number, irregular_bank_base; + const struct gpio_name_num_table *tabp; + char this_bank, bank_name, irregular_bank_name; + char *endp; + + /* + * The gpio name starts with either 'g' or 'gp' followed by the bank + * name character. Skip one or two characters depending on the prefix. + */ + if (name[0] == 'g' && name[1] == 'p') + name += 2; + else if (name[0] == 'g') + name++; + else + return -1; /* Name must start with 'g' */ + + bank_name = *name++; + if (!*name) + return -1; /* At least one digit is required/expected. */ + + /* + * On both exynos5 and exynos5420 architectures there is a bank of + * GPIOs which does not fall into the regular address pattern. Those + * banks are c4 on Exynos5 and y7 on Exynos5420. The rest of the below + * assignments help to handle these irregularities. + */ +#if defined(CONFIG_EXYNOS4) || defined(CONFIG_EXYNOS5) + if (cpu_is_exynos5()) { + if (proid_is_exynos5420()) { + tabp = exynos5420_gpio_table; + irregular_bank_name = 'y'; + irregular_set_number = '7'; + irregular_bank_base = EXYNOS5420_GPIO_Y70; + } else { + tabp = exynos5_gpio_table; + irregular_bank_name = 'c'; + irregular_set_number = '4'; + irregular_bank_base = EXYNOS5_GPIO_C40; + } + } else { + if (proid_is_exynos4412()) + tabp = exynos4x12_gpio_table; + else + tabp = exynos4_gpio_table; + irregular_bank_name = 0; + irregular_set_number = 0; + irregular_bank_base = 0; + } +#else + if (cpu_is_s5pc110()) + tabp = s5pc110_gpio_table; + else + tabp = s5pc100_gpio_table; + irregular_bank_name = 0; + irregular_set_number = 0; + irregular_bank_base = 0; +#endif + + this_bank = tabp->bank; + do { + if (bank_name == this_bank) { + unsigned pin_index; /* pin number within the bank */ + if ((bank_name == irregular_bank_name) && + (name[0] == irregular_set_number)) { + pin_index = name[1] - '0'; + /* Irregular sets have 8 pins. */ + if (pin_index >= GPIO_PER_BANK) + return -1; + num = irregular_bank_base + pin_index; + } else { + pin_index = simple_strtoul(name, &endp, 8); + pin_index -= tabp->bank_offset; + /* + * Sanity check: bunk 'z' has no set number, + * for all other banks there must be exactly + * two octal digits, and the resulting number + * should not exceed the number of pins in the + * bank. + */ + if (((bank_name != 'z') && !name[1]) || + *endp || + (pin_index >= tabp->bank_size)) + return -1; + num = tabp->base + pin_index; + } + return num; + } + this_bank = (++tabp)->bank; + } while (this_bank); + + return -1; +} + +static void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg) { unsigned int value; @@ -38,18 +132,7 @@ void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg) writel(value, &bank->con); } -void s5p_gpio_direction_output(struct s5p_gpio_bank *bank, int gpio, int en) -{ - s5p_gpio_cfg_pin(bank, gpio, GPIO_OUTPUT); - s5p_gpio_set_value(bank, gpio, en); -} - -void s5p_gpio_direction_input(struct s5p_gpio_bank *bank, int gpio) -{ - s5p_gpio_cfg_pin(bank, gpio, GPIO_INPUT); -} - -void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en) +static void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en) { unsigned int value; @@ -60,7 +143,19 @@ void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en) writel(value, &bank->dat); } -unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio) +static void s5p_gpio_direction_output(struct s5p_gpio_bank *bank, + int gpio, int en) +{ + s5p_gpio_cfg_pin(bank, gpio, S5P_GPIO_OUTPUT); + s5p_gpio_set_value(bank, gpio, en); +} + +static void s5p_gpio_direction_input(struct s5p_gpio_bank *bank, int gpio) +{ + s5p_gpio_cfg_pin(bank, gpio, S5P_GPIO_INPUT); +} + +static unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio) { unsigned int value; @@ -68,7 +163,7 @@ unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio) return !!(value & DAT_MASK(gpio)); } -void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode) +static void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode) { unsigned int value; @@ -76,8 +171,8 @@ void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode) value &= ~PULL_MASK(gpio); switch (mode) { - case GPIO_PULL_DOWN: - case GPIO_PULL_UP: + case S5P_GPIO_PULL_DOWN: + case S5P_GPIO_PULL_UP: value |= PULL_MODE(gpio, mode); break; default: @@ -87,7 +182,7 @@ void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode) writel(value, &bank->pull); } -void s5p_gpio_set_drv(struct s5p_gpio_bank *bank, int gpio, int mode) +static void s5p_gpio_set_drv(struct s5p_gpio_bank *bank, int gpio, int mode) { unsigned int value; @@ -95,10 +190,10 @@ void s5p_gpio_set_drv(struct s5p_gpio_bank *bank, int gpio, int mode) value &= ~DRV_MASK(gpio); switch (mode) { - case GPIO_DRV_1X: - case GPIO_DRV_2X: - case GPIO_DRV_3X: - case GPIO_DRV_4X: + case S5P_GPIO_DRV_1X: + case S5P_GPIO_DRV_2X: + case S5P_GPIO_DRV_3X: + case S5P_GPIO_DRV_4X: value |= DRV_SET(gpio, mode); break; default: @@ -108,7 +203,7 @@ void s5p_gpio_set_drv(struct s5p_gpio_bank *bank, int gpio, int mode) writel(value, &bank->drv); } -void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode) +static void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode) { unsigned int value; @@ -116,8 +211,8 @@ void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode) value &= ~RATE_MASK(gpio); switch (mode) { - case GPIO_DRV_FAST: - case GPIO_DRV_SLOW: + case S5P_GPIO_DRV_FAST: + case S5P_GPIO_DRV_SLOW: value |= RATE_SET(gpio); break; default: @@ -127,12 +222,31 @@ void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode) writel(value, &bank->drv); } -struct s5p_gpio_bank *s5p_gpio_get_bank(unsigned gpio) +struct s5p_gpio_bank *s5p_gpio_get_bank(unsigned int gpio) { - unsigned bank = S5P_GPIO_GET_BANK(gpio); - unsigned base = s5p_gpio_base(gpio); + const struct gpio_info *data; + unsigned int upto; + int i, count; + + data = get_gpio_data(); + count = get_bank_num(); + upto = 0; + + for (i = 0; i < count; i++) { + debug("i=%d, upto=%d\n", i, upto); + if (gpio < data->max_gpio) { + struct s5p_gpio_bank *bank; + bank = (struct s5p_gpio_bank *)data->reg_addr; + bank += (gpio - upto) / GPIO_PER_BANK; + debug("gpio=%d, bank=%p\n", gpio, bank); + return bank; + } + + upto = data->max_gpio; + data++; + } - return (struct s5p_gpio_bank *)(base + bank); + return NULL; } int s5p_gpio_get_pin(unsigned gpio) @@ -179,3 +293,27 @@ int gpio_set_value(unsigned gpio, int value) return 0; } + +void gpio_set_pull(int gpio, int mode) +{ + s5p_gpio_set_pull(s5p_gpio_get_bank(gpio), + s5p_gpio_get_pin(gpio), mode); +} + +void gpio_set_drv(int gpio, int mode) +{ + s5p_gpio_set_drv(s5p_gpio_get_bank(gpio), + s5p_gpio_get_pin(gpio), mode); +} + +void gpio_cfg_pin(int gpio, int cfg) +{ + s5p_gpio_cfg_pin(s5p_gpio_get_bank(gpio), + s5p_gpio_get_pin(gpio), cfg); +} + +void gpio_set_rate(int gpio, int mode) +{ + s5p_gpio_set_rate(s5p_gpio_get_bank(gpio), + s5p_gpio_get_pin(gpio), mode); +} diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c index 82b30d5..fea9d17 100644 --- a/drivers/gpio/tegra_gpio.c +++ b/drivers/gpio/tegra_gpio.c @@ -221,6 +221,26 @@ int gpio_set_value(unsigned gpio, int value) return 0; } +void gpio_config_table(const struct tegra_gpio_config *config, int len) +{ + int i; + + for (i = 0; i < len; i++) { + switch (config[i].init) { + case TEGRA_GPIO_INIT_IN: + gpio_direction_input(config[i].gpio); + break; + case TEGRA_GPIO_INIT_OUT0: + gpio_direction_output(config[i].gpio, 0); + break; + case TEGRA_GPIO_INIT_OUT1: + gpio_direction_output(config[i].gpio, 1); + break; + } + set_config(config[i].gpio, 1); + } +} + /* * Display Tegra GPIO information */ diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c index ed67eec..ca9c4aa 100644 --- a/drivers/mmc/tegra_mmc.c +++ b/drivers/mmc/tegra_mmc.c @@ -18,7 +18,7 @@ DECLARE_GLOBAL_DATA_PTR; -struct mmc_host mmc_host[MAX_HOSTS]; +struct mmc_host mmc_host[CONFIG_SYS_MMC_MAX_DEVICE]; #ifndef CONFIG_OF_CONTROL #error "Please enable device tree support to use this driver" @@ -669,13 +669,14 @@ static int process_nodes(const void *blob, int node_list[], int count) void tegra_mmc_init(void) { - int node_list[MAX_HOSTS], count; + int node_list[CONFIG_SYS_MMC_MAX_DEVICE], count; const void *blob = gd->fdt_blob; debug("%s entry\n", __func__); /* See if any Tegra124 MMC controllers are present */ count = fdtdec_find_aliases_for_id(blob, "sdhci", - COMPAT_NVIDIA_TEGRA124_SDMMC, node_list, MAX_HOSTS); + COMPAT_NVIDIA_TEGRA124_SDMMC, node_list, + CONFIG_SYS_MMC_MAX_DEVICE); debug("%s: count of Tegra124 sdhci nodes is %d\n", __func__, count); if (process_nodes(blob, node_list, count)) { printf("%s: Error processing T30 mmc node(s)!\n", __func__); @@ -684,7 +685,8 @@ void tegra_mmc_init(void) /* See if any Tegra30 MMC controllers are present */ count = fdtdec_find_aliases_for_id(blob, "sdhci", - COMPAT_NVIDIA_TEGRA30_SDMMC, node_list, MAX_HOSTS); + COMPAT_NVIDIA_TEGRA30_SDMMC, node_list, + CONFIG_SYS_MMC_MAX_DEVICE); debug("%s: count of T30 sdhci nodes is %d\n", __func__, count); if (process_nodes(blob, node_list, count)) { printf("%s: Error processing T30 mmc node(s)!\n", __func__); @@ -693,7 +695,8 @@ void tegra_mmc_init(void) /* Now look for any Tegra20 MMC controllers */ count = fdtdec_find_aliases_for_id(blob, "sdhci", - COMPAT_NVIDIA_TEGRA20_SDMMC, node_list, MAX_HOSTS); + COMPAT_NVIDIA_TEGRA20_SDMMC, node_list, + CONFIG_SYS_MMC_MAX_DEVICE); debug("%s: count of T20 sdhci nodes is %d\n", __func__, count); if (process_nodes(blob, node_list, count)) { printf("%s: Error processing T20 mmc node(s)!\n", __func__); |