Merge tag 'gpio-v4.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
[linux] / drivers / gpio / gpio-mxs.c
index ee17248..1e8fde8 100644 (file)
@@ -87,10 +87,15 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
        u32 val;
        u32 pin_mask = 1 << d->hwirq;
        struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+       struct irq_chip_type *ct = irq_data_get_chip_type(d);
        struct mxs_gpio_port *port = gc->private;
        void __iomem *pin_addr;
        int edge;
 
+       if (!(ct->type & type))
+               if (irq_setup_alt_chip(d, type))
+                       return -EINVAL;
+
        port->both_edges &= ~pin_mask;
        switch (type) {
        case IRQ_TYPE_EDGE_BOTH:
@@ -119,10 +124,13 @@ static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
 
        /* set level or edge */
        pin_addr = port->base + PINCTRL_IRQLEV(port);
-       if (edge & GPIO_INT_LEV_MASK)
+       if (edge & GPIO_INT_LEV_MASK) {
                writel(pin_mask, pin_addr + MXS_SET);
-       else
+               writel(pin_mask, port->base + PINCTRL_IRQEN(port) + MXS_SET);
+       } else {
                writel(pin_mask, pin_addr + MXS_CLR);
+               writel(pin_mask, port->base + PINCTRL_PIN2IRQ(port) + MXS_SET);
+       }
 
        /* set polarity */
        pin_addr = port->base + PINCTRL_IRQPOL(port);
@@ -202,21 +210,37 @@ static int __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
        struct irq_chip_generic *gc;
        struct irq_chip_type *ct;
 
-       gc = irq_alloc_generic_chip("gpio-mxs", 1, irq_base,
+       gc = irq_alloc_generic_chip("gpio-mxs", 2, irq_base,
                                    port->base, handle_level_irq);
        if (!gc)
                return -ENOMEM;
 
        gc->private = port;
 
-       ct = gc->chip_types;
+       ct = &gc->chip_types[0];
+       ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
+       ct->chip.irq_ack = irq_gc_ack_set_bit;
+       ct->chip.irq_mask = irq_gc_mask_disable_reg;
+       ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
+       ct->chip.irq_set_type = mxs_gpio_set_irq_type;
+       ct->chip.irq_set_wake = mxs_gpio_set_wake_irq;
+       ct->chip.flags = IRQCHIP_SET_TYPE_MASKED;
+       ct->regs.ack = PINCTRL_IRQSTAT(port) + MXS_CLR;
+       ct->regs.enable = PINCTRL_PIN2IRQ(port) + MXS_SET;
+       ct->regs.disable = PINCTRL_PIN2IRQ(port) + MXS_CLR;
+
+       ct = &gc->chip_types[1];
+       ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
        ct->chip.irq_ack = irq_gc_ack_set_bit;
-       ct->chip.irq_mask = irq_gc_mask_clr_bit;
-       ct->chip.irq_unmask = irq_gc_mask_set_bit;
+       ct->chip.irq_mask = irq_gc_mask_disable_reg;
+       ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
        ct->chip.irq_set_type = mxs_gpio_set_irq_type;
        ct->chip.irq_set_wake = mxs_gpio_set_wake_irq;
+       ct->chip.flags = IRQCHIP_SET_TYPE_MASKED;
        ct->regs.ack = PINCTRL_IRQSTAT(port) + MXS_CLR;
-       ct->regs.mask = PINCTRL_IRQEN(port);
+       ct->regs.enable = PINCTRL_IRQEN(port) + MXS_SET;
+       ct->regs.disable = PINCTRL_IRQEN(port) + MXS_CLR;
+       ct->handler = handle_level_irq;
 
        irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_NESTED_LOCK,
                               IRQ_NOREQUEST, 0);
@@ -297,11 +321,8 @@ static int mxs_gpio_probe(struct platform_device *pdev)
        }
        port->base = base;
 
-       /*
-        * select the pin interrupt functionality but initially
-        * disable the interrupts
-        */
-       writel(~0U, port->base + PINCTRL_PIN2IRQ(port));
+       /* initially disable the interrupts */
+       writel(0, port->base + PINCTRL_PIN2IRQ(port));
        writel(0, port->base + PINCTRL_IRQEN(port));
 
        /* clear address has to be used to clear IRQSTAT bits */