diff mbox series

[1/1] Merge xilinx gpio driver from linux-xlnx

Message ID 5D23E7CAADD3BE4A97642792FFC691C561C79D8A@MBX215.d.ethz.ch
State New
Headers show
Series [1/1] Merge xilinx gpio driver from linux-xlnx | expand

Commit Message

Hedges Alexander July 19, 2018, 3:22 p.m. UTC
This updates gpio-xilinx to include all the commits which are only present in
the official Xilinx Linux repository (github.com/Xilinx/linux-xlnx). The last
common ancestor is 64842aad5ec5, after that, linux-xlnx has not been merged into
mainline linux.

The only thing added in the merge is the second lock_class_key which is needed
by irq_set_lockdep_class after the signature change in 39c3fd58952d.

The changes to gpio-xilinx.c from the following commits are included:

commit 184f4682479b34d279d8fec236126b7e2f6a94ce
Author: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
Date: Thu May 3 14:35:46 2018 +0530
Title: gpio: xilinx: Add support for no initialisation at probe

commit dbf204e7a104cd1bb5eeaec945811c986bed4840
Author: Swapna Manupati <swapna.manupati@xilinx.com>
Date: Wed Mar 7 17:03:19 2018 +0530
Title: gpio: xilinx: Add reset support

commit 3bbc2fda8018d067910eac153c1f30caa509828a
Author: Venkatesh Yadav Abbarapu <venkatesh.abbarapu@xilinx.com>
Date: Wed Jan 24 18:20:19 2018 +0530
Title: gpio: xilinx: defer the probe if clock is not found

commit 1bd0377e19ba07436d1430f444f701c97e9cefd1
Author: Michal Simek <michal.simek@xilinx.com>
Date: Mon Oct 16 10:30:20 2017 +0200
Title: gpio: Fix typo in gpio driver

commit 3da7287a068080a6e100ddfef449ab94bebd429d
Author: Nava kishore Manne <nava.manne@xilinx.com>
Date: Wed Apr 19 17:41:20 2017 +0530
Title: gpio: gpio-xilinx: Fix warnings in the driver

commit 24132f85de16dd69948ed1fd1cd6bfef3802e9bd
Author: Nava kishore Manne <nava.manne@xilinx.com>
Date: Wed Apr 19 14:54:20 2017 +0530
Title: gpio: gpio-xilinx.c: Fix kernel doc warnings

commit 30b6bc689ae71b657f5e1f7fb86468b9d8edcfc2
Author: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
Date: Thu Apr 6 16:12:00 2017 +0530
Title: gpio: xilinx: Fix the NULL pointer access

commit e469c51aeca082452d0d34897f713906f4d3599a
Author: Michal Simek <michal.simek@xilinx.com>
Date: Tue Feb 14 16:16:56 2017 +0100
Title: gpio: Add simple remove and exit functions

commit 34b6b71b142476b9e377f2e21b087eb8434176cd
Author: Maulik Jodhani <maulik.jodhani@xilinx.com>
Date: Fri Feb 10 06:31:30 2017 -0800
Title: gpio: xilinx: Add clock adaptation support

commit c8105d8066c1b9ba5f8e160c213c7605ba6dffab
Author: Michal Simek <michal.simek@xilinx.com>
Date: Thu Jul 28 14:59:50 2016 +0200
Title: gpio: xilinx: Use readl/writel for ARM64

commit 1c9c40cbcbd896a6ee35e46560b5c3e99718c620
Author: Iban Rodriguez <irodriguez@cemitec.com>
Date: Mon Jun 13 12:53:39 2016 +0200
Title: gpio: xilinx: Always use own xlate function

commit 63bcc8b82965b185e632170dca04185539d970f9
Author: Iban Rodriguez <irodriguez@cemitec.com>
Date: Fri May 13 12:11:46 2016 +0200
Title: gpio: xilinx: Add support to set multiple GPIO at once

commit 426ad456b920a9b26394b1f973c100cf3984b954
Author: Topi Kuutela <topi.kuutela@gmail.com>
Date: Wed May 11 14:53:41 2016 +0300
Title: gpio: xilinx: Fix irq-handler prototype

commit 4fdaf2960d8ccecb504d312d2f7b2d532941a8dd
Author: Michal Simek <michal.simek@xilinx.com>
Date: Wed Jun 17 06:44:12 2015 +0200
Title: xilinx: Remove owner field from platform_driver

commit 616ac116ab2dcfe603c67ea3c8f70d5889aa6fc9
Author: Michal Simek <michal.simek@xilinx.com>
Date: Tue Sep 3 17:06:19 2013 +0200
Title: gpio: xilinx: Use platform_driver

commit 5f35773def8d97fcc48c587f54439ca12fc6a601
Author: Michal Simek <michal.simek@xilinx.com>
Date: Tue Sep 3 16:43:47 2013 +0200
Title: gpio: xilinx: Fix minor coding style issue.

commit 32161b344f3eb80f59bd99e9ca215a93b40b929a
Author: Michal Simek <michal.simek@xilinx.com>
Date: Tue Sep 3 16:22:12 2013 +0200
Title: gpio: xilinx: Fix type for irq_base

commit 9a5d02ee0f4fc8f7ff461e8955eaed19e542bed8
Author: Michal Simek <michal.simek@xilinx.com>
Date: Tue Aug 6 13:59:47 2013 +0200
Title: GPIO: xilinx: Do not use xgpiops but use only xgpio

commit 7c58460d5bb43758d879f391e85b7b857160d488
Author: Michal Simek <michal.simek@xilinx.com>
Date: Tue Aug 6 13:16:36 2013 +0200
Title: GPIO: xilinx: Do not allocate interrupts for IPs without IRQ support

commit 796ae5e3e4ae5f550e0ba01ade34604c83b08cfd
Author: Michal Simek <michal.simek@xilinx.com>
Date: Fri Jul 19 14:34:36 2013 +0200
Title: GPIO: xilinx: Add irq support to the driver

commit 8fd1942dec9edd0175dc6f242a9ab8c663c07fb9
Author: Michal Simek <michal.simek@xilinx.com>
Date: Fri Jul 19 14:31:15 2013 +0200
Title: GPIO: xilinx: Fix kernel-doc mainline

commit 6ecc02b189fb0147dd3221ff347f42901c575927
Author: Michal Simek <michal.simek@xilinx.com>
Date: Wed Jul 17 15:22:20 2013 +0200
Title: GPIO: xilinx: Use standard coding style for macros

commit 324c11445a487744dd2e4c286b63e83fc18eae54
Author: Michal Simek <michal.simek@xilinx.com>
Date: Tue Nov 27 15:40:47 2012 +0100
Title: gpio: gpio-xilinx: Remove CONFIG_OF conditionals

commit fb2379e7035e9855543e49637828aca4b7e72f58
Author: Michal Simek <monstr@monstr.eu>
Date: Fri Oct 19 10:49:31 2012 +0200
Title: of: gpio: Add support for dual xilinx GPIO

commit 5a711f8ecdc69bdf6a23494a503dd6f3c39381ce
Author: Naveen Mamindlapalli <naveenm@xilinx.com>
Date: Fri Aug 31 20:11:29 2012 +0530
Title: Xilinx: Microblaze: GPIO: Fixed compilation error.

commit e9a98626baf3b31fa6a699576d8d089c5df10f35
Author: John Linn <john.linn@xilinx.com>
Date: Fri Jun 29 11:27:45 2012 -0700
Title: Xilinx: ARM: GPIO: updated driver names for cleanup

From: Xilinx
Co-authored-by: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
Co-authored-by: Swapna Manupati <swapna.manupati@xilinx.com>
Co-authored-by: Venkatesh Yadav Abbarapu <venkatesh.abbarapu@xilinx.com>
Co-authored-by: Nava kishore Manne <nava.manne@xilinx.com>
Co-authored-by: Maulik Jodhani <maulik.jodhani@xilinx.com>
Co-authored-by: Iban Rodriguez <irodriguez@cemitec.com>
Co-authored-by: Topi Kuutela <topi.kuutela@gmail.com>
Co-authored-by: Michal Simek <michal.simek@xilinx.com>
Co-authored-by: Naveen Mamindlapalli <naveenm@xilinx.com>
Co-authored-by: John Linn <john.linn@xilinx.com>
Signed-off-by: Alexander Hedges <ahedges@ethz.ch>

---

A bit of explanation:

While linux-xlnx has has never been merged into linux, the opposite happened
quite often. So deconstructing the changes since 2011 and applying them onto
4.17 one-by-one in a way that does not break the builds and where the result
is the same as the current head of linux-xlnx + the patch for
irq_set_lockdep_class seems like a nearly impossible task to me.

Note that this is my first email to the kernel mailing list, so if I'm doing
something fundamentally wrong, please tell me. Also, I don't know how
changes like these are usually handled, if there is a better way to have the
newest version of gpio-xilinx in mainline linux, let me know.

I'm not affiliated with Xilinx in any way.

 drivers/gpio/gpio-xilinx.c | 670 +++++++++++++++++++++++++++++--------
 1 file changed, 529 insertions(+), 141 deletions(-)

Comments

Michal Simek July 20, 2018, 6:26 a.m. UTC | #1
On 19.7.2018 17:22, Hedges  Alexander wrote:
> This updates gpio-xilinx to include all the commits which are only present in
> the official Xilinx Linux repository (github.com/Xilinx/linux-xlnx). The last
> common ancestor is 64842aad5ec5, after that, linux-xlnx has not been merged into
> mainline linux.
> 
> The only thing added in the merge is the second lock_class_key which is needed
> by irq_set_lockdep_class after the signature change in 39c3fd58952d.
> 
> The changes to gpio-xilinx.c from the following commits are included:
> 
> commit 184f4682479b34d279d8fec236126b7e2f6a94ce
> Author: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
> Date: Thu May 3 14:35:46 2018 +0530
> Title: gpio: xilinx: Add support for no initialisation at probe
> 
> commit dbf204e7a104cd1bb5eeaec945811c986bed4840
> Author: Swapna Manupati <swapna.manupati@xilinx.com>
> Date: Wed Mar 7 17:03:19 2018 +0530
> Title: gpio: xilinx: Add reset support
> 
> commit 3bbc2fda8018d067910eac153c1f30caa509828a
> Author: Venkatesh Yadav Abbarapu <venkatesh.abbarapu@xilinx.com>
> Date: Wed Jan 24 18:20:19 2018 +0530
> Title: gpio: xilinx: defer the probe if clock is not found
> 
> commit 1bd0377e19ba07436d1430f444f701c97e9cefd1
> Author: Michal Simek <michal.simek@xilinx.com>
> Date: Mon Oct 16 10:30:20 2017 +0200
> Title: gpio: Fix typo in gpio driver
> 
> commit 3da7287a068080a6e100ddfef449ab94bebd429d
> Author: Nava kishore Manne <nava.manne@xilinx.com>
> Date: Wed Apr 19 17:41:20 2017 +0530
> Title: gpio: gpio-xilinx: Fix warnings in the driver
> 
> commit 24132f85de16dd69948ed1fd1cd6bfef3802e9bd
> Author: Nava kishore Manne <nava.manne@xilinx.com>
> Date: Wed Apr 19 14:54:20 2017 +0530
> Title: gpio: gpio-xilinx.c: Fix kernel doc warnings
> 
> commit 30b6bc689ae71b657f5e1f7fb86468b9d8edcfc2
> Author: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
> Date: Thu Apr 6 16:12:00 2017 +0530
> Title: gpio: xilinx: Fix the NULL pointer access
> 
> commit e469c51aeca082452d0d34897f713906f4d3599a
> Author: Michal Simek <michal.simek@xilinx.com>
> Date: Tue Feb 14 16:16:56 2017 +0100
> Title: gpio: Add simple remove and exit functions
> 
> commit 34b6b71b142476b9e377f2e21b087eb8434176cd
> Author: Maulik Jodhani <maulik.jodhani@xilinx.com>
> Date: Fri Feb 10 06:31:30 2017 -0800
> Title: gpio: xilinx: Add clock adaptation support
> 
> commit c8105d8066c1b9ba5f8e160c213c7605ba6dffab
> Author: Michal Simek <michal.simek@xilinx.com>
> Date: Thu Jul 28 14:59:50 2016 +0200
> Title: gpio: xilinx: Use readl/writel for ARM64
> 
> commit 1c9c40cbcbd896a6ee35e46560b5c3e99718c620
> Author: Iban Rodriguez <irodriguez@cemitec.com>
> Date: Mon Jun 13 12:53:39 2016 +0200
> Title: gpio: xilinx: Always use own xlate function
> 
> commit 63bcc8b82965b185e632170dca04185539d970f9
> Author: Iban Rodriguez <irodriguez@cemitec.com>
> Date: Fri May 13 12:11:46 2016 +0200
> Title: gpio: xilinx: Add support to set multiple GPIO at once
> 
> commit 426ad456b920a9b26394b1f973c100cf3984b954
> Author: Topi Kuutela <topi.kuutela@gmail.com>
> Date: Wed May 11 14:53:41 2016 +0300
> Title: gpio: xilinx: Fix irq-handler prototype
> 
> commit 4fdaf2960d8ccecb504d312d2f7b2d532941a8dd
> Author: Michal Simek <michal.simek@xilinx.com>
> Date: Wed Jun 17 06:44:12 2015 +0200
> Title: xilinx: Remove owner field from platform_driver
> 
> commit 616ac116ab2dcfe603c67ea3c8f70d5889aa6fc9
> Author: Michal Simek <michal.simek@xilinx.com>
> Date: Tue Sep 3 17:06:19 2013 +0200
> Title: gpio: xilinx: Use platform_driver
> 
> commit 5f35773def8d97fcc48c587f54439ca12fc6a601
> Author: Michal Simek <michal.simek@xilinx.com>
> Date: Tue Sep 3 16:43:47 2013 +0200
> Title: gpio: xilinx: Fix minor coding style issue.
> 
> commit 32161b344f3eb80f59bd99e9ca215a93b40b929a
> Author: Michal Simek <michal.simek@xilinx.com>
> Date: Tue Sep 3 16:22:12 2013 +0200
> Title: gpio: xilinx: Fix type for irq_base
> 
> commit 9a5d02ee0f4fc8f7ff461e8955eaed19e542bed8
> Author: Michal Simek <michal.simek@xilinx.com>
> Date: Tue Aug 6 13:59:47 2013 +0200
> Title: GPIO: xilinx: Do not use xgpiops but use only xgpio
> 
> commit 7c58460d5bb43758d879f391e85b7b857160d488
> Author: Michal Simek <michal.simek@xilinx.com>
> Date: Tue Aug 6 13:16:36 2013 +0200
> Title: GPIO: xilinx: Do not allocate interrupts for IPs without IRQ support
> 
> commit 796ae5e3e4ae5f550e0ba01ade34604c83b08cfd
> Author: Michal Simek <michal.simek@xilinx.com>
> Date: Fri Jul 19 14:34:36 2013 +0200
> Title: GPIO: xilinx: Add irq support to the driver
> 
> commit 8fd1942dec9edd0175dc6f242a9ab8c663c07fb9
> Author: Michal Simek <michal.simek@xilinx.com>
> Date: Fri Jul 19 14:31:15 2013 +0200
> Title: GPIO: xilinx: Fix kernel-doc mainline
> 
> commit 6ecc02b189fb0147dd3221ff347f42901c575927
> Author: Michal Simek <michal.simek@xilinx.com>
> Date: Wed Jul 17 15:22:20 2013 +0200
> Title: GPIO: xilinx: Use standard coding style for macros
> 
> commit 324c11445a487744dd2e4c286b63e83fc18eae54
> Author: Michal Simek <michal.simek@xilinx.com>
> Date: Tue Nov 27 15:40:47 2012 +0100
> Title: gpio: gpio-xilinx: Remove CONFIG_OF conditionals
> 
> commit fb2379e7035e9855543e49637828aca4b7e72f58
> Author: Michal Simek <monstr@monstr.eu>
> Date: Fri Oct 19 10:49:31 2012 +0200
> Title: of: gpio: Add support for dual xilinx GPIO
> 
> commit 5a711f8ecdc69bdf6a23494a503dd6f3c39381ce
> Author: Naveen Mamindlapalli <naveenm@xilinx.com>
> Date: Fri Aug 31 20:11:29 2012 +0530
> Title: Xilinx: Microblaze: GPIO: Fixed compilation error.
> 
> commit e9a98626baf3b31fa6a699576d8d089c5df10f35
> Author: John Linn <john.linn@xilinx.com>
> Date: Fri Jun 29 11:27:45 2012 -0700
> Title: Xilinx: ARM: GPIO: updated driver names for cleanup
> 
> From: Xilinx
> Co-authored-by: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
> Co-authored-by: Swapna Manupati <swapna.manupati@xilinx.com>
> Co-authored-by: Venkatesh Yadav Abbarapu <venkatesh.abbarapu@xilinx.com>
> Co-authored-by: Nava kishore Manne <nava.manne@xilinx.com>
> Co-authored-by: Maulik Jodhani <maulik.jodhani@xilinx.com>
> Co-authored-by: Iban Rodriguez <irodriguez@cemitec.com>
> Co-authored-by: Topi Kuutela <topi.kuutela@gmail.com>
> Co-authored-by: Michal Simek <michal.simek@xilinx.com>
> Co-authored-by: Naveen Mamindlapalli <naveenm@xilinx.com>
> Co-authored-by: John Linn <john.linn@xilinx.com>
> Signed-off-by: Alexander Hedges <ahedges@ethz.ch>
> 
> ---
> 
> A bit of explanation:
> 
> While linux-xlnx has has never been merged into linux, the opposite happened
> quite often. So deconstructing the changes since 2011 and applying them onto
> 4.17 one-by-one in a way that does not break the builds and where the result
> is the same as the current head of linux-xlnx + the patch for
> irq_set_lockdep_class seems like a nearly impossible task to me.
> 
> Note that this is my first email to the kernel mailing list, so if I'm doing
> something fundamentally wrong, please tell me. Also, I don't know how
> changes like these are usually handled, if there is a better way to have the
> newest version of gpio-xilinx in mainline linux, let me know.
> 
> I'm not affiliated with Xilinx in any way.

NACK.
That's not the way to go. You can cherry-pick that patches with keeping
origin author name and send them out but you can't squash all stuff
together. Please look at submitting patches doc in documentation for the
rules you need to follow.

Thanks,
Michal
--
To unsubscribe from this list: send the line "unsubscribe linux-gpio" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox series

Patch

diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index e8ec0e33a0a9..ec017c1640b2 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -17,20 +17,32 @@ 
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
+#include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/of_gpio.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
 #include <linux/gpio.h>
 #include <linux/slab.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
 
 /* Register Offset Definitions */
-#define XGPIO_DATA_OFFSET   (0x0)	/* Data register  */
-#define XGPIO_TRI_OFFSET    (0x4)	/* I/O direction register  */
+#define XGPIO_DATA_OFFSET	0x0 /* Data register */
+#define XGPIO_TRI_OFFSET	0x4 /* I/O direction register */
+#define XGPIO_GIER_OFFSET	0x11c /* Global Interrupt Enable */
+#define XGPIO_GIER_IE		BIT(31)
+
+#define XGPIO_IPISR_OFFSET	0x120 /* IP Interrupt Status */
+#define XGPIO_IPIER_OFFSET	0x128 /* IP Interrupt Enable */
 
 #define XGPIO_CHANNEL_OFFSET	0x8
 
 /* Read/Write access to the GPIO registers */
-#if defined(CONFIG_ARCH_ZYNQ) || defined(CONFIG_X86)
+#if defined(CONFIG_ARCH_ZYNQ) || defined(CONFIG_ARM64)
 # define xgpio_readreg(offset)		readl(offset)
 # define xgpio_writereg(offset, val)	writel(val, offset)
 #else
@@ -41,43 +53,29 @@ 
 /**
  * struct xgpio_instance - Stores information about GPIO device
  * @mmchip: OF GPIO chip for memory mapped banks
- * @gpio_width: GPIO width for every channel
  * @gpio_state: GPIO state shadow register
  * @gpio_dir: GPIO direction shadow register
+ * @offset: GPIO channel offset
+ * @irq_base: GPIO channel irq base address
+ * @irq_enable: GPIO irq enable/disable bitfield
+ * @no_init: No intitialisation at probe
  * @gpio_lock: Lock used for synchronization
+ * @irq_domain: irq_domain of the controller
+ * @clk: clock resource for this driver
  */
 struct xgpio_instance {
 	struct of_mm_gpio_chip mmchip;
-	unsigned int gpio_width[2];
-	u32 gpio_state[2];
-	u32 gpio_dir[2];
-	spinlock_t gpio_lock[2];
+	u32 gpio_state;
+	u32 gpio_dir;
+	u32 offset;
+	int irq_base;
+	u32 irq_enable;
+	bool no_init;
+	spinlock_t gpio_lock;
+	struct irq_domain *irq_domain;
+	struct clk *clk;
 };
 
-static inline int xgpio_index(struct xgpio_instance *chip, int gpio)
-{
-	if (gpio >= chip->gpio_width[0])
-		return 1;
-
-	return 0;
-}
-
-static inline int xgpio_regoffset(struct xgpio_instance *chip, int gpio)
-{
-	if (xgpio_index(chip, gpio))
-		return XGPIO_CHANNEL_OFFSET;
-
-	return 0;
-}
-
-static inline int xgpio_offset(struct xgpio_instance *chip, int gpio)
-{
-	if (xgpio_index(chip, gpio))
-		return gpio - chip->gpio_width[0];
-
-	return gpio;
-}
-
 /**
  * xgpio_get - Read the specified signal of the GPIO device.
  * @gc:     Pointer to gpio_chip device structure.
@@ -92,13 +90,12 @@  static inline int xgpio_offset(struct xgpio_instance *chip, int gpio)
 static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
 {
 	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
-	struct xgpio_instance *chip = gpiochip_get_data(gc);
-	u32 val;
+	struct xgpio_instance *chip =
+	    container_of(mm_gc, struct xgpio_instance, mmchip);
 
-	val = xgpio_readreg(mm_gc->regs + XGPIO_DATA_OFFSET +
-			    xgpio_regoffset(chip, gpio));
+	void __iomem *regs = mm_gc->regs + chip->offset;
 
-	return !!(val & BIT(xgpio_offset(chip, gpio)));
+	return !!(xgpio_readreg(regs + XGPIO_DATA_OFFSET) & BIT(gpio));
 }
 
 /**
@@ -114,22 +111,22 @@  static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
 {
 	unsigned long flags;
 	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
-	struct xgpio_instance *chip = gpiochip_get_data(gc);
-	int index =  xgpio_index(chip, gpio);
-	int offset =  xgpio_offset(chip, gpio);
+	struct xgpio_instance *chip =
+	    container_of(mm_gc, struct xgpio_instance, mmchip);
+	void __iomem *regs = mm_gc->regs;
 
-	spin_lock_irqsave(&chip->gpio_lock[index], flags);
+	spin_lock_irqsave(&chip->gpio_lock, flags);
 
 	/* Write to GPIO signal and set its direction to output */
 	if (val)
-		chip->gpio_state[index] |= BIT(offset);
+		chip->gpio_state |= BIT(gpio);
 	else
-		chip->gpio_state[index] &= ~BIT(offset);
+		chip->gpio_state &= ~BIT(gpio);
 
-	xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
-		       xgpio_regoffset(chip, gpio), chip->gpio_state[index]);
+	xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET,
+							 chip->gpio_state);
 
-	spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
+	spin_unlock_irqrestore(&chip->gpio_lock, flags);
 }
 
 /**
@@ -146,37 +143,29 @@  static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
 {
 	unsigned long flags;
 	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
-	struct xgpio_instance *chip = gpiochip_get_data(gc);
-	int index = xgpio_index(chip, 0);
-	int offset, i;
+	struct xgpio_instance *chip =
+	    container_of(mm_gc, struct xgpio_instance, mmchip);
+	void __iomem *regs = mm_gc->regs;
+	int i;
 
-	spin_lock_irqsave(&chip->gpio_lock[index], flags);
+	spin_lock_irqsave(&chip->gpio_lock, flags);
 
 	/* Write to GPIO signals */
 	for (i = 0; i < gc->ngpio; i++) {
 		if (*mask == 0)
 			break;
-		if (index !=  xgpio_index(chip, i)) {
-			xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
-				       xgpio_regoffset(chip, i),
-				       chip->gpio_state[index]);
-			spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
-			index =  xgpio_index(chip, i);
-			spin_lock_irqsave(&chip->gpio_lock[index], flags);
-		}
 		if (__test_and_clear_bit(i, mask)) {
-			offset =  xgpio_offset(chip, i);
 			if (test_bit(i, bits))
-				chip->gpio_state[index] |= BIT(offset);
+				chip->gpio_state |= BIT(i);
 			else
-				chip->gpio_state[index] &= ~BIT(offset);
+				chip->gpio_state &= ~BIT(i);
 		}
 	}
 
-	xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
-		       xgpio_regoffset(chip, i), chip->gpio_state[index]);
+	xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET,
+		       chip->gpio_state);
 
-	spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
+	spin_unlock_irqrestore(&chip->gpio_lock, flags);
 }
 
 /**
@@ -184,6 +173,8 @@  static void xgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
  * @gc:     Pointer to gpio_chip device structure.
  * @gpio:   GPIO signal number.
  *
+ * This function sets the direction of specified GPIO signal as input.
+ *
  * Return:
  * 0 - if direction of GPIO signals is set as input
  * otherwise it returns negative error value.
@@ -192,18 +183,17 @@  static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
 {
 	unsigned long flags;
 	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
-	struct xgpio_instance *chip = gpiochip_get_data(gc);
-	int index =  xgpio_index(chip, gpio);
-	int offset =  xgpio_offset(chip, gpio);
+	struct xgpio_instance *chip =
+	    container_of(mm_gc, struct xgpio_instance, mmchip);
+	void __iomem *regs = mm_gc->regs;
 
-	spin_lock_irqsave(&chip->gpio_lock[index], flags);
+	spin_lock_irqsave(&chip->gpio_lock, flags);
 
 	/* Set the GPIO bit in shadow register and set direction as input */
-	chip->gpio_dir[index] |= BIT(offset);
-	xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET +
-		       xgpio_regoffset(chip, gpio), chip->gpio_dir[index]);
+	chip->gpio_dir |= BIT(gpio);
+	xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir);
 
-	spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
+	spin_unlock_irqrestore(&chip->gpio_lock, flags);
 
 	return 0;
 }
@@ -224,26 +214,25 @@  static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
 {
 	unsigned long flags;
 	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
-	struct xgpio_instance *chip = gpiochip_get_data(gc);
-	int index =  xgpio_index(chip, gpio);
-	int offset =  xgpio_offset(chip, gpio);
+	struct xgpio_instance *chip =
+	    container_of(mm_gc, struct xgpio_instance, mmchip);
+	void __iomem *regs = mm_gc->regs;
 
-	spin_lock_irqsave(&chip->gpio_lock[index], flags);
+	spin_lock_irqsave(&chip->gpio_lock, flags);
 
 	/* Write state of GPIO signal */
 	if (val)
-		chip->gpio_state[index] |= BIT(offset);
+		chip->gpio_state |= BIT(gpio);
 	else
-		chip->gpio_state[index] &= ~BIT(offset);
-	xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
-			xgpio_regoffset(chip, gpio), chip->gpio_state[index]);
+		chip->gpio_state &= ~BIT(gpio);
+	xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET,
+		       chip->gpio_state);
 
 	/* Clear the GPIO bit in shadow register and set direction as output */
-	chip->gpio_dir[index] &= ~BIT(offset);
-	xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET +
-			xgpio_regoffset(chip, gpio), chip->gpio_dir[index]);
+	chip->gpio_dir &= ~BIT(gpio);
+	xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir);
 
-	spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
+	spin_unlock_irqrestore(&chip->gpio_lock, flags);
 
 	return 0;
 }
@@ -255,20 +244,320 @@  static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
 static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
 {
 	struct xgpio_instance *chip =
-		container_of(mm_gc, struct xgpio_instance, mmchip);
+	    container_of(mm_gc, struct xgpio_instance, mmchip);
+	if (chip->no_init) {
+		chip->gpio_state = xgpio_readreg(mm_gc->regs +
+						 XGPIO_DATA_OFFSET);
+		chip->gpio_dir = xgpio_readreg(mm_gc->regs + XGPIO_TRI_OFFSET);
+	} else {
+		xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_DATA_OFFSET,
+			       chip->gpio_state);
+		xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_TRI_OFFSET,
+			       chip->gpio_dir);
+	}
+}
+
+/**
+ * xgpio_xlate - Translate gpio_spec to the GPIO number and flags
+ * @gc: Pointer to gpio_chip device structure.
+ * @gpiospec:  gpio specifier as found in the device tree
+ * @flags: A flags pointer based on binding
+ *
+ * Return:
+ * irq number otherwise -EINVAL
+ */
+static int xgpio_xlate(struct gpio_chip *gc,
+		       const struct of_phandle_args *gpiospec, u32 *flags)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+	struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance,
+						   mmchip);
+	if (gc->of_gpio_n_cells == 3 && flags)
+		*flags = gpiospec->args[2];
+
+	if (gpiospec->args[1] == chip->offset)
+		return gpiospec->args[0];
+
+	return -EINVAL;
+}
+
+/**
+ * xgpio_irq_mask - Write the specified signal of the GPIO device.
+ * @irq_data: per irq and chip data passed down to chip functions
+ */
+static void xgpio_irq_mask(struct irq_data *irq_data)
+{
+	unsigned long flags;
+	struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data);
+	struct of_mm_gpio_chip *mm_gc = &chip->mmchip;
+	u32 offset = irq_data->irq - chip->irq_base;
+	u32 temp;
+
+	pr_debug("%s: Disable %d irq, irq_enable_mask 0x%x\n",
+		__func__, offset, chip->irq_enable);
+
+	spin_lock_irqsave(&chip->gpio_lock, flags);
+
+	chip->irq_enable &= ~BIT(offset);
+
+	if (!chip->irq_enable) {
+		/* Enable per channel interrupt */
+		temp = xgpio_readreg(mm_gc->regs + XGPIO_IPIER_OFFSET);
+		temp &= chip->offset / XGPIO_CHANNEL_OFFSET + 1;
+		xgpio_writereg(mm_gc->regs + XGPIO_IPIER_OFFSET, temp);
+
+		/* Disable global interrupt if channel interrupts are unused */
+		temp = xgpio_readreg(mm_gc->regs + XGPIO_IPIER_OFFSET);
+		if (!temp)
+			xgpio_writereg(mm_gc->regs + XGPIO_GIER_OFFSET,
+				       ~XGPIO_GIER_IE);
+
+	}
+	spin_unlock_irqrestore(&chip->gpio_lock, flags);
+}
+
+/**
+ * xgpio_irq_unmask - Write the specified signal of the GPIO device.
+ * @irq_data: per irq and chip data passed down to chip functions
+ */
+static void xgpio_irq_unmask(struct irq_data *irq_data)
+{
+	unsigned long flags;
+	struct xgpio_instance *chip = irq_data_get_irq_chip_data(irq_data);
+	struct of_mm_gpio_chip *mm_gc = &chip->mmchip;
+	u32 offset = irq_data->irq - chip->irq_base;
+	u32 temp;
+
+	pr_debug("%s: Enable %d irq, irq_enable_mask 0x%x\n",
+		__func__, offset, chip->irq_enable);
+
+	/* Setup pin as input */
+	xgpio_dir_in(&mm_gc->gc, offset);
+
+	spin_lock_irqsave(&chip->gpio_lock, flags);
+
+	chip->irq_enable |= BIT(offset);
+
+	if (chip->irq_enable) {
+
+		/* Enable per channel interrupt */
+		temp = xgpio_readreg(mm_gc->regs + XGPIO_IPIER_OFFSET);
+		temp |= chip->offset / XGPIO_CHANNEL_OFFSET + 1;
+		xgpio_writereg(mm_gc->regs + XGPIO_IPIER_OFFSET, temp);
+
+		/* Enable global interrupts */
+		xgpio_writereg(mm_gc->regs + XGPIO_GIER_OFFSET, XGPIO_GIER_IE);
+	}
+
+	spin_unlock_irqrestore(&chip->gpio_lock, flags);
+}
+
+/**
+ * xgpio_set_irq_type - Write the specified signal of the GPIO device.
+ * @irq_data: Per irq and chip data passed down to chip functions
+ * @type: Interrupt type that is to be set for the gpio pin
+ *
+ * Return:
+ * 0 if interrupt type is supported otherwise otherwise -EINVAL
+ */
+static int xgpio_set_irq_type(struct irq_data *irq_data, unsigned int type)
+{
+	/* Only rising edge case is supported now */
+	if (type == IRQ_TYPE_EDGE_RISING)
+		return 0;
+
+	return -EINVAL;
+}
+
+/* irq chip descriptor */
+static struct irq_chip xgpio_irqchip = {
+	.name		= "xgpio",
+	.irq_mask	= xgpio_irq_mask,
+	.irq_unmask	= xgpio_irq_unmask,
+	.irq_set_type	= xgpio_set_irq_type,
+};
+
+/**
+ * xgpio_to_irq - Find out gpio to Linux irq mapping
+ * @gc: Pointer to gpio_chip device structure.
+ * @offset: Gpio pin offset
+ *
+ * Return:
+ * irq number otherwise -EINVAL
+ */
+static int xgpio_to_irq(struct gpio_chip *gc, unsigned int offset)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+	struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance,
+						   mmchip);
+
+	return irq_find_mapping(chip->irq_domain, offset);
+}
+
+/**
+ * xgpio_irqhandler - Gpio interrupt service routine
+ * @desc: Pointer to interrupt description
+ */
+static void xgpio_irqhandler(struct irq_desc *desc)
+{
+	unsigned int irq = irq_desc_get_irq(desc);
+
+	struct xgpio_instance *chip = (struct xgpio_instance *)
+						irq_get_handler_data(irq);
+	struct of_mm_gpio_chip *mm_gc = &chip->mmchip;
+	struct irq_chip *irqchip = irq_desc_get_chip(desc);
+	int offset;
+	unsigned long val;
+
+	chained_irq_enter(irqchip, desc);
+
+	val = xgpio_readreg(mm_gc->regs + chip->offset);
+	/* Only rising edge is supported */
+	val &= chip->irq_enable;
+
+	for_each_set_bit(offset, &val, chip->mmchip.gc.ngpio) {
+		generic_handle_irq(chip->irq_base + offset);
+	}
+
+	xgpio_writereg(mm_gc->regs + XGPIO_IPISR_OFFSET,
+		       chip->offset / XGPIO_CHANNEL_OFFSET + 1);
+
+	chained_irq_exit(irqchip, desc);
+}
+
+static struct lock_class_key gpio_lock_class;
+static struct lock_class_key gpio_request_class;
+
+/**
+ * xgpio_irq_setup - Allocate irq for gpio and setup appropriate functions
+ * @np: Device node of the GPIO chip
+ * @chip: Pointer to private gpio channel structure
+ *
+ * Return:
+ * 0 if success, otherwise -1
+ */
+static int xgpio_irq_setup(struct device_node *np, struct xgpio_instance *chip)
+{
+	u32 pin_num;
+	struct resource res;
+
+	int ret = of_irq_to_resource(np, 0, &res);
+
+	if (!ret) {
+		pr_info("GPIO IRQ not connected\n");
+		return 0;
+	}
+
+	chip->mmchip.gc.to_irq = xgpio_to_irq;
+
+	chip->irq_base = irq_alloc_descs(-1, 0, chip->mmchip.gc.ngpio, 0);
+	if (chip->irq_base < 0) {
+		pr_err("Couldn't allocate IRQ numbers\n");
+		return -1;
+	}
+	chip->irq_domain = irq_domain_add_legacy(np, chip->mmchip.gc.ngpio,
+						 chip->irq_base, 0,
+						 &irq_domain_simple_ops, NULL);
+
+	/*
+	 * set the irq chip, handler and irq chip data for callbacks for
+	 * each pin
+	 */
+	for (pin_num = 0; pin_num < chip->mmchip.gc.ngpio; pin_num++) {
+		u32 gpio_irq = irq_find_mapping(chip->irq_domain, pin_num);
+
+		irq_set_lockdep_class(gpio_irq, &gpio_lock_class, &gpio_request_class);
+		pr_debug("IRQ Base: %d, Pin %d = IRQ %d\n",
+			chip->irq_base,	pin_num, gpio_irq);
+		irq_set_chip_and_handler(gpio_irq, &xgpio_irqchip,
+					 handle_simple_irq);
+		irq_set_chip_data(gpio_irq, (void *)chip);
+	}
+	irq_set_handler_data(res.start, (void *)chip);
+	irq_set_chained_handler(res.start, xgpio_irqhandler);
+
+	return 0;
+}
+
+static int xgpio_request(struct gpio_chip *chip, unsigned int offset)
+{
+	int ret = pm_runtime_get_sync(chip->parent);
 
-	xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET,	chip->gpio_state[0]);
-	xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir[0]);
+	/*
+	 * If the device is already active pm_runtime_get() will return 1 on
+	 * success, but gpio_request still needs to return 0.
+	 */
+	return ret < 0 ? ret : 0;
+}
 
-	if (!chip->gpio_width[1])
-		return;
+static void xgpio_free(struct gpio_chip *chip, unsigned int offset)
+{
+	pm_runtime_put(chip->parent);
+}
 
-	xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + XGPIO_CHANNEL_OFFSET,
-		       chip->gpio_state[1]);
-	xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + XGPIO_CHANNEL_OFFSET,
-		       chip->gpio_dir[1]);
+static int __maybe_unused xgpio_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	int irq;
+	struct irq_data *data;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq <= 0) {
+		dev_dbg(dev, "failed to get IRQ\n");
+		return 0;
+	}
+
+	data = irq_get_irq_data(irq);
+	if (!irqd_is_wakeup_set(data))
+		return pm_runtime_force_suspend(dev);
+
+	return 0;
 }
 
+static int __maybe_unused xgpio_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	int irq;
+	struct irq_data *data;
+
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq <= 0) {
+		dev_dbg(dev, "failed to get IRQ\n");
+		return 0;
+	}
+
+	data = irq_get_irq_data(irq);
+	if (!irqd_is_wakeup_set(data))
+		return pm_runtime_force_resume(dev);
+
+	return 0;
+}
+
+static int __maybe_unused xgpio_runtime_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct xgpio_instance *gpio = platform_get_drvdata(pdev);
+
+	clk_disable(gpio->clk);
+
+	return 0;
+}
+
+static int __maybe_unused xgpio_runtime_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct xgpio_instance *gpio = platform_get_drvdata(pdev);
+
+	return clk_enable(gpio->clk);
+}
+
+static const struct dev_pm_ops xgpio_dev_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(xgpio_suspend, xgpio_resume)
+	SET_RUNTIME_PM_OPS(xgpio_runtime_suspend,
+			xgpio_runtime_resume, NULL)
+};
+
 /**
  * xgpio_remove - Remove method for the GPIO device.
  * @pdev: pointer to the platform device
@@ -288,112 +577,211 @@  static int xgpio_remove(struct platform_device *pdev)
 
 /**
  * xgpio_of_probe - Probe method for the GPIO device.
- * @pdev: pointer to the platform device
+ * @pdev:       platform device instance
+ *
+ * This function probes the GPIO device in the device tree. It initializes the
+ * driver data structure.
  *
  * Return:
  * It returns 0, if the driver is bound to the GPIO device, or
  * a negative value if there is an error.
  */
-static int xgpio_probe(struct platform_device *pdev)
+static int xgpio_of_probe(struct platform_device *pdev)
 {
+	struct device_node *np = pdev->dev.of_node;
 	struct xgpio_instance *chip;
 	int status = 0;
-	struct device_node *np = pdev->dev.of_node;
-	u32 is_dual;
+	const u32 *tree_info;
+	u32 ngpio;
+	u32 cells = 2;
 
 	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
 	if (!chip)
 		return -ENOMEM;
 
-	platform_set_drvdata(pdev, chip);
-
 	/* Update GPIO state shadow register with default value */
-	of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state[0]);
+	of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state);
+
+	/* By default, all pins are inputs */
+	chip->gpio_dir = 0xFFFFFFFF;
 
 	/* Update GPIO direction shadow register with default value */
-	if (of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir[0]))
-		chip->gpio_dir[0] = 0xFFFFFFFF;
+	of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir);
+
+	chip->no_init = of_property_read_bool(np, "xlnx,no-init");
+
+	/* Update cells with gpio-cells value */
+	of_property_read_u32(np, "#gpio-cells", &cells);
 
 	/*
 	 * Check device node and parent device node for device width
 	 * and assume default width of 32
 	 */
-	if (of_property_read_u32(np, "xlnx,gpio-width", &chip->gpio_width[0]))
-		chip->gpio_width[0] = 32;
-
-	spin_lock_init(&chip->gpio_lock[0]);
-
-	if (of_property_read_u32(np, "xlnx,is-dual", &is_dual))
-		is_dual = 0;
-
-	if (is_dual) {
-		/* Update GPIO state shadow register with default value */
-		of_property_read_u32(np, "xlnx,dout-default-2",
-				     &chip->gpio_state[1]);
-
-		/* Update GPIO direction shadow register with default value */
-		if (of_property_read_u32(np, "xlnx,tri-default-2",
-					 &chip->gpio_dir[1]))
-			chip->gpio_dir[1] = 0xFFFFFFFF;
-
-		/*
-		 * Check device node and parent device node for device width
-		 * and assume default width of 32
-		 */
-		if (of_property_read_u32(np, "xlnx,gpio2-width",
-					 &chip->gpio_width[1]))
-			chip->gpio_width[1] = 32;
+	if (of_property_read_u32(np, "xlnx,gpio-width", &ngpio))
+		ngpio = 32;
+	chip->mmchip.gc.ngpio = (u16)ngpio;
 
-		spin_lock_init(&chip->gpio_lock[1]);
-	}
+	spin_lock_init(&chip->gpio_lock);
 
-	chip->mmchip.gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1];
 	chip->mmchip.gc.parent = &pdev->dev;
+	chip->mmchip.gc.owner = THIS_MODULE;
+	chip->mmchip.gc.of_xlate = xgpio_xlate;
+	chip->mmchip.gc.of_gpio_n_cells = cells;
 	chip->mmchip.gc.direction_input = xgpio_dir_in;
 	chip->mmchip.gc.direction_output = xgpio_dir_out;
 	chip->mmchip.gc.get = xgpio_get;
 	chip->mmchip.gc.set = xgpio_set;
+	chip->mmchip.gc.request = xgpio_request;
+	chip->mmchip.gc.free = xgpio_free;
 	chip->mmchip.gc.set_multiple = xgpio_set_multiple;
 
 	chip->mmchip.save_regs = xgpio_save_regs;
 
+	platform_set_drvdata(pdev, chip);
+
+	chip->clk = devm_clk_get(&pdev->dev, "s_axi_aclk");
+	if (IS_ERR(chip->clk)) {
+		if ((PTR_ERR(chip->clk) != -ENOENT) ||
+				(PTR_ERR(chip->clk) != -EPROBE_DEFER)) {
+			dev_err(&pdev->dev, "Input clock not found\n");
+			return PTR_ERR(chip->clk);
+		}
+
+		/*
+		 * Clock framework support is optional, continue on
+		 * anyways if we don't find a matching clock.
+		 */
+		chip->clk = NULL;
+	}
+
+	status = clk_prepare_enable(chip->clk);
+	if (status < 0) {
+		dev_err(&pdev->dev, "Failed to prepare clk\n");
+		return status;
+	}
+
+	pm_runtime_enable(&pdev->dev);
+	status = pm_runtime_get_sync(&pdev->dev);
+	if (status < 0)
+		goto err_unprepare_clk;
+
 	/* Call the OF gpio helper to setup and register the GPIO device */
-	status = of_mm_gpiochip_add_data(np, &chip->mmchip, chip);
+	status = of_mm_gpiochip_add(np, &chip->mmchip);
 	if (status) {
 		pr_err("%pOF: error in probe function with status %d\n",
 		       np, status);
-		return status;
+		goto err_pm_put;
 	}
 
+	status = xgpio_irq_setup(np, chip);
+	if (status) {
+		pr_err("%s: GPIO IRQ initialization failed %d\n",
+		       np->full_name, status);
+		goto err_pm_put;
+	}
+
+	pr_info("XGpio: %s: registered, base is %d\n", np->full_name,
+							chip->mmchip.gc.base);
+
+	tree_info = of_get_property(np, "xlnx,is-dual", NULL);
+	if (tree_info && be32_to_cpup(tree_info)) {
+		chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+		if (!chip)
+			return -ENOMEM;
+
+		/* Add dual channel offset */
+		chip->offset = XGPIO_CHANNEL_OFFSET;
+
+		/* Update GPIO state shadow register with default value */
+		of_property_read_u32(np, "xlnx,dout-default-2",
+				     &chip->gpio_state);
+
+		/* By default, all pins are inputs */
+		chip->gpio_dir = 0xFFFFFFFF;
+
+		/* Update GPIO direction shadow register with default value */
+		of_property_read_u32(np, "xlnx,tri-default-2", &chip->gpio_dir);
+
+		/*
+		 * Check device node and parent device node for device width
+		 * and assume default width of 32
+		 */
+		if (of_property_read_u32(np, "xlnx,gpio2-width", &ngpio))
+			ngpio = 32;
+		chip->mmchip.gc.ngpio = (u16)ngpio;
+
+		spin_lock_init(&chip->gpio_lock);
+
+		chip->mmchip.gc.parent = &pdev->dev;
+		chip->mmchip.gc.owner = THIS_MODULE;
+		chip->mmchip.gc.of_xlate = xgpio_xlate;
+		chip->mmchip.gc.of_gpio_n_cells = cells;
+		chip->mmchip.gc.direction_input = xgpio_dir_in;
+		chip->mmchip.gc.direction_output = xgpio_dir_out;
+		chip->mmchip.gc.get = xgpio_get;
+		chip->mmchip.gc.set = xgpio_set;
+		chip->mmchip.gc.request = xgpio_request;
+		chip->mmchip.gc.free = xgpio_free;
+		chip->mmchip.gc.set_multiple = xgpio_set_multiple;
+
+		chip->mmchip.save_regs = xgpio_save_regs;
+
+		status = xgpio_irq_setup(np, chip);
+		if (status) {
+			pr_err("%s: GPIO IRQ initialization failed %d\n",
+			      np->full_name, status);
+			goto err_pm_put;
+		}
+
+		/* Call the OF gpio helper to setup and register the GPIO dev */
+		status = of_mm_gpiochip_add(np, &chip->mmchip);
+		if (status) {
+			pr_err("%s: error in probe function with status %d\n",
+			       np->full_name, status);
+			goto err_pm_put;
+		}
+		pr_info("XGpio: %s: dual channel registered, base is %d\n",
+					np->full_name, chip->mmchip.gc.base);
+	}
+
+	pm_runtime_put(&pdev->dev);
 	return 0;
+
+err_pm_put:
+	pm_runtime_put(&pdev->dev);
+err_unprepare_clk:
+	pm_runtime_disable(&pdev->dev);
+	clk_disable_unprepare(chip->clk);
+	return status;
 }
 
 static const struct of_device_id xgpio_of_match[] = {
 	{ .compatible = "xlnx,xps-gpio-1.00.a", },
 	{ /* end of list */ },
 };
-
 MODULE_DEVICE_TABLE(of, xgpio_of_match);
 
-static struct platform_driver xgpio_plat_driver = {
-	.probe		= xgpio_probe,
-	.remove		= xgpio_remove,
-	.driver		= {
-			.name = "gpio-xilinx",
-			.of_match_table	= xgpio_of_match,
+static struct platform_driver xilinx_gpio_driver = {
+	.probe = xgpio_of_probe,
+	.remove = xgpio_remove,
+	.driver = {
+		.name = "xilinx-gpio",
+		.of_match_table = xgpio_of_match,
+		.pm = &xgpio_dev_pm_ops,
 	},
 };
 
 static int __init xgpio_init(void)
 {
-	return platform_driver_register(&xgpio_plat_driver);
+	return platform_driver_register(&xilinx_gpio_driver);
 }
 
+/* Make sure we get initialized before anyone else tries to use us */
 subsys_initcall(xgpio_init);
 
 static void __exit xgpio_exit(void)
 {
-	platform_driver_unregister(&xgpio_plat_driver);
+	platform_driver_unregister(&xilinx_gpio_driver);
 }
 module_exit(xgpio_exit);