#include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/irq.h>
-#include <linux/irqdomain.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 };
 #endif
 
+struct dwapb_gpio_port_irqchip {
+       struct irq_chip         irqchip;
+       unsigned int            nr_irqs;
+       unsigned int            irq[DWAPB_MAX_GPIOS];
+};
+
 struct dwapb_gpio_port {
        struct gpio_chip        gc;
+       struct dwapb_gpio_port_irqchip *pirq;
        bool                    is_registered;
        struct dwapb_gpio       *gpio;
 #ifdef CONFIG_PM_SLEEP
 #endif
        unsigned int            idx;
 };
+#define to_dwapb_gpio(_gc) \
+       (container_of(_gc, struct dwapb_gpio_port, gc)->gpio)
 
 struct dwapb_gpio {
        struct  device          *dev;
        void __iomem            *regs;
        struct dwapb_gpio_port  *ports;
        unsigned int            nr_ports;
-       struct irq_domain       *domain;
        unsigned int            flags;
        struct reset_control    *rst;
        struct clk_bulk_data    clks[DWAPB_NR_CLOCKS];
 
 static u32 dwapb_do_irq(struct dwapb_gpio *gpio)
 {
+       struct gpio_chip *gc = &gpio->ports[0].gc;
        unsigned long irq_status;
        irq_hw_number_t hwirq;
 
        irq_status = dwapb_read(gpio, GPIO_INTSTATUS);
        for_each_set_bit(hwirq, &irq_status, DWAPB_MAX_GPIOS) {
-               int gpio_irq = irq_find_mapping(gpio->domain, hwirq);
+               int gpio_irq = irq_find_mapping(gc->irq.domain, hwirq);
                u32 irq_type = irq_get_trigger_type(gpio_irq);
 
                generic_handle_irq(gpio_irq);
        return IRQ_RETVAL(dwapb_do_irq(dev_id));
 }
 
+static void dwapb_irq_ack(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
+       u32 val = BIT(irqd_to_hwirq(d));
+       unsigned long flags;
+
+       spin_lock_irqsave(&gc->bgpio_lock, flags);
+       dwapb_write(gpio, GPIO_PORTA_EOI, val);
+       spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+}
+
+static void dwapb_irq_mask(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&gc->bgpio_lock, flags);
+       val = dwapb_read(gpio, GPIO_INTMASK) | BIT(irqd_to_hwirq(d));
+       dwapb_write(gpio, GPIO_INTMASK, val);
+       spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+}
+
+static void dwapb_irq_unmask(struct irq_data *d)
+{
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&gc->bgpio_lock, flags);
+       val = dwapb_read(gpio, GPIO_INTMASK) & ~BIT(irqd_to_hwirq(d));
+       dwapb_write(gpio, GPIO_INTMASK, val);
+       spin_unlock_irqrestore(&gc->bgpio_lock, flags);
+}
+
 static void dwapb_irq_enable(struct irq_data *d)
 {
-       struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
-       struct dwapb_gpio *gpio = igc->private;
-       struct gpio_chip *gc = &gpio->ports[0].gc;
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
        unsigned long flags;
        u32 val;
 
 
 static void dwapb_irq_disable(struct irq_data *d)
 {
-       struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
-       struct dwapb_gpio *gpio = igc->private;
-       struct gpio_chip *gc = &gpio->ports[0].gc;
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
        unsigned long flags;
        u32 val;
 
 
 static int dwapb_irq_set_type(struct irq_data *d, u32 type)
 {
-       struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
-       struct dwapb_gpio *gpio = igc->private;
-       struct gpio_chip *gc = &gpio->ports[0].gc;
+       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+       struct dwapb_gpio *gpio = to_dwapb_gpio(gc);
        irq_hw_number_t bit = irqd_to_hwirq(d);
        unsigned long level, polarity, flags;
 
                break;
        }
 
-       irq_setup_alt_chip(d, type);
+       if (type & IRQ_TYPE_LEVEL_MASK)
+               irq_set_handler_locked(d, handle_level_irq);
+       else if (type & IRQ_TYPE_EDGE_BOTH)
+               irq_set_handler_locked(d, handle_edge_irq);
 
        dwapb_write(gpio, GPIO_INTTYPE_LEVEL, level);
        if (type != IRQ_TYPE_EDGE_BOTH)
        return dwapb_gpio_set_debounce(gc, offset, debounce);
 }
 
+static int dwapb_convert_irqs(struct dwapb_gpio_port_irqchip *pirq,
+                             struct dwapb_port_property *pp)
+{
+       int i;
+
+       /* Group all available IRQs into an array of parental IRQs. */
+       for (i = 0; i < pp->ngpio; ++i) {
+               if (!pp->irq[i])
+                       continue;
+
+               pirq->irq[pirq->nr_irqs++] = pp->irq[i];
+       }
+
+       return pirq->nr_irqs ? 0 : -ENOENT;
+}
+
 static void dwapb_configure_irqs(struct dwapb_gpio *gpio,
                                 struct dwapb_gpio_port *port,
                                 struct dwapb_port_property *pp)
 {
+       struct dwapb_gpio_port_irqchip *pirq;
        struct gpio_chip *gc = &port->gc;
-       struct fwnode_handle  *fwnode = pp->fwnode;
-       struct irq_chip_generic *irq_gc = NULL;
-       unsigned int ngpio = gc->ngpio;
-       struct irq_chip_type *ct;
-       irq_hw_number_t hwirq;
-       int err, i;
-
-       if (memchr_inv(pp->irq, 0, sizeof(pp->irq)) == NULL) {
-               dev_warn(gpio->dev, "no IRQ for port%d\n", pp->idx);
-               return;
-       }
-
-       gpio->domain = irq_domain_create_linear(fwnode, ngpio,
-                                                &irq_generic_chip_ops, gpio);
-       if (!gpio->domain)
-               return;
+       struct gpio_irq_chip *girq;
+       int err;
 
-       err = irq_alloc_domain_generic_chips(gpio->domain, ngpio, 2,
-                                            DWAPB_DRIVER_NAME, handle_bad_irq,
-                                            IRQ_NOREQUEST, 0,
-                                            IRQ_GC_INIT_NESTED_LOCK);
-       if (err) {
-               dev_info(gpio->dev, "irq_alloc_domain_generic_chips failed\n");
-               irq_domain_remove(gpio->domain);
-               gpio->domain = NULL;
+       pirq = devm_kzalloc(gpio->dev, sizeof(*pirq), GFP_KERNEL);
+       if (!pirq)
                return;
-       }
 
-       irq_gc = irq_get_domain_generic_chip(gpio->domain, 0);
-       if (!irq_gc) {
-               irq_domain_remove(gpio->domain);
-               gpio->domain = NULL;
-               return;
+       if (dwapb_convert_irqs(pirq, pp)) {
+               dev_warn(gpio->dev, "no IRQ for port%d\n", pp->idx);
+               goto err_kfree_pirq;
        }
 
-       irq_gc->reg_base = gpio->regs;
-       irq_gc->private = gpio;
-
-       for (i = 0; i < 2; i++) {
-               ct = &irq_gc->chip_types[i];
-               ct->chip.irq_ack = irq_gc_ack_set_bit;
-               ct->chip.irq_mask = irq_gc_mask_set_bit;
-               ct->chip.irq_unmask = irq_gc_mask_clr_bit;
-               ct->chip.irq_set_type = dwapb_irq_set_type;
-               ct->chip.irq_enable = dwapb_irq_enable;
-               ct->chip.irq_disable = dwapb_irq_disable;
+       girq = &gc->irq;
+       girq->handler = handle_bad_irq;
+       girq->default_type = IRQ_TYPE_NONE;
+
+       port->pirq = pirq;
+       pirq->irqchip.name = DWAPB_DRIVER_NAME;
+       pirq->irqchip.irq_ack = dwapb_irq_ack;
+       pirq->irqchip.irq_mask = dwapb_irq_mask;
+       pirq->irqchip.irq_unmask = dwapb_irq_unmask;
+       pirq->irqchip.irq_set_type = dwapb_irq_set_type;
+       pirq->irqchip.irq_enable = dwapb_irq_enable;
+       pirq->irqchip.irq_disable = dwapb_irq_disable;
 #ifdef CONFIG_PM_SLEEP
-               ct->chip.irq_set_wake = dwapb_irq_set_wake;
+       pirq->irqchip.irq_set_wake = dwapb_irq_set_wake;
 #endif
-               ct->regs.ack = gpio_reg_convert(gpio, GPIO_PORTA_EOI);
-               ct->regs.mask = gpio_reg_convert(gpio, GPIO_INTMASK);
-               ct->type = IRQ_TYPE_LEVEL_MASK;
-       }
-
-       irq_gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK;
-       irq_gc->chip_types[0].handler = handle_level_irq;
-       irq_gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
-       irq_gc->chip_types[1].handler = handle_edge_irq;
 
        if (!pp->irq_shared) {
-               int i;
-
-               for (i = 0; i < pp->ngpio; i++) {
-                       if (pp->irq[i])
-                               irq_set_chained_handler_and_data(pp->irq[i],
-                                               dwapb_irq_handler, gpio);
-               }
+               girq->num_parents = pirq->nr_irqs;
+               girq->parents = pirq->irq;
+               girq->parent_handler_data = gpio;
+               girq->parent_handler = dwapb_irq_handler;
        } else {
+               /* This will let us handle the parent IRQ in the driver */
+               girq->num_parents = 0;
+               girq->parents = NULL;
+               girq->parent_handler = NULL;
+
                /*
                 * Request a shared IRQ since where MFD would have devices
                 * using the same irq pin
                                       IRQF_SHARED, DWAPB_DRIVER_NAME, gpio);
                if (err) {
                        dev_err(gpio->dev, "error requesting IRQ\n");
-                       irq_domain_remove(gpio->domain);
-                       gpio->domain = NULL;
-                       return;
+                       goto err_kfree_pirq;
                }
        }
 
-       for (hwirq = 0; hwirq < ngpio; hwirq++)
-               irq_create_mapping(gpio->domain, hwirq);
+       girq->chip = &pirq->irqchip;
 
        port->gc.to_irq = dwapb_gpio_to_irq;
-}
-
-static void dwapb_irq_teardown(struct dwapb_gpio *gpio)
-{
-       struct dwapb_gpio_port *port = &gpio->ports[0];
-       struct gpio_chip *gc = &port->gc;
-       unsigned int ngpio = gc->ngpio;
-       irq_hw_number_t hwirq;
-
-       if (!gpio->domain)
-               return;
 
-       for (hwirq = 0; hwirq < ngpio; hwirq++)
-               irq_dispose_mapping(irq_find_mapping(gpio->domain, hwirq));
+       return;
 
-       irq_domain_remove(gpio->domain);
-       gpio->domain = NULL;
+err_kfree_pirq:
+       devm_kfree(gpio->dev, pirq);
 }
 
 static int dwapb_gpio_add_port(struct dwapb_gpio *gpio,
 
 out_unregister:
        dwapb_gpio_unregister(gpio);
-       dwapb_irq_teardown(gpio);
        clk_bulk_disable_unprepare(DWAPB_NR_CLOCKS, gpio->clks);
 
        return err;
        struct dwapb_gpio *gpio = platform_get_drvdata(pdev);
 
        dwapb_gpio_unregister(gpio);
-       dwapb_irq_teardown(gpio);
        reset_control_assert(gpio->rst);
        clk_bulk_disable_unprepare(DWAPB_NR_CLOCKS, gpio->clks);