[OpenWrt-Devel,1/3] brcm63xx: add bcm6345-gpio driver
diff mbox

Message ID 5488DC9C.3000504@gmail.com
State Changes Requested
Delegated to: Jonas Gorski
Headers show

Commit Message

Álvaro Fernández Rojas Dec. 10, 2014, 11:51 p.m. UTC
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
---

Comments

Jonas Gorski Dec. 12, 2014, 2:12 p.m. UTC | #1
On Thu, Dec 11, 2014 at 12:51 AM, Álvaro Fernández Rojas
<noltari@gmail.com> wrote:
> Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
> ---
> diff --git a/target/linux/brcm63xx/config-3.14 b/target/linux/brcm63xx/config-3.14
> index dd27f47..f94c567 100644
> --- a/target/linux/brcm63xx/config-3.14
> +++ b/target/linux/brcm63xx/config-3.14
> @@ -76,6 +76,7 @@ CONFIG_GENERIC_IRQ_SHOW=y
>  CONFIG_GENERIC_PCI_IOMAP=y
>  CONFIG_GENERIC_SMP_IDLE_THREAD=y
>  CONFIG_GPIOLIB=y
> +CONFIG_GPIO_BCM6345=y
>  CONFIG_GPIO_DEVRES=y
>  CONFIG_GPIO_SYSFS=y
>  # CONFIG_HAMRADIO is not set
> diff --git a/target/linux/brcm63xx/config-3.18 b/target/linux/brcm63xx/config-3.18
> index e3cf020..7957d02 100644
> --- a/target/linux/brcm63xx/config-3.18
> +++ b/target/linux/brcm63xx/config-3.18
> @@ -80,6 +80,7 @@ CONFIG_GENERIC_IRQ_SHOW=y
>  CONFIG_GENERIC_PCI_IOMAP=y
>  CONFIG_GENERIC_SMP_IDLE_THREAD=y
>  CONFIG_GPIOLIB=y
> +CONFIG_GPIO_BCM6345=y
>  CONFIG_GPIO_DEVRES=y
>  CONFIG_GPIO_SYSFS=y
>  # CONFIG_HAMRADIO is not set
> diff --git a/target/linux/brcm63xx/patches-3.14/374-GPIO-DT-add-bcm6345-driver.patch b/target/linux/brcm63xx/patches-3.14/374-GPIO-DT-add-bcm6345-driver.patch
> new file mode 100644
> index 0000000..a6c775b
> --- /dev/null
> +++ b/target/linux/brcm63xx/patches-3.14/374-GPIO-DT-add-bcm6345-driver.patch
> @@ -0,0 +1,244 @@
> +--- /dev/null
> ++++ b/drivers/gpio/gpio-bcm6345.c
> +@@ -0,0 +1,216 @@
> ++/*
> ++ * This file is subject to the terms and conditions of the GNU General Public
> ++ * License.  See the file "COPYING" in the main directory of this archive
> ++ * for more details.
> ++ *
> ++ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
> ++ * Copyright (C) 2008-2011 Florian Fainelli <florian@openwrt.org>
> ++ * Copyright (C) 2014 Álvaro Fernández Rojas <noltari@gmail.com>
> ++ */
> ++
> ++#include <linux/kernel.h>
> ++#include <linux/module.h>
> ++#include <linux/spinlock.h>
> ++#include <linux/platform_device.h>
> ++#include <linux/gpio.h>
> ++
> ++enum bcm6345_gpio_reg {
> ++      GPIO_REG_CTL_HI = 0,
> ++      GPIO_REG_CTL_LO,
> ++      GPIO_REG_DATA_HI,
> ++      GPIO_REG_DATA_LO,
> ++      GPIO_REG_MAX
> ++};
> ++
> ++struct bcm6345_gpio_chip {
> ++      struct gpio_chip chip;
> ++      u8 regs[GPIO_REG_MAX];


I think we could replace the whole driver with

e.g. bcm6345:

gpio0: gpio-controller@fffe0404 {
      compatible = "basic-mmio-gpio-be";
      regs = <0xfffe0404 0x4 0xfffe0408 0x2>
      reg-names = "dirin", "dat";
      gpio-controller;
      #gpio-cells = <2>;
};

and for the ones with > 32 gpios:

gpio0: gpio-controller@10000084 {
      compatible = "basic-mmio-gpio-be";
      regs = <0x10000084 0x4 0x1000008c 0x4>
      reg-names = "dirin", "dat";
      gpio-controller;
      #gpio-cells = <2>;
};

gpio1: gpio-controller@1000080 {
      compatible = "basic-mmio-gpio-be";
      regs = <0x10000080 0x4 0x1000008c 0x4>
      reg-names = "dirin", "dat";
      gpio-controller;
      #gpio-cells = <2>;
};

Maybe add support for setting ngpios through DT, or make it a usable-mask or so.

For the gpio-base problem, we should be able to register appropriate
platform data for it as OF_DEV_AUXDATA() in of_platform_populate.

e.g.

struct bgpio_pdata gpio0_pdata  = {
      .base = 0,
};

struct bgpio_pdata gpio1_pdata  = {
      .base = 32,
};

struct of_dev_auxdata auxdata[] = {
      OF_DEV_AUXDATA("basic-mmio-gpio-be",0xfffe0400, NULL, gpio1_pdata),
      OF_DEV_AUXDATA("basic-mmio-gpio-be",0xfffe0404, NULL, gpio0_pdata),
      OF_DEV_AUXDATA("basic-mmio-gpio-be",0xfffe0080, NULL, gpio1_pdata),
      OF_DEV_AUXDATA("basic-mmio-gpio-be",0xfffe0084, NULL, gpio0_pdata),
      OF_DEV_AUXDATA("basic-mmio-gpio-be",0x10000080, NULL, gpio1_pdata),
      OF_DEV_AUXDATA("basic-mmio-gpio-be",0x10000084, NULL, gpio0_pdata),
};

...
      of_platform_populate(... auxdata, );



Jonas
John Crispin Dec. 12, 2014, 2:17 p.m. UTC | #2
On 12/12/2014 15:12, Jonas Gorski wrote:
> or the gpio-base problem, we should be able to register appropriate
> platform data for it as OF_DEV_AUXDATA() in of_platform_populate.
> 
> e.g.
> 
> struct bgpio_pdata gpio0_pdata  = {
>       .base = 0,
> };
> 
> struct bgpio_pdata gpio1_pdata  = {
>       .base = 32,
> };

tried it for ralink and lantiq and it got nak'ed by LinusW

i keep that part of the code as a small patch inside owrt on top of the
stuff i sent upstream.

	John
Jonas Gorski Dec. 12, 2014, 2:33 p.m. UTC | #3
On Fri, Dec 12, 2014 at 3:17 PM, John Crispin <blogic@openwrt.org> wrote:
>
>
> On 12/12/2014 15:12, Jonas Gorski wrote:
>> or the gpio-base problem, we should be able to register appropriate
>> platform data for it as OF_DEV_AUXDATA() in of_platform_populate.
>>
>> e.g.
>>
>> struct bgpio_pdata gpio0_pdata  = {
>>       .base = 0,
>> };
>>
>> struct bgpio_pdata gpio1_pdata  = {
>>       .base = 32,
>> };
>
> tried it for ralink and lantiq and it got nak'ed by LinusW
>
> i keep that part of the code as a small patch inside owrt on top of the
> stuff i sent upstream.

Wasn't the objection on putting the gpio base into the dts(i) file
itself? I explicitly try to avoid that here, as gpio-base is something
linux internal.

But It doesn't matter much for now as not even basic DT support is
upstream, so these won't go anywhere soon.


Jonas
John Crispin Dec. 12, 2014, 2:34 p.m. UTC | #4
On 12/12/2014 15:33, Jonas Gorski wrote:
> On Fri, Dec 12, 2014 at 3:17 PM, John Crispin <blogic@openwrt.org> wrote:
>>
>>
>> On 12/12/2014 15:12, Jonas Gorski wrote:
>>> or the gpio-base problem, we should be able to register appropriate
>>> platform data for it as OF_DEV_AUXDATA() in of_platform_populate.
>>>
>>> e.g.
>>>
>>> struct bgpio_pdata gpio0_pdata  = {
>>>       .base = 0,
>>> };
>>>
>>> struct bgpio_pdata gpio1_pdata  = {
>>>       .base = 32,
>>> };
>>
>> tried it for ralink and lantiq and it got nak'ed by LinusW
>>
>> i keep that part of the code as a small patch inside owrt on top of the
>> stuff i sent upstream.
> 
> Wasn't the objection on putting the gpio base into the dts(i) file
> itself? I explicitly try to avoid that here, as gpio-base is something
> linux internal.
> 

i think it was in general but might be wrong .... i'll dig into my mails
when i go on the next kernel spree


> But It doesn't matter much for now as not even basic DT support is
> upstream, so these won't go anywhere soon.
> 
> 
> Jonas
>
Florian Fainelli Dec. 15, 2014, 3:15 p.m. UTC | #5
2014-12-12 6:33 GMT-08:00 Jonas Gorski <jogo@openwrt.org>:
> On Fri, Dec 12, 2014 at 3:17 PM, John Crispin <blogic@openwrt.org> wrote:
>>
>>
>> On 12/12/2014 15:12, Jonas Gorski wrote:
>>> or the gpio-base problem, we should be able to register appropriate
>>> platform data for it as OF_DEV_AUXDATA() in of_platform_populate.
>>>
>>> e.g.
>>>
>>> struct bgpio_pdata gpio0_pdata  = {
>>>       .base = 0,
>>> };
>>>
>>> struct bgpio_pdata gpio1_pdata  = {
>>>       .base = 32,
>>> };
>>
>> tried it for ralink and lantiq and it got nak'ed by LinusW
>>
>> i keep that part of the code as a small patch inside owrt on top of the
>> stuff i sent upstream.
>
> Wasn't the objection on putting the gpio base into the dts(i) file
> itself? I explicitly try to avoid that here, as gpio-base is something
> linux internal.

Right that is typically the objection, but with the new gpio
descriptor based API, we should not have that problem anymore, right?

>
> But It doesn't matter much for now as not even basic DT support is
> upstream, so these won't go anywhere soon.

--
Florian
Jonas Gorski Dec. 16, 2014, 12:58 p.m. UTC | #6
On Mon, Dec 15, 2014 at 4:15 PM, Florian Fainelli <florian@openwrt.org> wrote:
> 2014-12-12 6:33 GMT-08:00 Jonas Gorski <jogo@openwrt.org>:
>> On Fri, Dec 12, 2014 at 3:17 PM, John Crispin <blogic@openwrt.org> wrote:
>>>
>>>
>>> On 12/12/2014 15:12, Jonas Gorski wrote:
>>>> or the gpio-base problem, we should be able to register appropriate
>>>> platform data for it as OF_DEV_AUXDATA() in of_platform_populate.
>>>>
>>>> e.g.
>>>>
>>>> struct bgpio_pdata gpio0_pdata  = {
>>>>       .base = 0,
>>>> };
>>>>
>>>> struct bgpio_pdata gpio1_pdata  = {
>>>>       .base = 32,
>>>> };
>>>
>>> tried it for ralink and lantiq and it got nak'ed by LinusW
>>>
>>> i keep that part of the code as a small patch inside owrt on top of the
>>> stuff i sent upstream.
>>
>> Wasn't the objection on putting the gpio base into the dts(i) file
>> itself? I explicitly try to avoid that here, as gpio-base is something
>> linux internal.
>
> Right that is typically the objection, but with the new gpio
> descriptor based API, we should not have that problem anymore, right?

But we would first have to convert the consumers and the gpio driver
to use/provide it. I think it's easier to leave the gpio base set for
now, and remove it later once we have converted all users to either
get their gpios through DT (leds, buttons, ...) or being able to use
descriptors (phy reset gpio for ethernet).


Jonas

Patch
diff mbox

diff --git a/target/linux/brcm63xx/config-3.14 b/target/linux/brcm63xx/config-3.14
index dd27f47..f94c567 100644
--- a/target/linux/brcm63xx/config-3.14
+++ b/target/linux/brcm63xx/config-3.14
@@ -76,6 +76,7 @@  CONFIG_GENERIC_IRQ_SHOW=y
 CONFIG_GENERIC_PCI_IOMAP=y
 CONFIG_GENERIC_SMP_IDLE_THREAD=y
 CONFIG_GPIOLIB=y
+CONFIG_GPIO_BCM6345=y
 CONFIG_GPIO_DEVRES=y
 CONFIG_GPIO_SYSFS=y
 # CONFIG_HAMRADIO is not set
diff --git a/target/linux/brcm63xx/config-3.18 b/target/linux/brcm63xx/config-3.18
index e3cf020..7957d02 100644
--- a/target/linux/brcm63xx/config-3.18
+++ b/target/linux/brcm63xx/config-3.18
@@ -80,6 +80,7 @@  CONFIG_GENERIC_IRQ_SHOW=y
 CONFIG_GENERIC_PCI_IOMAP=y
 CONFIG_GENERIC_SMP_IDLE_THREAD=y
 CONFIG_GPIOLIB=y
+CONFIG_GPIO_BCM6345=y
 CONFIG_GPIO_DEVRES=y
 CONFIG_GPIO_SYSFS=y
 # CONFIG_HAMRADIO is not set
diff --git a/target/linux/brcm63xx/patches-3.14/374-GPIO-DT-add-bcm6345-driver.patch b/target/linux/brcm63xx/patches-3.14/374-GPIO-DT-add-bcm6345-driver.patch
new file mode 100644
index 0000000..a6c775b
--- /dev/null
+++ b/target/linux/brcm63xx/patches-3.14/374-GPIO-DT-add-bcm6345-driver.patch
@@ -0,0 +1,244 @@ 
+--- /dev/null
++++ b/drivers/gpio/gpio-bcm6345.c
+@@ -0,0 +1,216 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
++ * Copyright (C) 2008-2011 Florian Fainelli <florian@openwrt.org>
++ * Copyright (C) 2014 Álvaro Fernández Rojas <noltari@gmail.com>
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/platform_device.h>
++#include <linux/gpio.h>
++
++enum bcm6345_gpio_reg {
++	GPIO_REG_CTL_HI = 0,
++	GPIO_REG_CTL_LO,
++	GPIO_REG_DATA_HI,
++	GPIO_REG_DATA_LO,
++	GPIO_REG_MAX
++};
++
++struct bcm6345_gpio_chip {
++	struct gpio_chip chip;
++	u8 regs[GPIO_REG_MAX];
++
++	spinlock_t lock;
++	void __iomem *membase;
++};
++
++static inline struct bcm6345_gpio_chip *to_bcm6345_gpio(struct gpio_chip *chip)
++{
++	struct bcm6345_gpio_chip *bg;
++
++	bg = container_of(chip, struct bcm6345_gpio_chip, chip);
++
++	return bg;
++}
++
++static inline u32 bc_gpio_r32(struct bcm6345_gpio_chip *bg, u8 reg)
++{
++	return ioread32be(bg->membase + bg->regs[reg]);
++}
++
++static inline void bc_gpio_w32(struct bcm6345_gpio_chip *bg, u8 reg, u32 val)
++{
++	iowrite32be(val, bg->membase + bg->regs[reg]);
++}
++
++static void bcm6345_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
++{
++	struct bcm6345_gpio_chip *bg = to_bcm6345_gpio(chip);
++	unsigned long flags;
++	u32 mask, val;
++	u8 reg;
++
++	if (gpio < 32) {
++		reg = GPIO_REG_DATA_LO;
++		mask = BIT(gpio);
++	} else {
++		reg = GPIO_REG_DATA_HI;
++		mask = BIT(gpio - 32);
++	}
++
++	spin_lock_irqsave(&bg->lock, flags);
++	val = bc_gpio_r32(bg, reg);
++	if (value)
++		val |= mask;
++	else
++		val &= ~mask;
++	bc_gpio_w32(bg, reg, val);
++	spin_unlock_irqrestore(&bg->lock, flags);
++}
++
++static int bcm6345_gpio_get(struct gpio_chip *chip, unsigned gpio)
++{
++	struct bcm6345_gpio_chip *bg = to_bcm6345_gpio(chip);
++	u32 mask;
++	u8 reg;
++
++	if (gpio < 32) {
++		reg = GPIO_REG_DATA_LO;
++		mask = BIT(gpio);
++	} else {
++		reg = GPIO_REG_DATA_HI;
++		mask = BIT(gpio - 32);
++	}
++
++	return !!(bc_gpio_r32(bg, reg) & mask);
++}
++
++static int bcm6345_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
++{
++	struct bcm6345_gpio_chip *bg = to_bcm6345_gpio(chip);
++	unsigned long flags;
++	u32 mask, val;
++	u8 reg;
++
++	if (gpio < 32) {
++		reg = GPIO_REG_CTL_LO;
++		mask = BIT(gpio);
++	} else {
++		reg = GPIO_REG_CTL_HI;
++		mask = BIT(gpio - 32);
++	}
++
++	spin_lock_irqsave(&bg->lock, flags);
++	val = bc_gpio_r32(bg, reg) & ~mask;
++	bc_gpio_w32(bg, reg, val);
++	spin_unlock_irqrestore(&bg->lock, flags);
++
++	return 0;
++}
++
++static int bcm6345_gpio_direction_output(struct gpio_chip *chip, unsigned gpio)
++{
++	struct bcm6345_gpio_chip *bg = to_bcm6345_gpio(chip);
++	unsigned long flags;
++	u32 mask, val;
++	u8 reg;
++
++	if (gpio < 32) {
++		reg = GPIO_REG_CTL_LO;
++		mask = BIT(gpio);
++	} else {
++		reg = GPIO_REG_CTL_HI;
++		mask = BIT(gpio - 32);
++	}
++
++	spin_lock_irqsave(&bg->lock, flags);
++	val = bc_gpio_r32(bg, reg) | mask;
++	bc_gpio_w32(bg, reg, val);
++	spin_unlock_irqrestore(&bg->lock, flags);
++
++	return 0;
++}
++
++int __init bcm6345_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 bcm6345_gpio_chip *bg;
++	const __be32 *ngpio, *gpiobase;
++
++	if (!res) {
++		dev_err(&pdev->dev, "failed to find resource\n");
++		return -ENOMEM;
++	}
++
++	bg = devm_kzalloc(&pdev->dev,
++			sizeof(struct gpio_chip), GFP_KERNEL);
++	if (!bg)
++		return -ENOMEM;
++
++	bg->membase = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(bg->membase)) {
++		dev_err(&pdev->dev, "cannot remap I/O memory region\n");
++		return -ENOMEM;
++	}
++
++	if (of_property_read_u8_array(np, "bcm6345,register-map",
++			bg->regs, GPIO_REG_MAX)) {
++		dev_err(&pdev->dev, "failed to read register definition\n");
++		return -EINVAL;
++	}
++
++	ngpio = of_get_property(np, "bcm6345,num-gpios", NULL);
++	if (!ngpio) {
++		dev_err(&pdev->dev, "failed to read number of pins\n");
++		return -EINVAL;
++	}
++
++	gpiobase = of_get_property(np, "bcm6345,gpio-base", NULL);
++	if (gpiobase)
++		bg->chip.base = be32_to_cpu(*gpiobase);
++	else
++		bg->chip.base = -1;
++
++	spin_lock_init(&bg->lock);
++
++	bg->chip.dev = &pdev->dev;
++	bg->chip.label = dev_name(&pdev->dev);
++	bg->chip.of_node = np;
++	bg->chip.ngpio = be32_to_cpu(*ngpio);
++	bg->chip.direction_input = bcm6345_gpio_direction_input;
++	bg->chip.direction_output = bcm6345_gpio_direction_output;
++	bg->chip.get = bcm6345_gpio_get;
++	bg->chip.set = bcm6345_gpio_set;
++
++	dev_info(&pdev->dev, "registering %d gpios\n", bg->chip.ngpio);
++
++	return gpiochip_add(&bg->chip);
++}
++
++static struct of_device_id bcm6345_gpio_match[] = {
++	{ .compatible = "brcm,bcm6345-gpio" },
++	{ },
++};
++MODULE_DEVICE_TABLE(of, bcm6345_gpio_match);
++
++static struct platform_driver bcm6345_gpio_driver = {
++	.driver = {
++		.name = "bcm6345-gpio",
++		.owner = THIS_MODULE,
++		.of_match_table = bcm6345_gpio_match,
++	},
++	.probe = bcm6345_gpio_probe,
++};
++
++int __init bcm6345_gpio_init(void)
++{
++	return platform_driver_register(&bcm6345_gpio_driver);
++}
++subsys_initcall(bcm6345_gpio_init);
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -108,6 +108,12 @@ config GPIO_MAX730X
+ 
+ comment "Memory mapped GPIO drivers:"
+ 
++config GPIO_BCM6345
++	bool "Broadcom 6345 GPIO Support"
++	depends on BCM63XX
++	help
++	  Say yes here to support the Broadcom 6345 SoC GPIO device
++
+ config GPIO_CLPS711X
+ 	tristate "CLPS711X GPIO support"
+ 	depends on ARCH_CLPS711X || COMPILE_TEST
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -17,6 +17,7 @@ obj-$(CONFIG_GPIO_ADP5588)	+= gpio-adp55
+ obj-$(CONFIG_GPIO_AMD8111)	+= gpio-amd8111.o
+ obj-$(CONFIG_GPIO_ARIZONA)	+= gpio-arizona.o
+ obj-$(CONFIG_GPIO_BCM_KONA)	+= gpio-bcm-kona.o
++obj-$(CONFIG_GPIO_BCM6345)	+= gpio-bcm6345.o
+ obj-$(CONFIG_GPIO_BT8XX)	+= gpio-bt8xx.o
+ obj-$(CONFIG_GPIO_CLPS711X)	+= gpio-clps711x.o
+ obj-$(CONFIG_GPIO_CS5535)	+= gpio-cs5535.o
diff --git a/target/linux/brcm63xx/patches-3.18/374-GPIO-DT-add-bcm6345-driver.patch b/target/linux/brcm63xx/patches-3.18/374-GPIO-DT-add-bcm6345-driver.patch
new file mode 100644
index 0000000..690da62
--- /dev/null
+++ b/target/linux/brcm63xx/patches-3.18/374-GPIO-DT-add-bcm6345-driver.patch
@@ -0,0 +1,244 @@ 
+--- /dev/null
++++ b/drivers/gpio/gpio-bcm6345.c
+@@ -0,0 +1,216 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License.  See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
++ * Copyright (C) 2008-2011 Florian Fainelli <florian@openwrt.org>
++ * Copyright (C) 2014 Álvaro Fernández Rojas <noltari@gmail.com>
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/platform_device.h>
++#include <linux/gpio.h>
++
++enum bcm6345_gpio_reg {
++	GPIO_REG_CTL_HI = 0,
++	GPIO_REG_CTL_LO,
++	GPIO_REG_DATA_HI,
++	GPIO_REG_DATA_LO,
++	GPIO_REG_MAX
++};
++
++struct bcm6345_gpio_chip {
++	struct gpio_chip chip;
++	u8 regs[GPIO_REG_MAX];
++
++	spinlock_t lock;
++	void __iomem *membase;
++};
++
++static inline struct bcm6345_gpio_chip *to_bcm6345_gpio(struct gpio_chip *chip)
++{
++	struct bcm6345_gpio_chip *bg;
++
++	bg = container_of(chip, struct bcm6345_gpio_chip, chip);
++
++	return bg;
++}
++
++static inline u32 bc_gpio_r32(struct bcm6345_gpio_chip *bg, u8 reg)
++{
++	return ioread32be(bg->membase + bg->regs[reg]);
++}
++
++static inline void bc_gpio_w32(struct bcm6345_gpio_chip *bg, u8 reg, u32 val)
++{
++	iowrite32be(val, bg->membase + bg->regs[reg]);
++}
++
++static void bcm6345_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
++{
++	struct bcm6345_gpio_chip *bg = to_bcm6345_gpio(chip);
++	unsigned long flags;
++	u32 mask, val;
++	u8 reg;
++
++	if (gpio < 32) {
++		reg = GPIO_REG_DATA_LO;
++		mask = BIT(gpio);
++	} else {
++		reg = GPIO_REG_DATA_HI;
++		mask = BIT(gpio - 32);
++	}
++
++	spin_lock_irqsave(&bg->lock, flags);
++	val = bc_gpio_r32(bg, reg);
++	if (value)
++		val |= mask;
++	else
++		val &= ~mask;
++	bc_gpio_w32(bg, reg, val);
++	spin_unlock_irqrestore(&bg->lock, flags);
++}
++
++static int bcm6345_gpio_get(struct gpio_chip *chip, unsigned gpio)
++{
++	struct bcm6345_gpio_chip *bg = to_bcm6345_gpio(chip);
++	u32 mask;
++	u8 reg;
++
++	if (gpio < 32) {
++		reg = GPIO_REG_DATA_LO;
++		mask = BIT(gpio);
++	} else {
++		reg = GPIO_REG_DATA_HI;
++		mask = BIT(gpio - 32);
++	}
++
++	return !!(bc_gpio_r32(bg, reg) & mask);
++}
++
++static int bcm6345_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
++{
++	struct bcm6345_gpio_chip *bg = to_bcm6345_gpio(chip);
++	unsigned long flags;
++	u32 mask, val;
++	u8 reg;
++
++	if (gpio < 32) {
++		reg = GPIO_REG_CTL_LO;
++		mask = BIT(gpio);
++	} else {
++		reg = GPIO_REG_CTL_HI;
++		mask = BIT(gpio - 32);
++	}
++
++	spin_lock_irqsave(&bg->lock, flags);
++	val = bc_gpio_r32(bg, reg) & ~mask;
++	bc_gpio_w32(bg, reg, val);
++	spin_unlock_irqrestore(&bg->lock, flags);
++
++	return 0;
++}
++
++static int bcm6345_gpio_direction_output(struct gpio_chip *chip, unsigned gpio)
++{
++	struct bcm6345_gpio_chip *bg = to_bcm6345_gpio(chip);
++	unsigned long flags;
++	u32 mask, val;
++	u8 reg;
++
++	if (gpio < 32) {
++		reg = GPIO_REG_CTL_LO;
++		mask = BIT(gpio);
++	} else {
++		reg = GPIO_REG_CTL_HI;
++		mask = BIT(gpio - 32);
++	}
++
++	spin_lock_irqsave(&bg->lock, flags);
++	val = bc_gpio_r32(bg, reg) | mask;
++	bc_gpio_w32(bg, reg, val);
++	spin_unlock_irqrestore(&bg->lock, flags);
++
++	return 0;
++}
++
++int __init bcm6345_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 bcm6345_gpio_chip *bg;
++	const __be32 *ngpio, *gpiobase;
++
++	if (!res) {
++		dev_err(&pdev->dev, "failed to find resource\n");
++		return -ENOMEM;
++	}
++
++	bg = devm_kzalloc(&pdev->dev,
++			sizeof(struct gpio_chip), GFP_KERNEL);
++	if (!bg)
++		return -ENOMEM;
++
++	bg->membase = devm_ioremap_resource(&pdev->dev, res);
++	if (IS_ERR(bg->membase)) {
++		dev_err(&pdev->dev, "cannot remap I/O memory region\n");
++		return -ENOMEM;
++	}
++
++	if (of_property_read_u8_array(np, "bcm6345,register-map",
++			bg->regs, GPIO_REG_MAX)) {
++		dev_err(&pdev->dev, "failed to read register definition\n");
++		return -EINVAL;
++	}
++
++	ngpio = of_get_property(np, "bcm6345,num-gpios", NULL);
++	if (!ngpio) {
++		dev_err(&pdev->dev, "failed to read number of pins\n");
++		return -EINVAL;
++	}
++
++	gpiobase = of_get_property(np, "bcm6345,gpio-base", NULL);
++	if (gpiobase)
++		bg->chip.base = be32_to_cpu(*gpiobase);
++	else
++		bg->chip.base = -1;
++
++	spin_lock_init(&bg->lock);
++
++	bg->chip.dev = &pdev->dev;
++	bg->chip.label = dev_name(&pdev->dev);
++	bg->chip.of_node = np;
++	bg->chip.ngpio = be32_to_cpu(*ngpio);
++	bg->chip.direction_input = bcm6345_gpio_direction_input;
++	bg->chip.direction_output = bcm6345_gpio_direction_output;
++	bg->chip.get = bcm6345_gpio_get;
++	bg->chip.set = bcm6345_gpio_set;
++
++	dev_info(&pdev->dev, "registering %d gpios\n", bg->chip.ngpio);
++
++	return gpiochip_add(&bg->chip);
++}
++
++static struct of_device_id bcm6345_gpio_match[] = {
++	{ .compatible = "brcm,bcm6345-gpio" },
++	{ },
++};
++MODULE_DEVICE_TABLE(of, bcm6345_gpio_match);
++
++static struct platform_driver bcm6345_gpio_driver = {
++	.driver = {
++		.name = "bcm6345-gpio",
++		.owner = THIS_MODULE,
++		.of_match_table = bcm6345_gpio_match,
++	},
++	.probe = bcm6345_gpio_probe,
++};
++
++int __init bcm6345_gpio_init(void)
++{
++	return platform_driver_register(&bcm6345_gpio_driver);
++}
++subsys_initcall(bcm6345_gpio_init);
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -112,6 +112,12 @@ config GPIO_MAX730X
+ 
+ comment "Memory mapped GPIO drivers:"
+ 
++config GPIO_BCM6345
++	bool "Broadcom 6345 GPIO Support"
++	depends on BCM63XX
++	help
++	  Say yes here to support the Broadcom 6345 SoC GPIO device
++
+ config GPIO_CLPS711X
+ 	tristate "CLPS711X GPIO support"
+ 	depends on ARCH_CLPS711X || COMPILE_TEST
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -19,6 +19,7 @@ obj-$(CONFIG_GPIO_ADP5588)	+= gpio-adp55
+ obj-$(CONFIG_GPIO_AMD8111)	+= gpio-amd8111.o
+ obj-$(CONFIG_GPIO_ARIZONA)	+= gpio-arizona.o
+ obj-$(CONFIG_GPIO_BCM_KONA)	+= gpio-bcm-kona.o
++obj-$(CONFIG_GPIO_BCM6345)	+= gpio-bcm6345.o
+ obj-$(CONFIG_GPIO_BT8XX)	+= gpio-bt8xx.o
+ obj-$(CONFIG_GPIO_CLPS711X)	+= gpio-clps711x.o
+ obj-$(CONFIG_GPIO_CS5535)	+= gpio-cs5535.o