diff options
Diffstat (limited to 'drivers/gpio/gpio-tegra.c')
-rw-r--r-- | drivers/gpio/gpio-tegra.c | 122 |
1 files changed, 93 insertions, 29 deletions
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index bdc293791590..12f349b3830d 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -22,9 +22,10 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/gpio.h> -#include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/module.h> +#include <linux/irqdomain.h> #include <asm/mach/irq.h> @@ -36,7 +37,8 @@ #define GPIO_PORT(x) (((x) >> 3) & 0x3) #define GPIO_BIT(x) ((x) & 0x7) -#define GPIO_REG(x) (GPIO_BANK(x) * 0x80 + GPIO_PORT(x) * 4) +#define GPIO_REG(x) (GPIO_BANK(x) * tegra_gpio_bank_stride + \ + GPIO_PORT(x) * 4) #define GPIO_CNF(x) (GPIO_REG(x) + 0x00) #define GPIO_OE(x) (GPIO_REG(x) + 0x10) @@ -47,12 +49,12 @@ #define GPIO_INT_LVL(x) (GPIO_REG(x) + 0x60) #define GPIO_INT_CLR(x) (GPIO_REG(x) + 0x70) -#define GPIO_MSK_CNF(x) (GPIO_REG(x) + 0x800) -#define GPIO_MSK_OE(x) (GPIO_REG(x) + 0x810) -#define GPIO_MSK_OUT(x) (GPIO_REG(x) + 0X820) -#define GPIO_MSK_INT_STA(x) (GPIO_REG(x) + 0x840) -#define GPIO_MSK_INT_ENB(x) (GPIO_REG(x) + 0x850) -#define GPIO_MSK_INT_LVL(x) (GPIO_REG(x) + 0x860) +#define GPIO_MSK_CNF(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x00) +#define GPIO_MSK_OE(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x10) +#define GPIO_MSK_OUT(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0X20) +#define GPIO_MSK_INT_STA(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x40) +#define GPIO_MSK_INT_ENB(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x50) +#define GPIO_MSK_INT_LVL(x) (GPIO_REG(x) + tegra_gpio_upper_offset + 0x60) #define GPIO_INT_LVL_MASK 0x010101 #define GPIO_INT_LVL_EDGE_RISING 0x000101 @@ -74,9 +76,12 @@ struct tegra_gpio_bank { #endif }; - +static struct irq_domain *irq_domain; static void __iomem *regs; -static struct tegra_gpio_bank tegra_gpio_banks[7]; +static u32 tegra_gpio_bank_count; +static u32 tegra_gpio_bank_stride; +static u32 tegra_gpio_upper_offset; +static struct tegra_gpio_bank *tegra_gpio_banks; static inline void tegra_gpio_writel(u32 val, u32 reg) { @@ -107,11 +112,13 @@ void tegra_gpio_enable(int gpio) { tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1); } +EXPORT_SYMBOL_GPL(tegra_gpio_enable); void tegra_gpio_disable(int gpio) { tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0); } +EXPORT_SYMBOL_GPL(tegra_gpio_disable); static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { @@ -139,7 +146,7 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset, static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { - return TEGRA_GPIO_TO_IRQ(offset); + return irq_find_mapping(irq_domain, offset); } static struct gpio_chip tegra_gpio_chip = { @@ -155,28 +162,28 @@ static struct gpio_chip tegra_gpio_chip = { static void tegra_gpio_irq_ack(struct irq_data *d) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; tegra_gpio_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio)); } static void tegra_gpio_irq_mask(struct irq_data *d) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 0); } static void tegra_gpio_irq_unmask(struct irq_data *d) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 1); } static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) { - int gpio = d->irq - INT_GPIO_BASE; + int gpio = d->hwirq; struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d); int port = GPIO_PORT(gpio); int lvl_type; @@ -273,7 +280,7 @@ void tegra_gpio_resume(void) local_irq_save(flags); - for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) { + for (b = 0; b < tegra_gpio_bank_count; b++) { struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { @@ -296,7 +303,7 @@ void tegra_gpio_suspend(void) int p; local_irq_save(flags); - for (b = 0; b < ARRAY_SIZE(tegra_gpio_banks); b++) { + for (b = 0; b < tegra_gpio_bank_count; b++) { struct tegra_gpio_bank *bank = &tegra_gpio_banks[b]; for (p = 0; p < ARRAY_SIZE(bank->oe); p++) { @@ -329,6 +336,26 @@ static struct irq_chip tegra_gpio_irq_chip = { #endif }; +struct tegra_gpio_soc_config { + u32 bank_stride; + u32 upper_offset; +}; + +static struct tegra_gpio_soc_config tegra20_gpio_config = { + .bank_stride = 0x80, + .upper_offset = 0x800, +}; + +static struct tegra_gpio_soc_config tegra30_gpio_config = { + .bank_stride = 0x100, + .upper_offset = 0x80, +}; + +static struct of_device_id tegra_gpio_of_match[] __devinitdata = { + { .compatible = "nvidia,tegra30-gpio", .data = &tegra30_gpio_config }, + { .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config }, + { }, +}; /* This lock class tells lockdep that GPIO irqs are in a different * category than their parents, so it won't report false recursion. @@ -337,13 +364,55 @@ static struct lock_class_key gpio_lock_class; static int __devinit tegra_gpio_probe(struct platform_device *pdev) { + const struct of_device_id *match; + struct tegra_gpio_soc_config *config; + int irq_base; struct resource *res; struct tegra_gpio_bank *bank; int gpio; int i; int j; - for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { + match = of_match_device(tegra_gpio_of_match, &pdev->dev); + if (match) + config = (struct tegra_gpio_soc_config *)match->data; + else + config = &tegra20_gpio_config; + + tegra_gpio_bank_stride = config->bank_stride; + tegra_gpio_upper_offset = config->upper_offset; + + for (;;) { + res = platform_get_resource(pdev, IORESOURCE_IRQ, tegra_gpio_bank_count); + if (!res) + break; + tegra_gpio_bank_count++; + } + if (!tegra_gpio_bank_count) { + dev_err(&pdev->dev, "Missing IRQ resource\n"); + return -ENODEV; + } + + tegra_gpio_chip.ngpio = tegra_gpio_bank_count * 32; + + tegra_gpio_banks = devm_kzalloc(&pdev->dev, + tegra_gpio_bank_count * sizeof(*tegra_gpio_banks), + GFP_KERNEL); + if (!tegra_gpio_banks) { + dev_err(&pdev->dev, "Couldn't allocate bank structure\n"); + return -ENODEV; + } + + irq_base = irq_alloc_descs(-1, 0, tegra_gpio_chip.ngpio, 0); + if (irq_base < 0) { + dev_err(&pdev->dev, "Couldn't allocate IRQ numbers\n"); + return -ENODEV; + } + irq_domain = irq_domain_add_legacy(pdev->dev.of_node, + tegra_gpio_chip.ngpio, irq_base, 0, + &irq_domain_simple_ops, NULL); + + for (i = 0; i < tegra_gpio_bank_count; i++) { res = platform_get_resource(pdev, IORESOURCE_IRQ, i); if (!res) { dev_err(&pdev->dev, "Missing IRQ resource\n"); @@ -367,7 +436,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) return -ENODEV; } - for (i = 0; i < 7; i++) { + for (i = 0; i < tegra_gpio_bank_count; i++) { for (j = 0; j < 4; j++) { int gpio = tegra_gpio_compose(i, j, 0); tegra_gpio_writel(0x00, GPIO_INT_ENB(gpio)); @@ -380,8 +449,8 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) gpiochip_add(&tegra_gpio_chip); - for (gpio = 0; gpio < TEGRA_NR_GPIOS; gpio++) { - int irq = TEGRA_GPIO_TO_IRQ(gpio); + for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) { + int irq = irq_find_mapping(irq_domain, gpio); /* No validity check; all Tegra GPIOs are valid IRQs */ bank = &tegra_gpio_banks[GPIO_BANK(gpio)]; @@ -393,7 +462,7 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) set_irq_flags(irq, IRQF_VALID); } - for (i = 0; i < ARRAY_SIZE(tegra_gpio_banks); i++) { + for (i = 0; i < tegra_gpio_bank_count; i++) { bank = &tegra_gpio_banks[i]; irq_set_chained_handler(bank->irq, tegra_gpio_irq_handler); @@ -406,11 +475,6 @@ static int __devinit tegra_gpio_probe(struct platform_device *pdev) return 0; } -static struct of_device_id tegra_gpio_of_match[] __devinitdata = { - { .compatible = "nvidia,tegra20-gpio", }, - { }, -}; - static struct platform_driver tegra_gpio_driver = { .driver = { .name = "tegra-gpio", @@ -426,7 +490,7 @@ static int __init tegra_gpio_init(void) } postcore_initcall(tegra_gpio_init); -void __init tegra_gpio_config(struct tegra_gpio_table *table, int num) +void tegra_gpio_config(struct tegra_gpio_table *table, int num) { int i; @@ -450,7 +514,7 @@ static int dbg_gpio_show(struct seq_file *s, void *unused) int i; int j; - for (i = 0; i < 7; i++) { + for (i = 0; i < tegra_gpio_bank_count; i++) { for (j = 0; j < 4; j++) { int gpio = tegra_gpio_compose(i, j, 0); seq_printf(s, |