diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index bfcd20699ec8..8b89f03076c2 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -310,6 +310,107 @@ int of_gpio_simple_xlate(struct gpio_chip *gc,
 EXPORT_SYMBOL(of_gpio_simple_xlate);
 
 /**
+ * gpio_banked_irq_domain_xlate - decode an IRQ specifier for banked chips
+ * @domain: IRQ domain
+ * @np: device tree node
+ * @spec: IRQ specifier
+ * @size: number of cells in IRQ specifier
+ * @hwirq: return location for the hardware IRQ number
+ * @type: return location for the IRQ type
+ *
+ * Translates the IRQ specifier found in device tree into a hardware IRQ
+ * number and an interrupt type.
+ *
+ * Returns:
+ * 0 on success or a negative error code on failure.
+ */
+int gpio_banked_irq_domain_xlate(struct irq_domain *domain,
+				 struct device_node *np,
+				 const u32 *spec, unsigned int size,
+				 unsigned long *hwirq,
+				 unsigned int *type)
+{
+	struct gpio_chip *gc = domain->host_data;
+	unsigned int bank, pin, i, offset = 0;
+
+	if (size < 2)
+		return -EINVAL;
+
+	bank = (spec[0] >> gc->of_gpio_bank_mask) & gc->of_gpio_bank_shift;
+	pin = (spec[0] >> gc->of_gpio_pin_mask) & gc->of_gpio_pin_shift;
+
+	if (bank >= gc->num_banks) {
+		dev_err(gc->parent, "invalid bank number: %u\n", bank);
+		return -EINVAL;
+	}
+
+	if (pin >= gc->banks[bank]->num_pins) {
+		dev_err(gc->parent, "invalid pin number: %u\n", pin);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < bank; i++)
+		offset += gc->banks[i]->num_pins;
+
+	*type = spec[1] & IRQ_TYPE_SENSE_MASK;
+	*hwirq = offset + pin;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(gpio_banked_irq_domain_xlate);
+
+/**
+ * of_gpio_banked_xlate - translate GPIO specifier to a GPIO number and flags
+ * @gc: GPIO chip
+ * @gpiospec: GPIO specifier
+ * @flags: return location for flags parsed from the GPIO specifier
+ *
+ * This translation function takes into account multiple banks that can make
+ * up a single controller. Each bank can contain one or more pins. A single
+ * cell in the specifier is used to represent a (bank, pin) pair, with each
+ * encoded in different fields. The &gpio_chip.of_gpio_bank_shift and
+ * &gpio_chip.of_gpio_bank_mask fields, and &gpio_chip.of_gpio_pin_shift and
+ * &gpio_chip.of_gpio_pin_mask are used to specify the encoding.
+ *
+ * Returns:
+ * The chip-relative index of the pin given by the GPIO specifier.
+ */
+int of_gpio_banked_xlate(struct gpio_chip *gc,
+			 const struct of_phandle_args *gpiospec, u32 *flags)
+{
+	unsigned int offset = 0, bank, pin, i;
+	const u32 *spec = gpiospec->args;
+
+	if (WARN_ON(gc->of_gpio_n_cells < 2))
+		return -EINVAL;
+
+	if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
+		return -EINVAL;
+
+	bank = (spec[0] >> gc->of_gpio_bank_shift) & gc->of_gpio_bank_mask;
+	pin = (spec[0] >> gc->of_gpio_pin_shift) & gc->of_gpio_pin_mask;
+
+	if (bank >= gc->num_banks) {
+		dev_err(gc->parent, "invalid bank number: %u\n", bank);
+		return -EINVAL;
+	}
+
+	if (pin >= gc->banks[bank]->num_pins) {
+		dev_err(gc->parent, "invalid pin number: %u\n", pin);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < bank; i++)
+		offset += gc->banks[i]->num_pins;
+
+	if (flags)
+		*flags = spec[1];
+
+	return offset + pin;
+}
+EXPORT_SYMBOL(of_gpio_banked_xlate);
+
+/**
  * of_mm_gpiochip_add_data - Add memory mapped GPIO chip (bank)
  * @np:		device node of the GPIO chip
  * @mm_gc:	pointer to the of_mm_gpio_chip allocated structure
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 7a16dd37bd3d..306c3a13e814 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1776,6 +1776,57 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
 	gpiochip->to_irq = gpiochip_to_irq;
 	gpiochip->irq.default_type = type;
 
+	if (gpiochip->num_banks > 0 && !gpiochip->irq.map) {
+		struct gpio_irq_chip *irq = &gpiochip->irq;
+		unsigned int i, j, offset = 0;
+
+		if (!irq->parents) {
+			chip_err(gpiochip, "no parent interrupts defined\n");
+			return -EINVAL;
+		}
+
+		irq->map = devm_kcalloc(gpiochip->parent, gpiochip->ngpio,
+					sizeof(*irq->map), GFP_KERNEL);
+		if (!irq->map)
+			return -ENOMEM;
+
+		for (i = 0; i < gpiochip->num_banks; i++) {
+			struct gpio_bank *bank = gpiochip->banks[i];
+			unsigned int parent = bank->parent_irq;
+
+			for (j = 0; j < bank->num_pins; j++) {
+				if (parent >= irq->num_parents) {
+					chip_err(gpiochip,
+						 "invalid parent interrupt: %u\n",
+						 parent);
+					return -EINVAL;
+				}
+
+				irq->map[offset + j] = irq->parents[parent];
+			}
+
+			offset += bank->num_pins;
+		}
+	}
+
+	if (gpiochip->num_banks > 0) {
+		unsigned int i;
+
+		for (i = 0; i < gpiochip->num_banks; i++) {
+			struct gpio_bank *bank = gpiochip->banks[i];
+			unsigned int num_pins = bank->num_pins;
+
+			bank->pending = devm_kcalloc(gpiochip->parent,
+						     BITS_TO_LONGS(num_pins),
+						     sizeof(unsigned long),
+						     GFP_KERNEL);
+			if (!bank->pending)
+				return -ENOMEM;
+
+			bank->chip = gpiochip;
+		}
+	}
+
 	if (gpiochip->irq.domain_ops)
 		ops = gpiochip->irq.domain_ops;
 	else
@@ -1984,6 +2035,53 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 }
 EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
 
+/**
+ * gpio_irq_chip_banked_handler - interrupt handler for banked IRQ chips
+ * @desc: IRQ descriptor
+ *
+ * Drivers can use this interrupt handler for banked GPIO controllers. This
+ * implementation iterates over all banks and handles pending interrupts of
+ * the pins associated with the bank.
+ *
+ * This function uses driver specific parts, split out into the
+ * &gpio_chip.update_bank() callback, to retrieves the interrupt pending
+ * state for each of the GPIOs exposed by the given bank.
+ */
+void gpio_irq_chip_banked_handler(struct irq_desc *desc)
+{
+	struct gpio_chip *gpio = irq_desc_get_handler_data(desc);
+	struct irq_chip *irq = irq_desc_get_chip(desc);
+	unsigned int parent = irq_desc_get_irq(desc);
+	struct gpio_irq_chip *chip = &gpio->irq;
+	unsigned int i, offset = 0;
+
+	chained_irq_enter(irq, desc);
+
+	for (i = 0; i < gpio->num_banks; i++) {
+		struct gpio_bank *bank = gpio->banks[i];
+		unsigned int pin, virq;
+
+		if (parent != chip->parents[bank->parent_irq])
+			goto skip;
+
+		chip->update_bank(bank);
+
+		for_each_set_bit(pin, bank->pending, bank->num_pins) {
+			virq = irq_find_mapping(chip->domain, offset + pin);
+			if (WARN_ON(virq == 0))
+				continue;
+
+			generic_handle_irq(virq);
+		}
+
+skip:
+		offset += bank->num_pins;
+	}
+
+	chained_irq_exit(irq, desc);
+}
+EXPORT_SYMBOL_GPL(gpio_irq_chip_banked_handler);
+
 #else /* CONFIG_GPIOLIB_IRQCHIP */
 
 static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index c453e0716228..ecbeb50f8801 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -19,6 +19,47 @@ struct module;
 
 #ifdef CONFIG_GPIOLIB
 
+/**
+ * struct gpio_bank - GPIO bank
+ *
+ * A GPIO bank, sometimes also referred to as port, represents a subset of the
+ * pins of a GPIO controller. The separation into banks is often caused by the
+ * sharing of one or more resource (register region, interrupt, ...) for each
+ * of the pins in the bank.
+ *
+ * In many cases the banking is transparent, but when it is not, GPIO drivers
+ * can use this code, along with some supporting fields in &struct gpio_chip.
+ */
+struct gpio_bank {
+	/**
+	 * @chip:
+	 *
+	 * A pointer to the &struct gpio_chip that this bank belongs to.
+	 */
+	struct gpio_chip *chip;
+
+	/**
+	 * @parent_irq:
+	 *
+	 * The interrupt parent for this bank.
+	 */
+	unsigned int parent_irq;
+
+	/**
+	 * @num_pins:
+	 *
+	 * The number of pins provided by this bank.
+	 */
+	unsigned int num_pins;
+
+	/**
+	 * @pending:
+	 *
+	 * Current interrupt state of each pin in the bank.
+	 */
+	unsigned long *pending;
+};
+
 #ifdef CONFIG_GPIOLIB_IRQCHIP
 /**
  * struct gpio_irq_chip - GPIO interrupt controller
@@ -136,6 +177,15 @@ struct gpio_irq_chip {
 	 * in IRQ domain of the chip.
 	 */
 	unsigned long *valid_mask;
+
+	/**
+	 * @update_bank:
+	 *
+	 * Callback used by banked interrupt controllers. The driver updates
+	 * the &gpio_bank.pending field of the given @bank with the current
+	 * status for each of the GPIOs that it provides.
+	 */
+	void (*update_bank)(struct gpio_bank *bank);
 };
 
 static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
@@ -281,6 +331,24 @@ struct gpio_chip {
 	struct gpio_irq_chip irq;
 #endif
 
+	/**
+	 * @banks:
+	 *
+	 * If a GPIO controller is subdivided into multiple banks, the driver
+	 * can use this field to store information about these banks.
+	 *
+	 * Note that the driver owns this field and the core will not modify
+	 * it, only reference it.
+	 */
+	struct gpio_bank **banks;
+
+	/**
+	 * @num_banks:
+	 *
+	 * The number of banks described in @banks.
+	 */
+	unsigned int num_banks;
+
 #if defined(CONFIG_OF_GPIO)
 	/*
 	 * If CONFIG_OF is enabled, then all GPIO controllers described in the
@@ -302,6 +370,38 @@ struct gpio_chip {
 	unsigned int of_gpio_n_cells;
 
 	/**
+	 * @of_gpio_bank_shift:
+	 *
+	 * The offset of the field in the cell denoting the bank number of a
+	 * specified GPIO.
+	 */
+	unsigned int of_gpio_bank_shift;
+
+	/**
+	 * @of_gpio_bank_mask:
+	 *
+	 * The mask of the field in the cell denoting the bank number of a
+	 * specified GPIO.
+	 */
+	unsigned int of_gpio_bank_mask;
+
+	/**
+	 * @of_gpio_pin_shift:
+	 *
+	 * The offset of the field in the cell denoting the pin number of a
+	 * specified GPIO within its bank.
+	 */
+	unsigned int of_gpio_pin_shift;
+
+	/**
+	 * @of_gpio_pin_mask:
+	 *
+	 * The mask of the field in the cell denoting the pin number of a
+	 * specified GPIO within its bank.
+	 */
+	unsigned int of_gpio_pin_mask;
+
+	/**
 	 * @of_xlate:
 	 *
 	 * Callback to translate a device tree GPIO specifier into a chip-
@@ -374,6 +474,12 @@ int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
 		     irq_hw_number_t hwirq);
 void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq);
 
+int gpio_banked_irq_domain_xlate(struct irq_domain *domain,
+				 struct device_node *np,
+				 const u32 *spec, unsigned int size,
+				 unsigned long *hwirq,
+				 unsigned int *type);
+
 void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
 		struct irq_chip *irqchip,
 		unsigned int parent_irq,
@@ -391,6 +497,8 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 			     bool nested,
 			     struct lock_class_key *lock_key);
 
+void gpio_irq_chip_banked_handler(struct irq_desc *desc);
+
 #ifdef CONFIG_LOCKDEP
 
 /*
diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h
index ca10f43564de..f85414dc31f4 100644
--- a/include/linux/of_gpio.h
+++ b/include/linux/of_gpio.h
@@ -66,6 +66,9 @@ extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc);
 extern int of_gpio_simple_xlate(struct gpio_chip *gc,
 				const struct of_phandle_args *gpiospec,
 				u32 *flags);
+extern int of_gpio_banked_xlate(struct gpio_chip *gc,
+				const struct of_phandle_args *gpiospec,
+				u32 *flags);
 
 #else /* CONFIG_OF_GPIO */
 
@@ -86,6 +89,13 @@ static inline int of_gpio_simple_xlate(struct gpio_chip *gc,
 	return -ENOSYS;
 }
 
+static inline int of_gpio_banked_xlate(struct gpio_chip *gc,
+				       const struct of_phandle_args *gpiospec,
+				       u32 *flags)
+{
+	return -ENOSYS;
+}
+
 #endif /* CONFIG_OF_GPIO */
 
 /**
