Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux...
[deliverable/linux.git] / drivers / gpio / gpio-tegra.c
index bdc2937915906fa7a7589b02e258daccb7b024f7..12f349b3830d29589a6373b32e722f268bac58f9 100644 (file)
 #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)
 #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,
This page took 0.029047 seconds and 5 git commands to generate.