]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/gpio/gpio-omap.c
Merge remote-tracking branch 'sound-current/for-linus'
[karo-tx-linux.git] / drivers / gpio / gpio-omap.c
index 5236db161e76047db31bf8c8e5ae7299f12fd06d..56d2d026e62e42bf6fec7db5ad2aa25aebd970f3 100644 (file)
@@ -51,7 +51,7 @@ struct gpio_regs {
 struct gpio_bank {
        struct list_head node;
        void __iomem *base;
-       u16 irq;
+       int irq;
        u32 non_wakeup_gpios;
        u32 enabled_non_wakeup_gpios;
        struct gpio_regs context;
@@ -59,6 +59,7 @@ struct gpio_bank {
        u32 level_mask;
        u32 toggle_mask;
        raw_spinlock_t lock;
+       raw_spinlock_t wa_lock;
        struct gpio_chip chip;
        struct clk *dbck;
        u32 mod_usage;
@@ -496,9 +497,6 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
                (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
                return -EINVAL;
 
-       if (!BANK_USED(bank))
-               pm_runtime_get_sync(bank->dev);
-
        raw_spin_lock_irqsave(&bank->lock, flags);
        retval = omap_set_gpio_triggering(bank, offset, type);
        if (retval) {
@@ -521,8 +519,6 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
        return 0;
 
 error:
-       if (!BANK_USED(bank))
-               pm_runtime_put(bank->dev);
        return retval;
 }
 
@@ -654,8 +650,13 @@ static int omap_gpio_wake_enable(struct irq_data *d, unsigned int enable)
 {
        struct gpio_bank *bank = omap_irq_data_get_bank(d);
        unsigned offset = d->hwirq;
+       int ret;
+
+       ret = omap_set_gpio_wakeup(bank, offset, enable);
+       if (!ret)
+               ret = irq_set_irq_wake(bank->irq, enable);
 
-       return omap_set_gpio_wakeup(bank, offset, enable);
+       return ret;
 }
 
 static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -709,26 +710,21 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
  * line's interrupt handler has been run, we may miss some nested
  * interrupts.
  */
-static void omap_gpio_irq_handler(struct irq_desc *desc)
+static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
 {
        void __iomem *isr_reg = NULL;
        u32 isr;
        unsigned int bit;
-       struct gpio_bank *bank;
-       int unmasked = 0;
-       struct irq_chip *irqchip = irq_desc_get_chip(desc);
-       struct gpio_chip *chip = irq_desc_get_handler_data(desc);
+       struct gpio_bank *bank = gpiobank;
+       unsigned long wa_lock_flags;
        unsigned long lock_flags;
 
-       chained_irq_enter(irqchip, desc);
-
-       bank = container_of(chip, struct gpio_bank, chip);
        isr_reg = bank->base + bank->regs->irqstatus;
-       pm_runtime_get_sync(bank->dev);
-
        if (WARN_ON(!isr_reg))
                goto exit;
 
+       pm_runtime_get_sync(bank->dev);
+
        while (1) {
                u32 isr_saved, level_mask = 0;
                u32 enabled;
@@ -750,13 +746,6 @@ static void omap_gpio_irq_handler(struct irq_desc *desc)
 
                raw_spin_unlock_irqrestore(&bank->lock, lock_flags);
 
-               /* if there is only edge sensitive GPIO pin interrupts
-               configured, we could unmask GPIO bank interrupt immediately */
-               if (!level_mask && !unmasked) {
-                       unmasked = 1;
-                       chained_irq_exit(irqchip, desc);
-               }
-
                if (!isr)
                        break;
 
@@ -777,18 +766,18 @@ static void omap_gpio_irq_handler(struct irq_desc *desc)
 
                        raw_spin_unlock_irqrestore(&bank->lock, lock_flags);
 
+                       raw_spin_lock_irqsave(&bank->wa_lock, wa_lock_flags);
+
                        generic_handle_irq(irq_find_mapping(bank->chip.irqdomain,
                                                            bit));
+
+                       raw_spin_unlock_irqrestore(&bank->wa_lock,
+                                                  wa_lock_flags);
                }
        }
-       /* if bank has any level sensitive GPIO pin interrupt
-       configured, we must unmask the bank interrupt only after
-       handler(s) are executed in order to avoid spurious bank
-       interrupt */
 exit:
-       if (!unmasked)
-               chained_irq_exit(irqchip, desc);
        pm_runtime_put(bank->dev);
+       return IRQ_HANDLED;
 }
 
 static unsigned int omap_gpio_irq_startup(struct irq_data *d)
@@ -797,9 +786,6 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d)
        unsigned long flags;
        unsigned offset = d->hwirq;
 
-       if (!BANK_USED(bank))
-               pm_runtime_get_sync(bank->dev);
-
        raw_spin_lock_irqsave(&bank->lock, flags);
 
        if (!LINE_USED(bank->mod_usage, offset))
@@ -815,8 +801,6 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d)
        return 0;
 err:
        raw_spin_unlock_irqrestore(&bank->lock, flags);
-       if (!BANK_USED(bank))
-               pm_runtime_put(bank->dev);
        return -EINVAL;
 }
 
@@ -835,6 +819,19 @@ static void omap_gpio_irq_shutdown(struct irq_data *d)
                omap_clear_gpio_debounce(bank, offset);
        omap_disable_gpio_module(bank, offset);
        raw_spin_unlock_irqrestore(&bank->lock, flags);
+}
+
+static void omap_gpio_irq_bus_lock(struct irq_data *data)
+{
+       struct gpio_bank *bank = omap_irq_data_get_bank(data);
+
+       if (!BANK_USED(bank))
+               pm_runtime_get_sync(bank->dev);
+}
+
+static void gpio_irq_bus_sync_unlock(struct irq_data *data)
+{
+       struct gpio_bank *bank = omap_irq_data_get_bank(data);
 
        /*
         * If this is the last IRQ to be freed in the bank,
@@ -1132,7 +1129,7 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
        }
 
        ret = gpiochip_irqchip_add(&bank->chip, irqc,
-                                  irq_base, omap_gpio_irq_handler,
+                                  irq_base, handle_bad_irq,
                                   IRQ_TYPE_NONE);
 
        if (ret) {
@@ -1141,10 +1138,14 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
                return -ENODEV;
        }
 
-       gpiochip_set_chained_irqchip(&bank->chip, irqc,
-                                    bank->irq, omap_gpio_irq_handler);
+       gpiochip_set_chained_irqchip(&bank->chip, irqc, bank->irq, NULL);
 
-       return 0;
+       ret = devm_request_irq(bank->dev, bank->irq, omap_gpio_irq_handler,
+                              0, dev_name(bank->dev), bank);
+       if (ret)
+               gpiochip_remove(&bank->chip);
+
+       return ret;
 }
 
 static const struct of_device_id omap_gpio_match[];
@@ -1183,6 +1184,8 @@ static int omap_gpio_probe(struct platform_device *pdev)
        irqc->irq_unmask = omap_gpio_unmask_irq,
        irqc->irq_set_type = omap_gpio_irq_type,
        irqc->irq_set_wake = omap_gpio_wake_enable,
+       irqc->irq_bus_lock = omap_gpio_irq_bus_lock,
+       irqc->irq_bus_sync_unlock = gpio_irq_bus_sync_unlock,
        irqc->name = dev_name(&pdev->dev);
 
        bank->irq = platform_get_irq(pdev, 0);
@@ -1224,6 +1227,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
                bank->set_dataout = omap_set_gpio_dataout_mask;
 
        raw_spin_lock_init(&bank->lock);
+       raw_spin_lock_init(&bank->wa_lock);
 
        /* Static mapping, never released */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);