[v2,1/2] gpio: mediatek: add driver for MT7621

Message ID 1530276212-18376-2-git-send-email-sergio.paracuellos@gmail.com
State New
Headers show
Series
  • gpio: mediatek: driver for gpio chip in MT7621 SoC
Related show

Commit Message

Sergio Paracuellos June 29, 2018, 12:43 p.m.
Add driver support for gpio of MT7621 SoC.

Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
---
 drivers/gpio/Kconfig       |   8 ++
 drivers/gpio/Makefile      |   1 +
 drivers/gpio/gpio-mt7621.c | 320 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 329 insertions(+)
 create mode 100644 drivers/gpio/gpio-mt7621.c

Comments

Dan Carpenter June 29, 2018, 1:31 p.m. | #1
Looks pretty clean to me.  Sorry for not reviewing v1.  Smatch (private
devel version) points out a little bit of dead code.

drivers/staging/mt7621-gpio/gpio-mt7621.c:200 mediatek_gpio_irq_handler() warn: address of 'gpio_data->gc_map[i]' is non-NULL
drivers/staging/mt7621-gpio/gpio-mt7621.c:225 mediatek_gpio_irq_unmask() warn: address of 'gpio_data->gc_map[bank]' is non-NULL
drivers/staging/mt7621-gpio/gpio-mt7621.c:246 mediatek_gpio_irq_mask() warn: address of 'gpio_data->gc_map[bank]' is non-NULL
drivers/staging/mt7621-gpio/gpio-mt7621.c:266 mediatek_gpio_irq_type() warn: address of 'gpio_data->gc_map[bank]' is non-NULL

But that's harmless and very minor.

regards,
dan carpenter

--
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
Dan Carpenter June 29, 2018, 1:34 p.m. | #2
On Fri, Jun 29, 2018 at 04:31:35PM +0300, Dan Carpenter wrote:
> Looks pretty clean to me.  Sorry for not reviewing v1.  Smatch (private
> devel version) points out a little bit of dead code.
> 
> drivers/staging/mt7621-gpio/gpio-mt7621.c:200 mediatek_gpio_irq_handler() warn: address of 'gpio_data->gc_map[i]' is non-NULL
> drivers/staging/mt7621-gpio/gpio-mt7621.c:225 mediatek_gpio_irq_unmask() warn: address of 'gpio_data->gc_map[bank]' is non-NULL
> drivers/staging/mt7621-gpio/gpio-mt7621.c:246 mediatek_gpio_irq_mask() warn: address of 'gpio_data->gc_map[bank]' is non-NULL
> drivers/staging/mt7621-gpio/gpio-mt7621.c:266 mediatek_gpio_irq_type() warn: address of 'gpio_data->gc_map[bank]' is non-NULL
> 
> But that's harmless and very minor.

I think you fixed all these in the non-staging version...  That's fine
then.

regards,
dan carpenter

--
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
Sergio Paracuellos June 29, 2018, 1:51 p.m. | #3
On Fri, Jun 29, 2018 at 3:31 PM, Dan Carpenter <dan.carpenter@oracle.com> wrote:
> Looks pretty clean to me.  Sorry for not reviewing v1.  Smatch (private
> devel version) points out a little bit of dead code.
>
> drivers/staging/mt7621-gpio/gpio-mt7621.c:200 mediatek_gpio_irq_handler() warn: address of 'gpio_data->gc_map[i]' is non-NULL
> drivers/staging/mt7621-gpio/gpio-mt7621.c:225 mediatek_gpio_irq_unmask() warn: address of 'gpio_data->gc_map[bank]' is non-NULL
> drivers/staging/mt7621-gpio/gpio-mt7621.c:246 mediatek_gpio_irq_mask() warn: address of 'gpio_data->gc_map[bank]' is non-NULL
> drivers/staging/mt7621-gpio/gpio-mt7621.c:266 mediatek_gpio_irq_type() warn: address of 'gpio_data->gc_map[bank]' is non-NULL
>
> But that's harmless and very minor.

That warnings should not being in the staging version. Last patch
series was applied yesterday... Maybe you have not run against the
updated tree?

This patch fix them:

https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git/commit/?h=staging-testing&id=bfb623c5b0935a2e4b5fe86eab79a37a37b67209

>
> regards,
> dan carpenter

Thanks.

Best regards,
    Sergio Paracuellos
>
--
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
kbuild test robot June 29, 2018, 4:43 p.m. | #4
Hi Sergio,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on gpio/for-next]
[also build test ERROR on v4.18-rc2 next-20180629]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Sergio-Paracuellos/gpio-mediatek-driver-for-gpio-chip-in-MT7621-SoC/20180629-225420
base:   https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git for-next
config: x86_64-randconfig-s0-06292230 (attached as .config)
compiler: gcc-6 (Debian 6.4.0-9) 6.4.0 20171026
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

All errors (new ones prefixed by >>):

   drivers/gpio/gpio-mt7621.c: In function 'mediatek_gpio_bank_probe':
>> drivers/gpio/gpio-mt7621.c:221:10: error: 'struct gpio_chip' has no member named 'of_node'
     rg->chip.of_node = node;
             ^

vim +221 drivers/gpio/gpio-mt7621.c

   207	
   208	static int
   209	mediatek_gpio_bank_probe(struct platform_device *pdev,
   210				 struct device_node *node, int bank)
   211	{
   212		struct mtk_data *gpio = dev_get_drvdata(&pdev->dev);
   213		struct mtk_gc *rg;
   214		void __iomem *dat, *set, *ctrl, *diro;
   215		int ret;
   216	
   217		rg = &gpio->gc_map[bank];
   218		memset(rg, 0, sizeof(*rg));
   219	
   220		spin_lock_init(&rg->lock);
 > 221		rg->chip.of_node = node;
   222		rg->bank = bank;
   223		rg->chip.label = mediatek_gpio_bank_name(rg->bank);
   224	
   225		dat = gpio->gpio_membase + GPIO_REG_DATA + (rg->bank * GPIO_BANK_WIDE);
   226		set = gpio->gpio_membase + GPIO_REG_DSET + (rg->bank * GPIO_BANK_WIDE);
   227		ctrl = gpio->gpio_membase + GPIO_REG_DCLR + (rg->bank * GPIO_BANK_WIDE);
   228		diro = gpio->gpio_membase + GPIO_REG_CTRL + (rg->bank * GPIO_BANK_WIDE);
   229	
   230		ret = bgpio_init(&rg->chip, &pdev->dev, 4,
   231				 dat, set, ctrl, diro, NULL, 0);
   232		if (ret) {
   233			dev_err(&pdev->dev, "bgpio_init() failed\n");
   234			return ret;
   235		}
   236	
   237		ret = devm_gpiochip_add_data(&pdev->dev, &rg->chip, gpio);
   238		if (ret < 0) {
   239			dev_err(&pdev->dev, "Could not register gpio %d, ret=%d\n",
   240				rg->chip.ngpio, ret);
   241			return ret;
   242		}
   243	
   244		if (gpio->gpio_irq) {
   245			/*
   246			 * Manually request the irq here instead of passing
   247			 * a flow-handler to gpiochip_set_chained_irqchip,
   248			 * because the irq is shared.
   249			 */
   250			ret = devm_request_irq(&pdev->dev, gpio->gpio_irq,
   251					       mediatek_gpio_irq_handler, IRQF_SHARED,
   252					       rg->chip.label, &rg->chip);
   253	
   254			if (ret) {
   255				dev_err(&pdev->dev, "Error requesting IRQ %d: %d\n",
   256					gpio->gpio_irq, ret);
   257				return ret;
   258			}
   259	
   260			mediatek_gpio_irq_chip.name = rg->chip.label;
   261			ret = gpiochip_irqchip_add(&rg->chip, &mediatek_gpio_irq_chip,
   262						   0, handle_simple_irq, IRQ_TYPE_NONE);
   263			if (ret) {
   264				dev_err(&pdev->dev, "failed to add gpiochip_irqchip\n");
   265				return ret;
   266			}
   267	
   268			gpiochip_set_chained_irqchip(&rg->chip, &mediatek_gpio_irq_chip,
   269						     gpio->gpio_irq, NULL);
   270		}
   271	
   272		/* set polarity to low for all gpios */
   273		mtk_gpio_w32(rg, GPIO_REG_POL, 0);
   274	
   275		dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio);
   276	
   277		return 0;
   278	}
   279	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
Sergio Paracuellos June 29, 2018, 4:52 p.m. | #5
On Fri, Jun 29, 2018 at 6:43 PM, kbuild test robot <lkp@intel.com> wrote:
> Hi Sergio,
>
> Thank you for the patch! Yet something to improve:
>
> [auto build test ERROR on gpio/for-next]
> [also build test ERROR on v4.18-rc2 next-20180629]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>
> url:    https://github.com/0day-ci/linux/commits/Sergio-Paracuellos/gpio-mediatek-driver-for-gpio-chip-in-MT7621-SoC/20180629-225420
> base:   https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git for-next
> config: x86_64-randconfig-s0-06292230 (attached as .config)
> compiler: gcc-6 (Debian 6.4.0-9) 6.4.0 20171026
> reproduce:
>         # save the attached .config to linux build tree
>         make ARCH=x86_64
>
> All errors (new ones prefixed by >>):
>
>    drivers/gpio/gpio-mt7621.c: In function 'mediatek_gpio_bank_probe':
>>> drivers/gpio/gpio-mt7621.c:221:10: error: 'struct gpio_chip' has no member named 'of_node'
>      rg->chip.of_node = node;
>              ^

Should I have to add #ifdef CONFIG_OF_GPIO for this line? Is kind of
ugly hack... Does exist another way to fix this?

Thanks,
    Sergio Paracuellos

>
> vim +221 drivers/gpio/gpio-mt7621.c
>
>    207
>    208  static int
>    209  mediatek_gpio_bank_probe(struct platform_device *pdev,
>    210                           struct device_node *node, int bank)
>    211  {
>    212          struct mtk_data *gpio = dev_get_drvdata(&pdev->dev);
>    213          struct mtk_gc *rg;
>    214          void __iomem *dat, *set, *ctrl, *diro;
>    215          int ret;
>    216
>    217          rg = &gpio->gc_map[bank];
>    218          memset(rg, 0, sizeof(*rg));
>    219
>    220          spin_lock_init(&rg->lock);
>  > 221          rg->chip.of_node = node;
>    222          rg->bank = bank;
>    223          rg->chip.label = mediatek_gpio_bank_name(rg->bank);
>    224
>    225          dat = gpio->gpio_membase + GPIO_REG_DATA + (rg->bank * GPIO_BANK_WIDE);
>    226          set = gpio->gpio_membase + GPIO_REG_DSET + (rg->bank * GPIO_BANK_WIDE);
>    227          ctrl = gpio->gpio_membase + GPIO_REG_DCLR + (rg->bank * GPIO_BANK_WIDE);
>    228          diro = gpio->gpio_membase + GPIO_REG_CTRL + (rg->bank * GPIO_BANK_WIDE);
>    229
>    230          ret = bgpio_init(&rg->chip, &pdev->dev, 4,
>    231                           dat, set, ctrl, diro, NULL, 0);
>    232          if (ret) {
>    233                  dev_err(&pdev->dev, "bgpio_init() failed\n");
>    234                  return ret;
>    235          }
>    236
>    237          ret = devm_gpiochip_add_data(&pdev->dev, &rg->chip, gpio);
>    238          if (ret < 0) {
>    239                  dev_err(&pdev->dev, "Could not register gpio %d, ret=%d\n",
>    240                          rg->chip.ngpio, ret);
>    241                  return ret;
>    242          }
>    243
>    244          if (gpio->gpio_irq) {
>    245                  /*
>    246                   * Manually request the irq here instead of passing
>    247                   * a flow-handler to gpiochip_set_chained_irqchip,
>    248                   * because the irq is shared.
>    249                   */
>    250                  ret = devm_request_irq(&pdev->dev, gpio->gpio_irq,
>    251                                         mediatek_gpio_irq_handler, IRQF_SHARED,
>    252                                         rg->chip.label, &rg->chip);
>    253
>    254                  if (ret) {
>    255                          dev_err(&pdev->dev, "Error requesting IRQ %d: %d\n",
>    256                                  gpio->gpio_irq, ret);
>    257                          return ret;
>    258                  }
>    259
>    260                  mediatek_gpio_irq_chip.name = rg->chip.label;
>    261                  ret = gpiochip_irqchip_add(&rg->chip, &mediatek_gpio_irq_chip,
>    262                                             0, handle_simple_irq, IRQ_TYPE_NONE);
>    263                  if (ret) {
>    264                          dev_err(&pdev->dev, "failed to add gpiochip_irqchip\n");
>    265                          return ret;
>    266                  }
>    267
>    268                  gpiochip_set_chained_irqchip(&rg->chip, &mediatek_gpio_irq_chip,
>    269                                               gpio->gpio_irq, NULL);
>    270          }
>    271
>    272          /* set polarity to low for all gpios */
>    273          mtk_gpio_w32(rg, GPIO_REG_POL, 0);
>    274
>    275          dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio);
>    276
>    277          return 0;
>    278  }
>    279
>
> ---
> 0-DAY kernel test infrastructure                Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
--
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
Sergio Paracuellos June 29, 2018, 7:30 p.m. | #6
On Fri, Jun 29, 2018 at 6:52 PM, Sergio Paracuellos
<sergio.paracuellos@gmail.com> wrote:
> On Fri, Jun 29, 2018 at 6:43 PM, kbuild test robot <lkp@intel.com> wrote:
>> Hi Sergio,
>>
>> Thank you for the patch! Yet something to improve:
>>
>> [auto build test ERROR on gpio/for-next]
>> [also build test ERROR on v4.18-rc2 next-20180629]
>> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>>
>> url:    https://github.com/0day-ci/linux/commits/Sergio-Paracuellos/gpio-mediatek-driver-for-gpio-chip-in-MT7621-SoC/20180629-225420
>> base:   https://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio.git for-next
>> config: x86_64-randconfig-s0-06292230 (attached as .config)
>> compiler: gcc-6 (Debian 6.4.0-9) 6.4.0 20171026
>> reproduce:
>>         # save the attached .config to linux build tree
>>         make ARCH=x86_64
>>
>> All errors (new ones prefixed by >>):
>>
>>    drivers/gpio/gpio-mt7621.c: In function 'mediatek_gpio_bank_probe':
>>>> drivers/gpio/gpio-mt7621.c:221:10: error: 'struct gpio_chip' has no member named 'of_node'
>>      rg->chip.of_node = node;
>>              ^
>
> Should I have to add #ifdef CONFIG_OF_GPIO for this line? Is kind of
> ugly hack... Does exist another way to fix this?
>

Ah, this is v2 where the Makefile was wrong... I though it was v3. I
think we can ignore this and see what happen with likely correct v3.

Best regards,
    Sergio Paracuellos

> Thanks,
>     Sergio Paracuellos
>
>>
>> vim +221 drivers/gpio/gpio-mt7621.c
>>
>>    207
>>    208  static int
>>    209  mediatek_gpio_bank_probe(struct platform_device *pdev,
>>    210                           struct device_node *node, int bank)
>>    211  {
>>    212          struct mtk_data *gpio = dev_get_drvdata(&pdev->dev);
>>    213          struct mtk_gc *rg;
>>    214          void __iomem *dat, *set, *ctrl, *diro;
>>    215          int ret;
>>    216
>>    217          rg = &gpio->gc_map[bank];
>>    218          memset(rg, 0, sizeof(*rg));
>>    219
>>    220          spin_lock_init(&rg->lock);
>>  > 221          rg->chip.of_node = node;
>>    222          rg->bank = bank;
>>    223          rg->chip.label = mediatek_gpio_bank_name(rg->bank);
>>    224
>>    225          dat = gpio->gpio_membase + GPIO_REG_DATA + (rg->bank * GPIO_BANK_WIDE);
>>    226          set = gpio->gpio_membase + GPIO_REG_DSET + (rg->bank * GPIO_BANK_WIDE);
>>    227          ctrl = gpio->gpio_membase + GPIO_REG_DCLR + (rg->bank * GPIO_BANK_WIDE);
>>    228          diro = gpio->gpio_membase + GPIO_REG_CTRL + (rg->bank * GPIO_BANK_WIDE);
>>    229
>>    230          ret = bgpio_init(&rg->chip, &pdev->dev, 4,
>>    231                           dat, set, ctrl, diro, NULL, 0);
>>    232          if (ret) {
>>    233                  dev_err(&pdev->dev, "bgpio_init() failed\n");
>>    234                  return ret;
>>    235          }
>>    236
>>    237          ret = devm_gpiochip_add_data(&pdev->dev, &rg->chip, gpio);
>>    238          if (ret < 0) {
>>    239                  dev_err(&pdev->dev, "Could not register gpio %d, ret=%d\n",
>>    240                          rg->chip.ngpio, ret);
>>    241                  return ret;
>>    242          }
>>    243
>>    244          if (gpio->gpio_irq) {
>>    245                  /*
>>    246                   * Manually request the irq here instead of passing
>>    247                   * a flow-handler to gpiochip_set_chained_irqchip,
>>    248                   * because the irq is shared.
>>    249                   */
>>    250                  ret = devm_request_irq(&pdev->dev, gpio->gpio_irq,
>>    251                                         mediatek_gpio_irq_handler, IRQF_SHARED,
>>    252                                         rg->chip.label, &rg->chip);
>>    253
>>    254                  if (ret) {
>>    255                          dev_err(&pdev->dev, "Error requesting IRQ %d: %d\n",
>>    256                                  gpio->gpio_irq, ret);
>>    257                          return ret;
>>    258                  }
>>    259
>>    260                  mediatek_gpio_irq_chip.name = rg->chip.label;
>>    261                  ret = gpiochip_irqchip_add(&rg->chip, &mediatek_gpio_irq_chip,
>>    262                                             0, handle_simple_irq, IRQ_TYPE_NONE);
>>    263                  if (ret) {
>>    264                          dev_err(&pdev->dev, "failed to add gpiochip_irqchip\n");
>>    265                          return ret;
>>    266                  }
>>    267
>>    268                  gpiochip_set_chained_irqchip(&rg->chip, &mediatek_gpio_irq_chip,
>>    269                                               gpio->gpio_irq, NULL);
>>    270          }
>>    271
>>    272          /* set polarity to low for all gpios */
>>    273          mtk_gpio_w32(rg, GPIO_REG_POL, 0);
>>    274
>>    275          dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio);
>>    276
>>    277          return 0;
>>    278  }
>>    279
>>
>> ---
>> 0-DAY kernel test infrastructure                Open Source Technology Center
>> https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
--
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
Sergio Paracuellos June 30, 2018, 6:12 a.m. | #7
On Fri, Jun 29, 2018 at 2:43 PM, Sergio Paracuellos
<sergio.paracuellos@gmail.com> wrote:
> Add driver support for gpio of MT7621 SoC.
>
> Signed-off-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
> ---
>  drivers/gpio/Kconfig       |   8 ++
>  drivers/gpio/Makefile      |   1 +
>  drivers/gpio/gpio-mt7621.c | 320 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 329 insertions(+)
>  create mode 100644 drivers/gpio/gpio-mt7621.c

Hi all,

Sorry for the noise. Ignore this and v3 for now. It seems the "only
one node" approach for the gpio in the device tree is not working
properly.
I thought it was but Neil points out here it was not:

http://driverdev.linuxdriverproject.org/pipermail/driverdev-devel/2018-June/122621.html

We'll send v4 with all properly working.

Thanks in advance and sorry again.

Best regards,
    Sergio Paracuellos

>
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index 71c0ab4..836aa21 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -359,6 +359,14 @@ config GPIO_MPC8XXX
>           Say Y here if you're going to use hardware that connects to the
>           MPC512x/831x/834x/837x/8572/8610/QorIQ GPIOs.
>
> +config GPIO_MT7621
> +       bool "Mediatek MT7621 GPIO Support"
> +       depends on SOC_MT7620 || SOC_MT7621 || COMPILE_TEST
> +       select GPIO_GENERIC
> +       select GPIOLIB_IRQCHIP
> +       help
> +         Say yes here to support the Mediatek MT7621 SoC GPIO device
> +
>  config GPIO_MVEBU
>         def_bool y
>         depends on PLAT_ORION || ARCH_MVEBU
> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> index 1324c8f..b264426 100644
> --- a/drivers/gpio/Makefile
> +++ b/drivers/gpio/Makefile
> @@ -88,6 +88,7 @@ obj-$(CONFIG_GPIO_MOCKUP)      += gpio-mockup.o
>  obj-$(CONFIG_GPIO_MPC5200)     += gpio-mpc5200.o
>  obj-$(CONFIG_GPIO_MPC8XXX)     += gpio-mpc8xxx.o
>  obj-$(CONFIG_GPIO_MSIC)                += gpio-msic.o
> +obj-$(CONFIG_GPIO_MSIC)                += gpio-mt7621.o
>  obj-$(CONFIG_GPIO_MVEBU)        += gpio-mvebu.o
>  obj-$(CONFIG_GPIO_MXC)         += gpio-mxc.o
>  obj-$(CONFIG_GPIO_MXS)         += gpio-mxs.o
> diff --git a/drivers/gpio/gpio-mt7621.c b/drivers/gpio/gpio-mt7621.c
> new file mode 100644
> index 0000000..281e621
> --- /dev/null
> +++ b/drivers/gpio/gpio-mt7621.c
> @@ -0,0 +1,320 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
> + * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
> + */
> +
> +#include <linux/err.h>
> +#include <linux/gpio/driver.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of_irq.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>
> +
> +#define MTK_BANK_CNT   3
> +#define MTK_BANK_WIDTH 32
> +
> +#define GPIO_BANK_WIDE 0x04
> +#define GPIO_REG_CTRL  0x00
> +#define GPIO_REG_POL   0x10
> +#define GPIO_REG_DATA  0x20
> +#define GPIO_REG_DSET  0x30
> +#define GPIO_REG_DCLR  0x40
> +#define GPIO_REG_REDGE 0x50
> +#define GPIO_REG_FEDGE 0x60
> +#define GPIO_REG_HLVL  0x70
> +#define GPIO_REG_LLVL  0x80
> +#define GPIO_REG_STAT  0x90
> +#define GPIO_REG_EDGE  0xA0
> +
> +struct mtk_gc {
> +       struct gpio_chip chip;
> +       spinlock_t lock;
> +       int bank;
> +       u32 rising;
> +       u32 falling;
> +       u32 hlevel;
> +       u32 llevel;
> +};
> +
> +/**
> + * struct mtk_data - state container for
> + * data of the platform driver. It is 3
> + * separate gpio-chip each one with its
> + * own irq_chip.
> + * @dev: device instance
> + * @gpio_membase: memory base address
> + * @gpio_irq: irq number from the device tree
> + * @gc_map: array of the gpio chips
> + */
> +struct mtk_data {
> +       struct device *dev;
> +       void __iomem *gpio_membase;
> +       int gpio_irq;
> +       struct mtk_gc gc_map[MTK_BANK_CNT];
> +};
> +
> +static inline struct mtk_gc *
> +to_mediatek_gpio(struct gpio_chip *chip)
> +{
> +       return container_of(chip, struct mtk_gc, chip);
> +}
> +
> +static inline void
> +mtk_gpio_w32(struct mtk_gc *rg, u32 offset, u32 val)
> +{
> +       struct gpio_chip *gc = &rg->chip;
> +       struct mtk_data *gpio_data = gpiochip_get_data(gc);
> +
> +       offset = (rg->bank * GPIO_BANK_WIDE) + offset;
> +       gc->write_reg(gpio_data->gpio_membase + offset, val);
> +}
> +
> +static inline u32
> +mtk_gpio_r32(struct mtk_gc *rg, u32 offset)
> +{
> +       struct gpio_chip *gc = &rg->chip;
> +       struct mtk_data *gpio_data = gpiochip_get_data(gc);
> +
> +       offset = (rg->bank * GPIO_BANK_WIDE) + offset;
> +       return gc->read_reg(gpio_data->gpio_membase + offset);
> +}
> +
> +static irqreturn_t
> +mediatek_gpio_irq_handler(int irq, void *data)
> +{
> +       struct gpio_chip *gc = data;
> +       struct mtk_gc *rg = to_mediatek_gpio(gc);
> +       irqreturn_t ret = IRQ_NONE;
> +       unsigned long pending;
> +       int bit;
> +
> +       pending = mtk_gpio_r32(rg, GPIO_REG_STAT);
> +
> +       for_each_set_bit(bit, &pending, MTK_BANK_WIDTH) {
> +               u32 map = irq_find_mapping(gc->irq.domain, bit);
> +
> +               generic_handle_irq(map);
> +               mtk_gpio_w32(rg, GPIO_REG_STAT, BIT(bit));
> +               ret |= IRQ_HANDLED;
> +       }
> +
> +       return ret;
> +}
> +
> +static void
> +mediatek_gpio_irq_unmask(struct irq_data *d)
> +{
> +       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
> +       struct mtk_gc *rg = to_mediatek_gpio(gc);
> +       int pin = d->hwirq;
> +       unsigned long flags;
> +       u32 rise, fall, high, low;
> +
> +       spin_lock_irqsave(&rg->lock, flags);
> +       rise = mtk_gpio_r32(rg, GPIO_REG_REDGE);
> +       fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE);
> +       high = mtk_gpio_r32(rg, GPIO_REG_HLVL);
> +       low = mtk_gpio_r32(rg, GPIO_REG_LLVL);
> +       mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (BIT(pin) & rg->rising));
> +       mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (BIT(pin) & rg->falling));
> +       mtk_gpio_w32(rg, GPIO_REG_HLVL, high | (BIT(pin) & rg->hlevel));
> +       mtk_gpio_w32(rg, GPIO_REG_LLVL, low | (BIT(pin) & rg->llevel));
> +       spin_unlock_irqrestore(&rg->lock, flags);
> +}
> +
> +static void
> +mediatek_gpio_irq_mask(struct irq_data *d)
> +{
> +       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
> +       struct mtk_gc *rg = to_mediatek_gpio(gc);
> +       int pin = d->hwirq;
> +       unsigned long flags;
> +       u32 rise, fall, high, low;
> +
> +       spin_lock_irqsave(&rg->lock, flags);
> +       rise = mtk_gpio_r32(rg, GPIO_REG_REDGE);
> +       fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE);
> +       high = mtk_gpio_r32(rg, GPIO_REG_HLVL);
> +       low = mtk_gpio_r32(rg, GPIO_REG_LLVL);
> +       mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~BIT(pin));
> +       mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~BIT(pin));
> +       mtk_gpio_w32(rg, GPIO_REG_HLVL, high & ~BIT(pin));
> +       mtk_gpio_w32(rg, GPIO_REG_LLVL, low & ~BIT(pin));
> +       spin_unlock_irqrestore(&rg->lock, flags);
> +}
> +
> +static int
> +mediatek_gpio_irq_type(struct irq_data *d, unsigned int type)
> +{
> +       struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
> +       struct mtk_gc *rg = to_mediatek_gpio(gc);
> +       int pin = d->hwirq;
> +       u32 mask = BIT(pin);
> +
> +       if (type == IRQ_TYPE_PROBE) {
> +               if ((rg->rising | rg->falling |
> +                    rg->hlevel | rg->llevel) & mask)
> +                       return 0;
> +
> +               type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
> +       }
> +
> +       rg->rising &= ~mask;
> +       rg->falling &= ~mask;
> +       rg->hlevel &= ~mask;
> +       rg->llevel &= ~mask;
> +
> +       switch (type & IRQ_TYPE_SENSE_MASK) {
> +       case IRQ_TYPE_EDGE_BOTH:
> +               rg->rising |= mask;
> +               rg->falling |= mask;
> +               break;
> +       case IRQ_TYPE_EDGE_RISING:
> +               rg->rising |= mask;
> +               break;
> +       case IRQ_TYPE_EDGE_FALLING:
> +               rg->falling |= mask;
> +               break;
> +       case IRQ_TYPE_LEVEL_HIGH:
> +               rg->hlevel |= mask;
> +               break;
> +       case IRQ_TYPE_LEVEL_LOW:
> +               rg->llevel |= mask;
> +               break;
> +       }
> +
> +       return 0;
> +}
> +
> +static struct irq_chip mediatek_gpio_irq_chip = {
> +       .irq_unmask             = mediatek_gpio_irq_unmask,
> +       .irq_mask               = mediatek_gpio_irq_mask,
> +       .irq_mask_ack           = mediatek_gpio_irq_mask,
> +       .irq_set_type           = mediatek_gpio_irq_type,
> +};
> +
> +static inline const char * const mediatek_gpio_bank_name(int bank)
> +{
> +       static const char * const bank_names[] = {
> +               "mt7621-bank0", "mt7621-bank1", "mt7621-bank2",
> +       };
> +
> +       return bank_names[bank];
> +}
> +
> +static int
> +mediatek_gpio_bank_probe(struct platform_device *pdev,
> +                        struct device_node *node, int bank)
> +{
> +       struct mtk_data *gpio = dev_get_drvdata(&pdev->dev);
> +       struct mtk_gc *rg;
> +       void __iomem *dat, *set, *ctrl, *diro;
> +       int ret;
> +
> +       rg = &gpio->gc_map[bank];
> +       memset(rg, 0, sizeof(*rg));
> +
> +       spin_lock_init(&rg->lock);
> +       rg->chip.of_node = node;
> +       rg->bank = bank;
> +       rg->chip.label = mediatek_gpio_bank_name(rg->bank);
> +
> +       dat = gpio->gpio_membase + GPIO_REG_DATA + (rg->bank * GPIO_BANK_WIDE);
> +       set = gpio->gpio_membase + GPIO_REG_DSET + (rg->bank * GPIO_BANK_WIDE);
> +       ctrl = gpio->gpio_membase + GPIO_REG_DCLR + (rg->bank * GPIO_BANK_WIDE);
> +       diro = gpio->gpio_membase + GPIO_REG_CTRL + (rg->bank * GPIO_BANK_WIDE);
> +
> +       ret = bgpio_init(&rg->chip, &pdev->dev, 4,
> +                        dat, set, ctrl, diro, NULL, 0);
> +       if (ret) {
> +               dev_err(&pdev->dev, "bgpio_init() failed\n");
> +               return ret;
> +       }
> +
> +       ret = devm_gpiochip_add_data(&pdev->dev, &rg->chip, gpio);
> +       if (ret < 0) {
> +               dev_err(&pdev->dev, "Could not register gpio %d, ret=%d\n",
> +                       rg->chip.ngpio, ret);
> +               return ret;
> +       }
> +
> +       if (gpio->gpio_irq) {
> +               /*
> +                * Manually request the irq here instead of passing
> +                * a flow-handler to gpiochip_set_chained_irqchip,
> +                * because the irq is shared.
> +                */
> +               ret = devm_request_irq(&pdev->dev, gpio->gpio_irq,
> +                                      mediatek_gpio_irq_handler, IRQF_SHARED,
> +                                      rg->chip.label, &rg->chip);
> +
> +               if (ret) {
> +                       dev_err(&pdev->dev, "Error requesting IRQ %d: %d\n",
> +                               gpio->gpio_irq, ret);
> +                       return ret;
> +               }
> +
> +               mediatek_gpio_irq_chip.name = rg->chip.label;
> +               ret = gpiochip_irqchip_add(&rg->chip, &mediatek_gpio_irq_chip,
> +                                          0, handle_simple_irq, IRQ_TYPE_NONE);
> +               if (ret) {
> +                       dev_err(&pdev->dev, "failed to add gpiochip_irqchip\n");
> +                       return ret;
> +               }
> +
> +               gpiochip_set_chained_irqchip(&rg->chip, &mediatek_gpio_irq_chip,
> +                                            gpio->gpio_irq, NULL);
> +       }
> +
> +       /* set polarity to low for all gpios */
> +       mtk_gpio_w32(rg, GPIO_REG_POL, 0);
> +
> +       dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio);
> +
> +       return 0;
> +}
> +
> +static int
> +mediatek_gpio_probe(struct platform_device *pdev)
> +{
> +       struct device_node *np = pdev->dev.of_node;
> +       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       struct mtk_data *gpio_data;
> +       int i;
> +
> +       gpio_data = devm_kzalloc(&pdev->dev, sizeof(*gpio_data), GFP_KERNEL);
> +       if (!gpio_data)
> +               return -ENOMEM;
> +
> +       gpio_data->gpio_membase = devm_ioremap_resource(&pdev->dev, res);
> +       if (IS_ERR(gpio_data->gpio_membase))
> +               return PTR_ERR(gpio_data->gpio_membase);
> +
> +       gpio_data->gpio_irq = irq_of_parse_and_map(np, 0);
> +       gpio_data->dev = &pdev->dev;
> +       platform_set_drvdata(pdev, gpio_data);
> +
> +       for (i = 0; i < MTK_BANK_CNT; i++)
> +               mediatek_gpio_bank_probe(pdev, np, i);
> +
> +       return 0;
> +}
> +
> +static const struct of_device_id mediatek_gpio_match[] = {
> +       { .compatible = "mediatek,mt7621-gpio" },
> +       {},
> +};
> +MODULE_DEVICE_TABLE(of, mediatek_gpio_match);
> +
> +static struct platform_driver mediatek_gpio_driver = {
> +       .probe = mediatek_gpio_probe,
> +       .driver = {
> +               .name = "mt7621_gpio",
> +               .of_match_table = mediatek_gpio_match,
> +       },
> +};
> +
> +builtin_platform_driver(mediatek_gpio_driver);
> --
> 2.7.4
>
--
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

Patch

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 71c0ab4..836aa21 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -359,6 +359,14 @@  config GPIO_MPC8XXX
 	  Say Y here if you're going to use hardware that connects to the
 	  MPC512x/831x/834x/837x/8572/8610/QorIQ GPIOs.
 
+config GPIO_MT7621
+	bool "Mediatek MT7621 GPIO Support"
+	depends on SOC_MT7620 || SOC_MT7621 || COMPILE_TEST
+	select GPIO_GENERIC
+	select GPIOLIB_IRQCHIP
+	help
+	  Say yes here to support the Mediatek MT7621 SoC GPIO device
+
 config GPIO_MVEBU
 	def_bool y
 	depends on PLAT_ORION || ARCH_MVEBU
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 1324c8f..b264426 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -88,6 +88,7 @@  obj-$(CONFIG_GPIO_MOCKUP)      += gpio-mockup.o
 obj-$(CONFIG_GPIO_MPC5200)	+= gpio-mpc5200.o
 obj-$(CONFIG_GPIO_MPC8XXX)	+= gpio-mpc8xxx.o
 obj-$(CONFIG_GPIO_MSIC)		+= gpio-msic.o
+obj-$(CONFIG_GPIO_MSIC)		+= gpio-mt7621.o
 obj-$(CONFIG_GPIO_MVEBU)        += gpio-mvebu.o
 obj-$(CONFIG_GPIO_MXC)		+= gpio-mxc.o
 obj-$(CONFIG_GPIO_MXS)		+= gpio-mxs.o
diff --git a/drivers/gpio/gpio-mt7621.c b/drivers/gpio/gpio-mt7621.c
new file mode 100644
index 0000000..281e621
--- /dev/null
+++ b/drivers/gpio/gpio-mt7621.c
@@ -0,0 +1,320 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#define MTK_BANK_CNT	3
+#define MTK_BANK_WIDTH	32
+
+#define GPIO_BANK_WIDE	0x04
+#define GPIO_REG_CTRL	0x00
+#define GPIO_REG_POL	0x10
+#define GPIO_REG_DATA	0x20
+#define GPIO_REG_DSET	0x30
+#define GPIO_REG_DCLR	0x40
+#define GPIO_REG_REDGE	0x50
+#define GPIO_REG_FEDGE	0x60
+#define GPIO_REG_HLVL	0x70
+#define GPIO_REG_LLVL	0x80
+#define GPIO_REG_STAT	0x90
+#define GPIO_REG_EDGE	0xA0
+
+struct mtk_gc {
+	struct gpio_chip chip;
+	spinlock_t lock;
+	int bank;
+	u32 rising;
+	u32 falling;
+	u32 hlevel;
+	u32 llevel;
+};
+
+/**
+ * struct mtk_data - state container for
+ * data of the platform driver. It is 3
+ * separate gpio-chip each one with its
+ * own irq_chip.
+ * @dev: device instance
+ * @gpio_membase: memory base address
+ * @gpio_irq: irq number from the device tree
+ * @gc_map: array of the gpio chips
+ */
+struct mtk_data {
+	struct device *dev;
+	void __iomem *gpio_membase;
+	int gpio_irq;
+	struct mtk_gc gc_map[MTK_BANK_CNT];
+};
+
+static inline struct mtk_gc *
+to_mediatek_gpio(struct gpio_chip *chip)
+{
+	return container_of(chip, struct mtk_gc, chip);
+}
+
+static inline void
+mtk_gpio_w32(struct mtk_gc *rg, u32 offset, u32 val)
+{
+	struct gpio_chip *gc = &rg->chip;
+	struct mtk_data *gpio_data = gpiochip_get_data(gc);
+
+	offset = (rg->bank * GPIO_BANK_WIDE) + offset;
+	gc->write_reg(gpio_data->gpio_membase + offset, val);
+}
+
+static inline u32
+mtk_gpio_r32(struct mtk_gc *rg, u32 offset)
+{
+	struct gpio_chip *gc = &rg->chip;
+	struct mtk_data *gpio_data = gpiochip_get_data(gc);
+
+	offset = (rg->bank * GPIO_BANK_WIDE) + offset;
+	return gc->read_reg(gpio_data->gpio_membase + offset);
+}
+
+static irqreturn_t
+mediatek_gpio_irq_handler(int irq, void *data)
+{
+	struct gpio_chip *gc = data;
+	struct mtk_gc *rg = to_mediatek_gpio(gc);
+	irqreturn_t ret = IRQ_NONE;
+	unsigned long pending;
+	int bit;
+
+	pending = mtk_gpio_r32(rg, GPIO_REG_STAT);
+
+	for_each_set_bit(bit, &pending, MTK_BANK_WIDTH) {
+		u32 map = irq_find_mapping(gc->irq.domain, bit);
+
+		generic_handle_irq(map);
+		mtk_gpio_w32(rg, GPIO_REG_STAT, BIT(bit));
+		ret |= IRQ_HANDLED;
+	}
+
+	return ret;
+}
+
+static void
+mediatek_gpio_irq_unmask(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct mtk_gc *rg = to_mediatek_gpio(gc);
+	int pin = d->hwirq;
+	unsigned long flags;
+	u32 rise, fall, high, low;
+
+	spin_lock_irqsave(&rg->lock, flags);
+	rise = mtk_gpio_r32(rg, GPIO_REG_REDGE);
+	fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE);
+	high = mtk_gpio_r32(rg, GPIO_REG_HLVL);
+	low = mtk_gpio_r32(rg, GPIO_REG_LLVL);
+	mtk_gpio_w32(rg, GPIO_REG_REDGE, rise | (BIT(pin) & rg->rising));
+	mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall | (BIT(pin) & rg->falling));
+	mtk_gpio_w32(rg, GPIO_REG_HLVL, high | (BIT(pin) & rg->hlevel));
+	mtk_gpio_w32(rg, GPIO_REG_LLVL, low | (BIT(pin) & rg->llevel));
+	spin_unlock_irqrestore(&rg->lock, flags);
+}
+
+static void
+mediatek_gpio_irq_mask(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct mtk_gc *rg = to_mediatek_gpio(gc);
+	int pin = d->hwirq;
+	unsigned long flags;
+	u32 rise, fall, high, low;
+
+	spin_lock_irqsave(&rg->lock, flags);
+	rise = mtk_gpio_r32(rg, GPIO_REG_REDGE);
+	fall = mtk_gpio_r32(rg, GPIO_REG_FEDGE);
+	high = mtk_gpio_r32(rg, GPIO_REG_HLVL);
+	low = mtk_gpio_r32(rg, GPIO_REG_LLVL);
+	mtk_gpio_w32(rg, GPIO_REG_FEDGE, fall & ~BIT(pin));
+	mtk_gpio_w32(rg, GPIO_REG_REDGE, rise & ~BIT(pin));
+	mtk_gpio_w32(rg, GPIO_REG_HLVL, high & ~BIT(pin));
+	mtk_gpio_w32(rg, GPIO_REG_LLVL, low & ~BIT(pin));
+	spin_unlock_irqrestore(&rg->lock, flags);
+}
+
+static int
+mediatek_gpio_irq_type(struct irq_data *d, unsigned int type)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct mtk_gc *rg = to_mediatek_gpio(gc);
+	int pin = d->hwirq;
+	u32 mask = BIT(pin);
+
+	if (type == IRQ_TYPE_PROBE) {
+		if ((rg->rising | rg->falling |
+		     rg->hlevel | rg->llevel) & mask)
+			return 0;
+
+		type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+	}
+
+	rg->rising &= ~mask;
+	rg->falling &= ~mask;
+	rg->hlevel &= ~mask;
+	rg->llevel &= ~mask;
+
+	switch (type & IRQ_TYPE_SENSE_MASK) {
+	case IRQ_TYPE_EDGE_BOTH:
+		rg->rising |= mask;
+		rg->falling |= mask;
+		break;
+	case IRQ_TYPE_EDGE_RISING:
+		rg->rising |= mask;
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		rg->falling |= mask;
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		rg->hlevel |= mask;
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+		rg->llevel |= mask;
+		break;
+	}
+
+	return 0;
+}
+
+static struct irq_chip mediatek_gpio_irq_chip = {
+	.irq_unmask		= mediatek_gpio_irq_unmask,
+	.irq_mask		= mediatek_gpio_irq_mask,
+	.irq_mask_ack		= mediatek_gpio_irq_mask,
+	.irq_set_type		= mediatek_gpio_irq_type,
+};
+
+static inline const char * const mediatek_gpio_bank_name(int bank)
+{
+	static const char * const bank_names[] = {
+		"mt7621-bank0", "mt7621-bank1", "mt7621-bank2",
+	};
+
+	return bank_names[bank];
+}
+
+static int
+mediatek_gpio_bank_probe(struct platform_device *pdev,
+			 struct device_node *node, int bank)
+{
+	struct mtk_data *gpio = dev_get_drvdata(&pdev->dev);
+	struct mtk_gc *rg;
+	void __iomem *dat, *set, *ctrl, *diro;
+	int ret;
+
+	rg = &gpio->gc_map[bank];
+	memset(rg, 0, sizeof(*rg));
+
+	spin_lock_init(&rg->lock);
+	rg->chip.of_node = node;
+	rg->bank = bank;
+	rg->chip.label = mediatek_gpio_bank_name(rg->bank);
+
+	dat = gpio->gpio_membase + GPIO_REG_DATA + (rg->bank * GPIO_BANK_WIDE);
+	set = gpio->gpio_membase + GPIO_REG_DSET + (rg->bank * GPIO_BANK_WIDE);
+	ctrl = gpio->gpio_membase + GPIO_REG_DCLR + (rg->bank * GPIO_BANK_WIDE);
+	diro = gpio->gpio_membase + GPIO_REG_CTRL + (rg->bank * GPIO_BANK_WIDE);
+
+	ret = bgpio_init(&rg->chip, &pdev->dev, 4,
+			 dat, set, ctrl, diro, NULL, 0);
+	if (ret) {
+		dev_err(&pdev->dev, "bgpio_init() failed\n");
+		return ret;
+	}
+
+	ret = devm_gpiochip_add_data(&pdev->dev, &rg->chip, gpio);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Could not register gpio %d, ret=%d\n",
+			rg->chip.ngpio, ret);
+		return ret;
+	}
+
+	if (gpio->gpio_irq) {
+		/*
+		 * Manually request the irq here instead of passing
+		 * a flow-handler to gpiochip_set_chained_irqchip,
+		 * because the irq is shared.
+		 */
+		ret = devm_request_irq(&pdev->dev, gpio->gpio_irq,
+				       mediatek_gpio_irq_handler, IRQF_SHARED,
+				       rg->chip.label, &rg->chip);
+
+		if (ret) {
+			dev_err(&pdev->dev, "Error requesting IRQ %d: %d\n",
+				gpio->gpio_irq, ret);
+			return ret;
+		}
+
+		mediatek_gpio_irq_chip.name = rg->chip.label;
+		ret = gpiochip_irqchip_add(&rg->chip, &mediatek_gpio_irq_chip,
+					   0, handle_simple_irq, IRQ_TYPE_NONE);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to add gpiochip_irqchip\n");
+			return ret;
+		}
+
+		gpiochip_set_chained_irqchip(&rg->chip, &mediatek_gpio_irq_chip,
+					     gpio->gpio_irq, NULL);
+	}
+
+	/* set polarity to low for all gpios */
+	mtk_gpio_w32(rg, GPIO_REG_POL, 0);
+
+	dev_info(&pdev->dev, "registering %d gpios\n", rg->chip.ngpio);
+
+	return 0;
+}
+
+static int
+mediatek_gpio_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	struct mtk_data *gpio_data;
+	int i;
+
+	gpio_data = devm_kzalloc(&pdev->dev, sizeof(*gpio_data), GFP_KERNEL);
+	if (!gpio_data)
+		return -ENOMEM;
+
+	gpio_data->gpio_membase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(gpio_data->gpio_membase))
+		return PTR_ERR(gpio_data->gpio_membase);
+
+	gpio_data->gpio_irq = irq_of_parse_and_map(np, 0);
+	gpio_data->dev = &pdev->dev;
+	platform_set_drvdata(pdev, gpio_data);
+
+	for (i = 0; i < MTK_BANK_CNT; i++)
+		mediatek_gpio_bank_probe(pdev, np, i);
+
+	return 0;
+}
+
+static const struct of_device_id mediatek_gpio_match[] = {
+	{ .compatible = "mediatek,mt7621-gpio" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, mediatek_gpio_match);
+
+static struct platform_driver mediatek_gpio_driver = {
+	.probe = mediatek_gpio_probe,
+	.driver = {
+		.name = "mt7621_gpio",
+		.of_match_table = mediatek_gpio_match,
+	},
+};
+
+builtin_platform_driver(mediatek_gpio_driver);