From: Tony Prisk <linux@prisktech.co.nz>
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 8/8] ARM: vt8500: gpio: Devicetree support for arch-vt8500
Date: Wed, 08 Aug 2012 01:39:26 +0000 [thread overview]
Message-ID: <1344389967-8465-9-git-send-email-linux@prisktech.co.nz> (raw)
In-Reply-To: <1344389967-8465-1-git-send-email-linux@prisktech.co.nz>
Converted the existing arch-vt8500 gpio to a platform_device.
Added support for WM8505 and WM8650 GPIO controllers.
Signed-off-by: Tony Prisk <linux@prisktech.co.nz>
---
drivers/gpio/Kconfig | 6 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-vt8500.c | 318 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 325 insertions(+)
create mode 100644 drivers/gpio/gpio-vt8500.c
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 542f0c0..3c8897a 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -183,6 +183,12 @@ config GPIO_STA2X11
Say yes here to support the STA2x11/ConneXt GPIO device.
The GPIO module has 128 GPIO pins with alternate functions.
+config GPIO_VT8500
+ bool "VIA/Wondermedia SoC GPIO Support"
+ depends on ARCH_VT8500
+ help
+ Say yes here to support the VT8500/WM8505/WM8650 GPIO controller.
+
config GPIO_XILINX
bool "Xilinx GPIO support"
depends on PPC_OF || MICROBLAZE
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 0f55662..2c014b9 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o
obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o
obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o
obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o
+obj-$(CONFIG_GPIO_VT8500) += gpio-vt8500.o
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o
obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c
new file mode 100644
index 0000000..3306634
--- /dev/null
+++ b/drivers/gpio/gpio-vt8500.c
@@ -0,0 +1,318 @@
+/* linux/arch/arm/mach-vt8500/gpio.c
+ *
+ * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ * Based on gpio.c:
+ * - Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+
+/*
+ We handle GPIOs by bank, each bank containing up to 32 GPIOs covered
+ by one set of registers (although not all may be valid).
+
+ Because different SoC's have different register offsets, we pass the
+ register offsets as data in vt8500_gpio_dt_ids[].
+*/
+
+struct vt8500_gpio_bank_regs {
+ int en;
+ int dir;
+ int data_out;
+ int data_in;
+ int ngpio;
+};
+
+struct vt8500_gpio_data {
+ unsigned int num_banks;
+ struct vt8500_gpio_bank_regs banks[];
+};
+
+#define VT8500_BANK(__en, __dir, __out, __in, __ngpio) \
+{ \
+ .en = __en, \
+ .dir = __dir, \
+ .data_out = __out, \
+ .data_in = __in, \
+ .ngpio = __ngpio, \
+}
+
+static struct vt8500_gpio_data vt8500_data = {
+ .num_banks = 7,
+ .banks = {
+ VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26),
+ VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28),
+ VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31),
+ VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19),
+ VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19),
+ VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23),
+ VT8500_BANK(-1, 0x3C, 0x5C, 0x7C, 9), /* external gpio */
+ },
+};
+
+static struct vt8500_gpio_data wm8505_data = {
+ .num_banks = 10,
+ .banks = {
+ VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8),
+ VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32),
+ VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6),
+ VT8500_BANK(0x4C, 0x74, 0x9C, 0xC4, 16),
+ VT8500_BANK(0x50, 0x78, 0xA0, 0xC8, 25),
+ VT8500_BANK(0x54, 0x7C, 0xA4, 0xCC, 5),
+ VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5),
+ VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12),
+ VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16),
+ VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22),
+ },
+};
+
+/*
+ * No information about which bits are valid so we just make
+ * them all available until its figured out.
+ */
+static struct vt8500_gpio_data wm8650_data = {
+ .num_banks = 9,
+ .banks = {
+ VT8500_BANK(0x40, 0x80, 0xC0, 0x00, 32),
+ VT8500_BANK(0x44, 0x84, 0xC4, 0x04, 32),
+ VT8500_BANK(0x48, 0x88, 0xC8, 0x08, 32),
+ VT8500_BANK(0x4C, 0x8C, 0xCC, 0x0C, 32),
+ VT8500_BANK(0x50, 0x90, 0xD0, 0x10, 32),
+ VT8500_BANK(0x54, 0x94, 0xD4, 0x14, 32),
+ VT8500_BANK(0x58, 0x98, 0xD8, 0x18, 32),
+ VT8500_BANK(0x5C, 0x9C, 0xDC, 0x1C, 32),
+ VT8500_BANK(0x7C, 0xBC, 0xFC, 0x3C, 32),
+ },
+};
+
+struct vt8500_gpio_chip {
+ struct gpio_chip chip;
+
+ const struct vt8500_gpio_bank_regs *regs;
+ void __iomem *base;
+ unsigned int regoff;
+};
+
+
+#define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip)
+
+static int vt8500_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ unsigned val;
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ val = readl(vt8500_chip->base + vt8500_chip->regs->en +
+ vt8500_chip->regoff);
+ val |= (1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->en +
+ vt8500_chip->regoff);
+
+ return 0;
+}
+
+static void vt8500_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ unsigned val = readl(vt8500_chip->base + vt8500_chip->regs->en +
+ vt8500_chip->regoff);
+ val &= ~(1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->en +
+ vt8500_chip->regoff);
+}
+
+static int vt8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ unsigned val = readl(vt8500_chip->base + vt8500_chip->regs->dir +
+ vt8500_chip->regoff);
+ val &= ~(1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->dir +
+ vt8500_chip->regoff);
+
+ return 0;
+}
+
+static int vt8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ unsigned val = readl(vt8500_chip->base + vt8500_chip->regs->dir +
+ vt8500_chip->regoff);
+ val |= (1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->dir +
+ vt8500_chip->regoff);
+
+ if (value) {
+ val = readl(vt8500_chip->base + vt8500_chip->regs->data_out +
+ vt8500_chip->regoff);
+ val |= (1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->data_out +
+ vt8500_chip->regoff);
+ }
+ return 0;
+}
+
+static int vt8500_gpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ return (readl(vt8500_chip->base + vt8500_chip->regoff) >> offset) & 1;
+}
+
+static void vt8500_gpio_set_value(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ unsigned val = readl(vt8500_chip->base + vt8500_chip->regs->data_out +
+ vt8500_chip->regoff);
+ if (value)
+ val |= (1 << offset);
+ else
+ val &= ~(1 << offset);
+
+ writel(val, vt8500_chip->base + vt8500_chip->regs->data_out +
+ vt8500_chip->regoff);
+}
+
+static int vt8500_of_xlate(struct gpio_chip *gc,
+ const struct of_phandle_args *gpiospec, u32 *flags)
+{
+ /* bank if specificed in gpiospec->args[0] */
+ if (flags)
+ *flags = gpiospec->args[2];
+
+ return gpiospec->args[1];
+}
+
+static int vt8500_add_chips(struct platform_device *pdev, void __iomem *base,
+ const struct vt8500_gpio_data *data)
+{
+ struct vt8500_gpio_chip *vtchip;
+ struct gpio_chip *chip;
+ int i;
+ int pin_cnt = 0;
+
+ vtchip = devm_kzalloc(&pdev->dev,
+ sizeof(struct vt8500_gpio_chip) * data->num_banks,
+ GFP_KERNEL);
+ if (!vtchip) {
+ pr_err("%s: failed to allocate chip memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < data->num_banks; i++)
+ {
+ vtchip[i].base = base;
+ vtchip[i].regs = &data->banks[i];
+ vtchip[i].regoff = i << 2;
+
+ chip = &vtchip[i].chip;
+
+ chip->of_xlate = vt8500_of_xlate;
+ chip->of_gpio_n_cells = 3;
+ chip->of_node = pdev->dev.of_node;
+
+ chip->request = vt8500_gpio_request;
+ chip->free = vt8500_gpio_free;
+ chip->direction_input = vt8500_gpio_direction_input;
+ chip->direction_output = vt8500_gpio_direction_output;
+ chip->get = vt8500_gpio_get_value;
+ chip->set = vt8500_gpio_set_value;
+ chip->can_sleep = 0;
+ chip->base = pin_cnt;
+ chip->ngpio = data->banks[i].ngpio;
+
+ pin_cnt += data->banks[i].ngpio;
+
+ gpiochip_add(chip);
+ }
+ return 0;
+}
+
+static struct of_device_id vt8500_gpio_dt_ids[] = {
+ { .compatible = "via,vt8500-gpio", .data = &vt8500_data, },
+ { .compatible = "wm,wm8505-gpio", .data = &wm8505_data, },
+ { .compatible = "wm,wm8650-gpio", .data = &wm8650_data, },
+ { /* Sentinel */ },
+};
+
+static int __devinit vt8500_gpio_probe(struct platform_device *pdev)
+{
+ void __iomem *gpio_base;
+ struct device_node *np;
+ const struct of_device_id *of_id + of_match_device(vt8500_gpio_dt_ids, &pdev->dev);
+
+ if (!of_id) {
+ dev_err(&pdev->dev, "Failed to find gpio controller\n");
+ return -ENODEV;
+ }
+
+ np = of_find_matching_node(NULL, vt8500_gpio_dt_ids);
+ if (!np) {
+ dev_err(&pdev->dev, "Missing GPIO description in devicetree\n");
+ return -EFAULT;
+ }
+
+ gpio_base = of_iomap(np, 0);
+ if (!gpio_base) {
+ dev_err(&pdev->dev, "Unable to map GPIO registers\n");
+ of_node_put(np);
+ return -ENOMEM;
+ }
+
+ of_node_put(np);
+
+ vt8500_add_chips(pdev, gpio_base, of_id->data);
+
+ return 0;
+}
+
+static struct platform_driver vt8500_gpio_driver = {
+ .probe = vt8500_gpio_probe,
+ .driver = {
+ .name = "vt8500-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = vt8500_gpio_dt_ids,
+ },
+};
+
+static int __init vt8500_gpio_init(void)
+{
+ return platform_driver_probe(&vt8500_gpio_driver, &vt8500_gpio_probe);
+}
+
+static void __exit vt8500_gpio_exit(void)
+{
+ return platform_driver_unregister(&vt8500_gpio_driver);
+}
+
+module_init(vt8500_gpio_init);
+module_exit(vt8500_gpio_exit);
+
+MODULE_DESCRIPTION("VT8500 GPIO Driver");
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, vt8500_gpio_dt_ids);
--
1.7.9.5
WARNING: multiple messages have this Message-ID (diff)
From: Tony Prisk <linux@prisktech.co.nz>
To: vt8500-wm8505-linux-kernel@googlegroups.com
Cc: Tony Prisk <linux@prisktech.co.nz>,
Russell King <linux@arm.linux.org.uk>,
Arnd Bergmann <arnd@arndb.de>,
Alessandro Zummo <a.zummo@towertech.it>,
Grant Likely <grant.likely@secretlab.ca>,
Rob Herring <rob.herring@calxeda.com>,
Alan Cox <alan@linux.intel.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Alan Stern <stern@rowland.harvard.edu>,
Hauke Mehrtens <hauke@hauke-m.de>, Felipe Balbi <balbi@ti.com>,
Neil Zhang <zhangwm@marvell.com>,
Florian Tobias Schandinat <FlorianSchandinat@gmx.de>,
Rob Landley <rob@landley.net>,
Mark Brown <broonie@opensource.wolfsonmicro.com>,
Stephen Warren <swarren@nvidia.com>,
Eric Andersson <eric.andersson@unixphere.com>,
Linus Walleij <linus.walleij@stericsson.com>,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org,
linux-fbdev@vger.kernel.org, linux-usb@vger.kernel.org,
linux-serial@
Subject: [PATCH 8/8] ARM: vt8500: gpio: Devicetree support for arch-vt8500
Date: Wed, 8 Aug 2012 13:39:26 +1200 [thread overview]
Message-ID: <1344389967-8465-9-git-send-email-linux@prisktech.co.nz> (raw)
In-Reply-To: <1344389967-8465-1-git-send-email-linux@prisktech.co.nz>
Converted the existing arch-vt8500 gpio to a platform_device.
Added support for WM8505 and WM8650 GPIO controllers.
Signed-off-by: Tony Prisk <linux@prisktech.co.nz>
---
drivers/gpio/Kconfig | 6 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-vt8500.c | 318 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 325 insertions(+)
create mode 100644 drivers/gpio/gpio-vt8500.c
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 542f0c0..3c8897a 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -183,6 +183,12 @@ config GPIO_STA2X11
Say yes here to support the STA2x11/ConneXt GPIO device.
The GPIO module has 128 GPIO pins with alternate functions.
+config GPIO_VT8500
+ bool "VIA/Wondermedia SoC GPIO Support"
+ depends on ARCH_VT8500
+ help
+ Say yes here to support the VT8500/WM8505/WM8650 GPIO controller.
+
config GPIO_XILINX
bool "Xilinx GPIO support"
depends on PPC_OF || MICROBLAZE
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 0f55662..2c014b9 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o
obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o
obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o
obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o
+obj-$(CONFIG_GPIO_VT8500) += gpio-vt8500.o
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o
obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c
new file mode 100644
index 0000000..3306634
--- /dev/null
+++ b/drivers/gpio/gpio-vt8500.c
@@ -0,0 +1,318 @@
+/* linux/arch/arm/mach-vt8500/gpio.c
+ *
+ * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ * Based on gpio.c:
+ * - Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+
+/*
+ We handle GPIOs by bank, each bank containing up to 32 GPIOs covered
+ by one set of registers (although not all may be valid).
+
+ Because different SoC's have different register offsets, we pass the
+ register offsets as data in vt8500_gpio_dt_ids[].
+*/
+
+struct vt8500_gpio_bank_regs {
+ int en;
+ int dir;
+ int data_out;
+ int data_in;
+ int ngpio;
+};
+
+struct vt8500_gpio_data {
+ unsigned int num_banks;
+ struct vt8500_gpio_bank_regs banks[];
+};
+
+#define VT8500_BANK(__en, __dir, __out, __in, __ngpio) \
+{ \
+ .en = __en, \
+ .dir = __dir, \
+ .data_out = __out, \
+ .data_in = __in, \
+ .ngpio = __ngpio, \
+}
+
+static struct vt8500_gpio_data vt8500_data = {
+ .num_banks = 7,
+ .banks = {
+ VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26),
+ VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28),
+ VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31),
+ VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19),
+ VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19),
+ VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23),
+ VT8500_BANK(-1, 0x3C, 0x5C, 0x7C, 9), /* external gpio */
+ },
+};
+
+static struct vt8500_gpio_data wm8505_data = {
+ .num_banks = 10,
+ .banks = {
+ VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8),
+ VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32),
+ VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6),
+ VT8500_BANK(0x4C, 0x74, 0x9C, 0xC4, 16),
+ VT8500_BANK(0x50, 0x78, 0xA0, 0xC8, 25),
+ VT8500_BANK(0x54, 0x7C, 0xA4, 0xCC, 5),
+ VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5),
+ VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12),
+ VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16),
+ VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22),
+ },
+};
+
+/*
+ * No information about which bits are valid so we just make
+ * them all available until its figured out.
+ */
+static struct vt8500_gpio_data wm8650_data = {
+ .num_banks = 9,
+ .banks = {
+ VT8500_BANK(0x40, 0x80, 0xC0, 0x00, 32),
+ VT8500_BANK(0x44, 0x84, 0xC4, 0x04, 32),
+ VT8500_BANK(0x48, 0x88, 0xC8, 0x08, 32),
+ VT8500_BANK(0x4C, 0x8C, 0xCC, 0x0C, 32),
+ VT8500_BANK(0x50, 0x90, 0xD0, 0x10, 32),
+ VT8500_BANK(0x54, 0x94, 0xD4, 0x14, 32),
+ VT8500_BANK(0x58, 0x98, 0xD8, 0x18, 32),
+ VT8500_BANK(0x5C, 0x9C, 0xDC, 0x1C, 32),
+ VT8500_BANK(0x7C, 0xBC, 0xFC, 0x3C, 32),
+ },
+};
+
+struct vt8500_gpio_chip {
+ struct gpio_chip chip;
+
+ const struct vt8500_gpio_bank_regs *regs;
+ void __iomem *base;
+ unsigned int regoff;
+};
+
+
+#define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip)
+
+static int vt8500_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ unsigned val;
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ val = readl(vt8500_chip->base + vt8500_chip->regs->en +
+ vt8500_chip->regoff);
+ val |= (1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->en +
+ vt8500_chip->regoff);
+
+ return 0;
+}
+
+static void vt8500_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ unsigned val = readl(vt8500_chip->base + vt8500_chip->regs->en +
+ vt8500_chip->regoff);
+ val &= ~(1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->en +
+ vt8500_chip->regoff);
+}
+
+static int vt8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ unsigned val = readl(vt8500_chip->base + vt8500_chip->regs->dir +
+ vt8500_chip->regoff);
+ val &= ~(1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->dir +
+ vt8500_chip->regoff);
+
+ return 0;
+}
+
+static int vt8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ unsigned val = readl(vt8500_chip->base + vt8500_chip->regs->dir +
+ vt8500_chip->regoff);
+ val |= (1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->dir +
+ vt8500_chip->regoff);
+
+ if (value) {
+ val = readl(vt8500_chip->base + vt8500_chip->regs->data_out +
+ vt8500_chip->regoff);
+ val |= (1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->data_out +
+ vt8500_chip->regoff);
+ }
+ return 0;
+}
+
+static int vt8500_gpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ return (readl(vt8500_chip->base + vt8500_chip->regoff) >> offset) & 1;
+}
+
+static void vt8500_gpio_set_value(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ unsigned val = readl(vt8500_chip->base + vt8500_chip->regs->data_out +
+ vt8500_chip->regoff);
+ if (value)
+ val |= (1 << offset);
+ else
+ val &= ~(1 << offset);
+
+ writel(val, vt8500_chip->base + vt8500_chip->regs->data_out +
+ vt8500_chip->regoff);
+}
+
+static int vt8500_of_xlate(struct gpio_chip *gc,
+ const struct of_phandle_args *gpiospec, u32 *flags)
+{
+ /* bank if specificed in gpiospec->args[0] */
+ if (flags)
+ *flags = gpiospec->args[2];
+
+ return gpiospec->args[1];
+}
+
+static int vt8500_add_chips(struct platform_device *pdev, void __iomem *base,
+ const struct vt8500_gpio_data *data)
+{
+ struct vt8500_gpio_chip *vtchip;
+ struct gpio_chip *chip;
+ int i;
+ int pin_cnt = 0;
+
+ vtchip = devm_kzalloc(&pdev->dev,
+ sizeof(struct vt8500_gpio_chip) * data->num_banks,
+ GFP_KERNEL);
+ if (!vtchip) {
+ pr_err("%s: failed to allocate chip memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < data->num_banks; i++)
+ {
+ vtchip[i].base = base;
+ vtchip[i].regs = &data->banks[i];
+ vtchip[i].regoff = i << 2;
+
+ chip = &vtchip[i].chip;
+
+ chip->of_xlate = vt8500_of_xlate;
+ chip->of_gpio_n_cells = 3;
+ chip->of_node = pdev->dev.of_node;
+
+ chip->request = vt8500_gpio_request;
+ chip->free = vt8500_gpio_free;
+ chip->direction_input = vt8500_gpio_direction_input;
+ chip->direction_output = vt8500_gpio_direction_output;
+ chip->get = vt8500_gpio_get_value;
+ chip->set = vt8500_gpio_set_value;
+ chip->can_sleep = 0;
+ chip->base = pin_cnt;
+ chip->ngpio = data->banks[i].ngpio;
+
+ pin_cnt += data->banks[i].ngpio;
+
+ gpiochip_add(chip);
+ }
+ return 0;
+}
+
+static struct of_device_id vt8500_gpio_dt_ids[] = {
+ { .compatible = "via,vt8500-gpio", .data = &vt8500_data, },
+ { .compatible = "wm,wm8505-gpio", .data = &wm8505_data, },
+ { .compatible = "wm,wm8650-gpio", .data = &wm8650_data, },
+ { /* Sentinel */ },
+};
+
+static int __devinit vt8500_gpio_probe(struct platform_device *pdev)
+{
+ void __iomem *gpio_base;
+ struct device_node *np;
+ const struct of_device_id *of_id =
+ of_match_device(vt8500_gpio_dt_ids, &pdev->dev);
+
+ if (!of_id) {
+ dev_err(&pdev->dev, "Failed to find gpio controller\n");
+ return -ENODEV;
+ }
+
+ np = of_find_matching_node(NULL, vt8500_gpio_dt_ids);
+ if (!np) {
+ dev_err(&pdev->dev, "Missing GPIO description in devicetree\n");
+ return -EFAULT;
+ }
+
+ gpio_base = of_iomap(np, 0);
+ if (!gpio_base) {
+ dev_err(&pdev->dev, "Unable to map GPIO registers\n");
+ of_node_put(np);
+ return -ENOMEM;
+ }
+
+ of_node_put(np);
+
+ vt8500_add_chips(pdev, gpio_base, of_id->data);
+
+ return 0;
+}
+
+static struct platform_driver vt8500_gpio_driver = {
+ .probe = vt8500_gpio_probe,
+ .driver = {
+ .name = "vt8500-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = vt8500_gpio_dt_ids,
+ },
+};
+
+static int __init vt8500_gpio_init(void)
+{
+ return platform_driver_probe(&vt8500_gpio_driver, &vt8500_gpio_probe);
+}
+
+static void __exit vt8500_gpio_exit(void)
+{
+ return platform_driver_unregister(&vt8500_gpio_driver);
+}
+
+module_init(vt8500_gpio_init);
+module_exit(vt8500_gpio_exit);
+
+MODULE_DESCRIPTION("VT8500 GPIO Driver");
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, vt8500_gpio_dt_ids);
--
1.7.9.5
WARNING: multiple messages have this Message-ID (diff)
From: linux@prisktech.co.nz (Tony Prisk)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 8/8] ARM: vt8500: gpio: Devicetree support for arch-vt8500
Date: Wed, 8 Aug 2012 13:39:26 +1200 [thread overview]
Message-ID: <1344389967-8465-9-git-send-email-linux@prisktech.co.nz> (raw)
In-Reply-To: <1344389967-8465-1-git-send-email-linux@prisktech.co.nz>
Converted the existing arch-vt8500 gpio to a platform_device.
Added support for WM8505 and WM8650 GPIO controllers.
Signed-off-by: Tony Prisk <linux@prisktech.co.nz>
---
drivers/gpio/Kconfig | 6 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-vt8500.c | 318 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 325 insertions(+)
create mode 100644 drivers/gpio/gpio-vt8500.c
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 542f0c0..3c8897a 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -183,6 +183,12 @@ config GPIO_STA2X11
Say yes here to support the STA2x11/ConneXt GPIO device.
The GPIO module has 128 GPIO pins with alternate functions.
+config GPIO_VT8500
+ bool "VIA/Wondermedia SoC GPIO Support"
+ depends on ARCH_VT8500
+ help
+ Say yes here to support the VT8500/WM8505/WM8650 GPIO controller.
+
config GPIO_XILINX
bool "Xilinx GPIO support"
depends on PPC_OF || MICROBLAZE
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 0f55662..2c014b9 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o
obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o
obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o
obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o
+obj-$(CONFIG_GPIO_VT8500) += gpio-vt8500.o
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o
obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c
new file mode 100644
index 0000000..3306634
--- /dev/null
+++ b/drivers/gpio/gpio-vt8500.c
@@ -0,0 +1,318 @@
+/* linux/arch/arm/mach-vt8500/gpio.c
+ *
+ * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ * Based on gpio.c:
+ * - Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+
+/*
+ We handle GPIOs by bank, each bank containing up to 32 GPIOs covered
+ by one set of registers (although not all may be valid).
+
+ Because different SoC's have different register offsets, we pass the
+ register offsets as data in vt8500_gpio_dt_ids[].
+*/
+
+struct vt8500_gpio_bank_regs {
+ int en;
+ int dir;
+ int data_out;
+ int data_in;
+ int ngpio;
+};
+
+struct vt8500_gpio_data {
+ unsigned int num_banks;
+ struct vt8500_gpio_bank_regs banks[];
+};
+
+#define VT8500_BANK(__en, __dir, __out, __in, __ngpio) \
+{ \
+ .en = __en, \
+ .dir = __dir, \
+ .data_out = __out, \
+ .data_in = __in, \
+ .ngpio = __ngpio, \
+}
+
+static struct vt8500_gpio_data vt8500_data = {
+ .num_banks = 7,
+ .banks = {
+ VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26),
+ VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28),
+ VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31),
+ VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19),
+ VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19),
+ VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23),
+ VT8500_BANK(-1, 0x3C, 0x5C, 0x7C, 9), /* external gpio */
+ },
+};
+
+static struct vt8500_gpio_data wm8505_data = {
+ .num_banks = 10,
+ .banks = {
+ VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8),
+ VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32),
+ VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6),
+ VT8500_BANK(0x4C, 0x74, 0x9C, 0xC4, 16),
+ VT8500_BANK(0x50, 0x78, 0xA0, 0xC8, 25),
+ VT8500_BANK(0x54, 0x7C, 0xA4, 0xCC, 5),
+ VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5),
+ VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12),
+ VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16),
+ VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22),
+ },
+};
+
+/*
+ * No information about which bits are valid so we just make
+ * them all available until its figured out.
+ */
+static struct vt8500_gpio_data wm8650_data = {
+ .num_banks = 9,
+ .banks = {
+ VT8500_BANK(0x40, 0x80, 0xC0, 0x00, 32),
+ VT8500_BANK(0x44, 0x84, 0xC4, 0x04, 32),
+ VT8500_BANK(0x48, 0x88, 0xC8, 0x08, 32),
+ VT8500_BANK(0x4C, 0x8C, 0xCC, 0x0C, 32),
+ VT8500_BANK(0x50, 0x90, 0xD0, 0x10, 32),
+ VT8500_BANK(0x54, 0x94, 0xD4, 0x14, 32),
+ VT8500_BANK(0x58, 0x98, 0xD8, 0x18, 32),
+ VT8500_BANK(0x5C, 0x9C, 0xDC, 0x1C, 32),
+ VT8500_BANK(0x7C, 0xBC, 0xFC, 0x3C, 32),
+ },
+};
+
+struct vt8500_gpio_chip {
+ struct gpio_chip chip;
+
+ const struct vt8500_gpio_bank_regs *regs;
+ void __iomem *base;
+ unsigned int regoff;
+};
+
+
+#define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip)
+
+static int vt8500_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ unsigned val;
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ val = readl(vt8500_chip->base + vt8500_chip->regs->en +
+ vt8500_chip->regoff);
+ val |= (1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->en +
+ vt8500_chip->regoff);
+
+ return 0;
+}
+
+static void vt8500_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ unsigned val = readl(vt8500_chip->base + vt8500_chip->regs->en +
+ vt8500_chip->regoff);
+ val &= ~(1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->en +
+ vt8500_chip->regoff);
+}
+
+static int vt8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ unsigned val = readl(vt8500_chip->base + vt8500_chip->regs->dir +
+ vt8500_chip->regoff);
+ val &= ~(1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->dir +
+ vt8500_chip->regoff);
+
+ return 0;
+}
+
+static int vt8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ unsigned val = readl(vt8500_chip->base + vt8500_chip->regs->dir +
+ vt8500_chip->regoff);
+ val |= (1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->dir +
+ vt8500_chip->regoff);
+
+ if (value) {
+ val = readl(vt8500_chip->base + vt8500_chip->regs->data_out +
+ vt8500_chip->regoff);
+ val |= (1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->data_out +
+ vt8500_chip->regoff);
+ }
+ return 0;
+}
+
+static int vt8500_gpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ return (readl(vt8500_chip->base + vt8500_chip->regoff) >> offset) & 1;
+}
+
+static void vt8500_gpio_set_value(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ unsigned val = readl(vt8500_chip->base + vt8500_chip->regs->data_out +
+ vt8500_chip->regoff);
+ if (value)
+ val |= (1 << offset);
+ else
+ val &= ~(1 << offset);
+
+ writel(val, vt8500_chip->base + vt8500_chip->regs->data_out +
+ vt8500_chip->regoff);
+}
+
+static int vt8500_of_xlate(struct gpio_chip *gc,
+ const struct of_phandle_args *gpiospec, u32 *flags)
+{
+ /* bank if specificed in gpiospec->args[0] */
+ if (flags)
+ *flags = gpiospec->args[2];
+
+ return gpiospec->args[1];
+}
+
+static int vt8500_add_chips(struct platform_device *pdev, void __iomem *base,
+ const struct vt8500_gpio_data *data)
+{
+ struct vt8500_gpio_chip *vtchip;
+ struct gpio_chip *chip;
+ int i;
+ int pin_cnt = 0;
+
+ vtchip = devm_kzalloc(&pdev->dev,
+ sizeof(struct vt8500_gpio_chip) * data->num_banks,
+ GFP_KERNEL);
+ if (!vtchip) {
+ pr_err("%s: failed to allocate chip memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < data->num_banks; i++)
+ {
+ vtchip[i].base = base;
+ vtchip[i].regs = &data->banks[i];
+ vtchip[i].regoff = i << 2;
+
+ chip = &vtchip[i].chip;
+
+ chip->of_xlate = vt8500_of_xlate;
+ chip->of_gpio_n_cells = 3;
+ chip->of_node = pdev->dev.of_node;
+
+ chip->request = vt8500_gpio_request;
+ chip->free = vt8500_gpio_free;
+ chip->direction_input = vt8500_gpio_direction_input;
+ chip->direction_output = vt8500_gpio_direction_output;
+ chip->get = vt8500_gpio_get_value;
+ chip->set = vt8500_gpio_set_value;
+ chip->can_sleep = 0;
+ chip->base = pin_cnt;
+ chip->ngpio = data->banks[i].ngpio;
+
+ pin_cnt += data->banks[i].ngpio;
+
+ gpiochip_add(chip);
+ }
+ return 0;
+}
+
+static struct of_device_id vt8500_gpio_dt_ids[] = {
+ { .compatible = "via,vt8500-gpio", .data = &vt8500_data, },
+ { .compatible = "wm,wm8505-gpio", .data = &wm8505_data, },
+ { .compatible = "wm,wm8650-gpio", .data = &wm8650_data, },
+ { /* Sentinel */ },
+};
+
+static int __devinit vt8500_gpio_probe(struct platform_device *pdev)
+{
+ void __iomem *gpio_base;
+ struct device_node *np;
+ const struct of_device_id *of_id =
+ of_match_device(vt8500_gpio_dt_ids, &pdev->dev);
+
+ if (!of_id) {
+ dev_err(&pdev->dev, "Failed to find gpio controller\n");
+ return -ENODEV;
+ }
+
+ np = of_find_matching_node(NULL, vt8500_gpio_dt_ids);
+ if (!np) {
+ dev_err(&pdev->dev, "Missing GPIO description in devicetree\n");
+ return -EFAULT;
+ }
+
+ gpio_base = of_iomap(np, 0);
+ if (!gpio_base) {
+ dev_err(&pdev->dev, "Unable to map GPIO registers\n");
+ of_node_put(np);
+ return -ENOMEM;
+ }
+
+ of_node_put(np);
+
+ vt8500_add_chips(pdev, gpio_base, of_id->data);
+
+ return 0;
+}
+
+static struct platform_driver vt8500_gpio_driver = {
+ .probe = vt8500_gpio_probe,
+ .driver = {
+ .name = "vt8500-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = vt8500_gpio_dt_ids,
+ },
+};
+
+static int __init vt8500_gpio_init(void)
+{
+ return platform_driver_probe(&vt8500_gpio_driver, &vt8500_gpio_probe);
+}
+
+static void __exit vt8500_gpio_exit(void)
+{
+ return platform_driver_unregister(&vt8500_gpio_driver);
+}
+
+module_init(vt8500_gpio_init);
+module_exit(vt8500_gpio_exit);
+
+MODULE_DESCRIPTION("VT8500 GPIO Driver");
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, vt8500_gpio_dt_ids);
--
1.7.9.5
WARNING: multiple messages have this Message-ID (diff)
From: Tony Prisk <linux@prisktech.co.nz>
To: vt8500-wm8505-linux-kernel@googlegroups.com
Cc: Tony Prisk <linux@prisktech.co.nz>,
Russell King <linux@arm.linux.org.uk>,
Arnd Bergmann <arnd@arndb.de>,
Alessandro Zummo <a.zummo@towertech.it>,
Grant Likely <grant.likely@secretlab.ca>,
Rob Herring <rob.herring@calxeda.com>,
Alan Cox <alan@linux.intel.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Alan Stern <stern@rowland.harvard.edu>,
Hauke Mehrtens <hauke@hauke-m.de>, Felipe Balbi <balbi@ti.com>,
Neil Zhang <zhangwm@marvell.com>,
Florian Tobias Schandinat <FlorianSchandinat@gmx.de>,
Rob Landley <rob@landley.net>,
Mark Brown <broonie@opensource.wolfsonmicro.com>,
Stephen Warren <swarren@nvidia.com>,
Eric Andersson <eric.andersson@unixphere.com>,
Linus Walleij <linus.walleij@stericsson.com>,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org,
linux-fbdev@vger.kernel.org, linux-usb@vger.kernel.org,
linux-serial@vger.kernel.org, rtc-linux@googlegroups.com,
devicetree-discuss@lists.ozlabs.org
Subject: [PATCH 8/8] ARM: vt8500: gpio: Devicetree support for arch-vt8500
Date: Wed, 8 Aug 2012 13:39:26 +1200 [thread overview]
Message-ID: <1344389967-8465-9-git-send-email-linux@prisktech.co.nz> (raw)
In-Reply-To: <1344389967-8465-1-git-send-email-linux@prisktech.co.nz>
Converted the existing arch-vt8500 gpio to a platform_device.
Added support for WM8505 and WM8650 GPIO controllers.
Signed-off-by: Tony Prisk <linux@prisktech.co.nz>
---
drivers/gpio/Kconfig | 6 +
drivers/gpio/Makefile | 1 +
drivers/gpio/gpio-vt8500.c | 318 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 325 insertions(+)
create mode 100644 drivers/gpio/gpio-vt8500.c
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 542f0c0..3c8897a 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -183,6 +183,12 @@ config GPIO_STA2X11
Say yes here to support the STA2x11/ConneXt GPIO device.
The GPIO module has 128 GPIO pins with alternate functions.
+config GPIO_VT8500
+ bool "VIA/Wondermedia SoC GPIO Support"
+ depends on ARCH_VT8500
+ help
+ Say yes here to support the VT8500/WM8505/WM8650 GPIO controller.
+
config GPIO_XILINX
bool "Xilinx GPIO support"
depends on PPC_OF || MICROBLAZE
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 0f55662..2c014b9 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -66,6 +66,7 @@ obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o
obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o
obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o
obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o
+obj-$(CONFIG_GPIO_VT8500) += gpio-vt8500.o
obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o
obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o
obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
diff --git a/drivers/gpio/gpio-vt8500.c b/drivers/gpio/gpio-vt8500.c
new file mode 100644
index 0000000..3306634
--- /dev/null
+++ b/drivers/gpio/gpio-vt8500.c
@@ -0,0 +1,318 @@
+/* linux/arch/arm/mach-vt8500/gpio.c
+ *
+ * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
+ * Based on gpio.c:
+ * - Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+
+/*
+ We handle GPIOs by bank, each bank containing up to 32 GPIOs covered
+ by one set of registers (although not all may be valid).
+
+ Because different SoC's have different register offsets, we pass the
+ register offsets as data in vt8500_gpio_dt_ids[].
+*/
+
+struct vt8500_gpio_bank_regs {
+ int en;
+ int dir;
+ int data_out;
+ int data_in;
+ int ngpio;
+};
+
+struct vt8500_gpio_data {
+ unsigned int num_banks;
+ struct vt8500_gpio_bank_regs banks[];
+};
+
+#define VT8500_BANK(__en, __dir, __out, __in, __ngpio) \
+{ \
+ .en = __en, \
+ .dir = __dir, \
+ .data_out = __out, \
+ .data_in = __in, \
+ .ngpio = __ngpio, \
+}
+
+static struct vt8500_gpio_data vt8500_data = {
+ .num_banks = 7,
+ .banks = {
+ VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26),
+ VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28),
+ VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31),
+ VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19),
+ VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19),
+ VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23),
+ VT8500_BANK(-1, 0x3C, 0x5C, 0x7C, 9), /* external gpio */
+ },
+};
+
+static struct vt8500_gpio_data wm8505_data = {
+ .num_banks = 10,
+ .banks = {
+ VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8),
+ VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32),
+ VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6),
+ VT8500_BANK(0x4C, 0x74, 0x9C, 0xC4, 16),
+ VT8500_BANK(0x50, 0x78, 0xA0, 0xC8, 25),
+ VT8500_BANK(0x54, 0x7C, 0xA4, 0xCC, 5),
+ VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5),
+ VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12),
+ VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16),
+ VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22),
+ },
+};
+
+/*
+ * No information about which bits are valid so we just make
+ * them all available until its figured out.
+ */
+static struct vt8500_gpio_data wm8650_data = {
+ .num_banks = 9,
+ .banks = {
+ VT8500_BANK(0x40, 0x80, 0xC0, 0x00, 32),
+ VT8500_BANK(0x44, 0x84, 0xC4, 0x04, 32),
+ VT8500_BANK(0x48, 0x88, 0xC8, 0x08, 32),
+ VT8500_BANK(0x4C, 0x8C, 0xCC, 0x0C, 32),
+ VT8500_BANK(0x50, 0x90, 0xD0, 0x10, 32),
+ VT8500_BANK(0x54, 0x94, 0xD4, 0x14, 32),
+ VT8500_BANK(0x58, 0x98, 0xD8, 0x18, 32),
+ VT8500_BANK(0x5C, 0x9C, 0xDC, 0x1C, 32),
+ VT8500_BANK(0x7C, 0xBC, 0xFC, 0x3C, 32),
+ },
+};
+
+struct vt8500_gpio_chip {
+ struct gpio_chip chip;
+
+ const struct vt8500_gpio_bank_regs *regs;
+ void __iomem *base;
+ unsigned int regoff;
+};
+
+
+#define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip)
+
+static int vt8500_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ unsigned val;
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ val = readl(vt8500_chip->base + vt8500_chip->regs->en +
+ vt8500_chip->regoff);
+ val |= (1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->en +
+ vt8500_chip->regoff);
+
+ return 0;
+}
+
+static void vt8500_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ unsigned val = readl(vt8500_chip->base + vt8500_chip->regs->en +
+ vt8500_chip->regoff);
+ val &= ~(1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->en +
+ vt8500_chip->regoff);
+}
+
+static int vt8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ unsigned val = readl(vt8500_chip->base + vt8500_chip->regs->dir +
+ vt8500_chip->regoff);
+ val &= ~(1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->dir +
+ vt8500_chip->regoff);
+
+ return 0;
+}
+
+static int vt8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ unsigned val = readl(vt8500_chip->base + vt8500_chip->regs->dir +
+ vt8500_chip->regoff);
+ val |= (1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->dir +
+ vt8500_chip->regoff);
+
+ if (value) {
+ val = readl(vt8500_chip->base + vt8500_chip->regs->data_out +
+ vt8500_chip->regoff);
+ val |= (1 << offset);
+ writel(val, vt8500_chip->base + vt8500_chip->regs->data_out +
+ vt8500_chip->regoff);
+ }
+ return 0;
+}
+
+static int vt8500_gpio_get_value(struct gpio_chip *chip, unsigned offset)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ return (readl(vt8500_chip->base + vt8500_chip->regoff) >> offset) & 1;
+}
+
+static void vt8500_gpio_set_value(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
+
+ unsigned val = readl(vt8500_chip->base + vt8500_chip->regs->data_out +
+ vt8500_chip->regoff);
+ if (value)
+ val |= (1 << offset);
+ else
+ val &= ~(1 << offset);
+
+ writel(val, vt8500_chip->base + vt8500_chip->regs->data_out +
+ vt8500_chip->regoff);
+}
+
+static int vt8500_of_xlate(struct gpio_chip *gc,
+ const struct of_phandle_args *gpiospec, u32 *flags)
+{
+ /* bank if specificed in gpiospec->args[0] */
+ if (flags)
+ *flags = gpiospec->args[2];
+
+ return gpiospec->args[1];
+}
+
+static int vt8500_add_chips(struct platform_device *pdev, void __iomem *base,
+ const struct vt8500_gpio_data *data)
+{
+ struct vt8500_gpio_chip *vtchip;
+ struct gpio_chip *chip;
+ int i;
+ int pin_cnt = 0;
+
+ vtchip = devm_kzalloc(&pdev->dev,
+ sizeof(struct vt8500_gpio_chip) * data->num_banks,
+ GFP_KERNEL);
+ if (!vtchip) {
+ pr_err("%s: failed to allocate chip memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < data->num_banks; i++)
+ {
+ vtchip[i].base = base;
+ vtchip[i].regs = &data->banks[i];
+ vtchip[i].regoff = i << 2;
+
+ chip = &vtchip[i].chip;
+
+ chip->of_xlate = vt8500_of_xlate;
+ chip->of_gpio_n_cells = 3;
+ chip->of_node = pdev->dev.of_node;
+
+ chip->request = vt8500_gpio_request;
+ chip->free = vt8500_gpio_free;
+ chip->direction_input = vt8500_gpio_direction_input;
+ chip->direction_output = vt8500_gpio_direction_output;
+ chip->get = vt8500_gpio_get_value;
+ chip->set = vt8500_gpio_set_value;
+ chip->can_sleep = 0;
+ chip->base = pin_cnt;
+ chip->ngpio = data->banks[i].ngpio;
+
+ pin_cnt += data->banks[i].ngpio;
+
+ gpiochip_add(chip);
+ }
+ return 0;
+}
+
+static struct of_device_id vt8500_gpio_dt_ids[] = {
+ { .compatible = "via,vt8500-gpio", .data = &vt8500_data, },
+ { .compatible = "wm,wm8505-gpio", .data = &wm8505_data, },
+ { .compatible = "wm,wm8650-gpio", .data = &wm8650_data, },
+ { /* Sentinel */ },
+};
+
+static int __devinit vt8500_gpio_probe(struct platform_device *pdev)
+{
+ void __iomem *gpio_base;
+ struct device_node *np;
+ const struct of_device_id *of_id =
+ of_match_device(vt8500_gpio_dt_ids, &pdev->dev);
+
+ if (!of_id) {
+ dev_err(&pdev->dev, "Failed to find gpio controller\n");
+ return -ENODEV;
+ }
+
+ np = of_find_matching_node(NULL, vt8500_gpio_dt_ids);
+ if (!np) {
+ dev_err(&pdev->dev, "Missing GPIO description in devicetree\n");
+ return -EFAULT;
+ }
+
+ gpio_base = of_iomap(np, 0);
+ if (!gpio_base) {
+ dev_err(&pdev->dev, "Unable to map GPIO registers\n");
+ of_node_put(np);
+ return -ENOMEM;
+ }
+
+ of_node_put(np);
+
+ vt8500_add_chips(pdev, gpio_base, of_id->data);
+
+ return 0;
+}
+
+static struct platform_driver vt8500_gpio_driver = {
+ .probe = vt8500_gpio_probe,
+ .driver = {
+ .name = "vt8500-gpio",
+ .owner = THIS_MODULE,
+ .of_match_table = vt8500_gpio_dt_ids,
+ },
+};
+
+static int __init vt8500_gpio_init(void)
+{
+ return platform_driver_probe(&vt8500_gpio_driver, &vt8500_gpio_probe);
+}
+
+static void __exit vt8500_gpio_exit(void)
+{
+ return platform_driver_unregister(&vt8500_gpio_driver);
+}
+
+module_init(vt8500_gpio_init);
+module_exit(vt8500_gpio_exit);
+
+MODULE_DESCRIPTION("VT8500 GPIO Driver");
+MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(of, vt8500_gpio_dt_ids);
--
1.7.9.5
next prev parent reply other threads:[~2012-08-08 1:39 UTC|newest]
Thread overview: 79+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-08-08 1:39 [PATCH 0/8] *** ARM: Update arch-vt8500 to Devicetree *** Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` [PATCH 1/8] arm: vt8500: Add device tree files for VIA/Wondermedia SoC's Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 18:43 ` Stephen Warren
2012-08-08 18:43 ` Stephen Warren
2012-08-08 18:43 ` Stephen Warren
[not found] ` <5022B342.7080606-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2012-08-08 20:08 ` Tony Prisk
2012-08-08 20:08 ` Tony Prisk
2012-08-08 1:39 ` [PATCH 2/8] rtc: vt8500: Add devicetree support for vt8500-rtc Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` [PATCH 3/8] serial: vt8500: Add devicetree support for vt8500-serial Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` [PATCH 4/8] usb: vt8500: Add devicetree support for vt8500-ehci and -uhci Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` [PATCH 5/8] video: vt8500: Add devicetree support for vt8500-fb and wm8505-fb Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 18:47 ` Stephen Warren
2012-08-08 18:47 ` Stephen Warren
2012-08-08 18:47 ` Stephen Warren
[not found] ` <5022B444.2020501-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2012-08-08 19:37 ` Tony Prisk
2012-08-08 19:37 ` Tony Prisk
[not found] ` <76F764B079F92A4E843589C893D0A022D1DCA8D0-A1+cU8XkcJSYgi1/3OOQJ8krCUz0bFs7@public.gmane.org>
2012-08-15 19:21 ` Stephen Warren
2012-08-15 19:21 ` Stephen Warren
2012-08-08 1:39 ` [PATCH 6/8] arm: vt8500: Update arch-vt8500 to devicetree support Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 18:58 ` Stephen Warren
2012-08-08 18:58 ` Stephen Warren
2012-08-08 18:58 ` Stephen Warren
[not found] ` <5022B6EE.7060006-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>
2012-08-08 19:37 ` Tony Prisk
2012-08-08 19:37 ` Tony Prisk
2012-08-08 1:39 ` [PATCH 7/8] arm: vt8500: doc: Add device tree bindings for arch-vt8500 devices Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` Tony Prisk [this message]
2012-08-08 1:39 ` [PATCH 8/8] ARM: vt8500: gpio: Devicetree support for arch-vt8500 Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 1:39 ` Tony Prisk
2012-08-08 9:11 ` [rtc-linux] " Linus Walleij
2012-08-08 9:11 ` Linus Walleij
2012-08-08 9:11 ` Linus Walleij
2012-08-08 9:11 ` Linus Walleij
2012-08-08 9:19 ` Arnd Bergmann
2012-08-08 9:19 ` Arnd Bergmann
2012-08-08 9:19 ` Arnd Bergmann
2012-08-08 9:19 ` Arnd Bergmann
2012-08-08 14:28 ` Linus Walleij
2012-08-08 14:28 ` Linus Walleij
2012-08-08 14:28 ` Linus Walleij
2012-08-08 14:28 ` Linus Walleij
[not found] ` <CACRpkdabUWpDsBhz4ZEJNhEuqw-U+v-HrX7NcWoNLeuenv5t9A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-08-08 19:46 ` Tony Prisk
2012-08-08 19:46 ` Tony Prisk
2012-08-08 18:38 ` Stephen Warren
2012-08-08 18:38 ` Stephen Warren
2012-08-08 18:38 ` Stephen Warren
2012-08-08 18:38 ` Stephen Warren
2012-08-08 19:17 ` Arnd Bergmann
2012-08-08 19:17 ` Arnd Bergmann
2012-08-08 19:17 ` Arnd Bergmann
2012-08-08 19:17 ` Arnd Bergmann
[not found] ` <1344389967-8465-1-git-send-email-linux-ci5G2KO2hbZ+pU9mqzGVBQ@public.gmane.org>
2012-08-08 2:40 ` [PATCH 0/8] *** ARM: Update arch-vt8500 to Devicetree *** Tony Prisk
2012-08-08 2:40 ` Tony Prisk
2012-08-19 1:22 ` Marcos Silva Cunha
2012-08-19 1:22 ` Marcos Silva Cunha
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1344389967-8465-9-git-send-email-linux@prisktech.co.nz \
--to=linux@prisktech.co.nz \
--cc=linux-arm-kernel@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.