diff options
Diffstat (limited to 'patches.zynq/0030-GPIO-xilinx-Add-support-for-dual-channel.patch')
-rw-r--r-- | patches.zynq/0030-GPIO-xilinx-Add-support-for-dual-channel.patch | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/patches.zynq/0030-GPIO-xilinx-Add-support-for-dual-channel.patch b/patches.zynq/0030-GPIO-xilinx-Add-support-for-dual-channel.patch new file mode 100644 index 00000000000000..1dc40d12346a1a --- /dev/null +++ b/patches.zynq/0030-GPIO-xilinx-Add-support-for-dual-channel.patch @@ -0,0 +1,215 @@ +From 182740a085e83bd94a291554eee572946ada657e Mon Sep 17 00:00:00 2001 +From: Michal Simek <michal.simek@xilinx.com> +Date: Mon, 3 Jun 2013 14:31:17 +0200 +Subject: GPIO: xilinx: Add support for dual channel + +Supporting the second channel in the driver. +Offset is 0x8 and both channnels share the same +IRQ. + +Signed-off-by: Michal Simek <michal.simek@xilinx.com> +Signed-off-by: Linus Walleij <linus.walleij@linaro.org> +(cherry picked from commit 74600ee017557b2ebb669e45237f655e9e2fbac8) +Signed-off-by: Daniel Sangorrin <daniel.sangorrin@toshiba.co.jp> +Signed-off-by: Yoshitake Kobayashi <yoshitake.kobayashi@toshiba.co.jp> +--- + drivers/gpio/gpio-xilinx.c | 103 +++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 91 insertions(+), 12 deletions(-) + +diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c +index 2aad53497a63..626eaa876f09 100644 +--- a/drivers/gpio/gpio-xilinx.c ++++ b/drivers/gpio/gpio-xilinx.c +@@ -1,7 +1,7 @@ + /* +- * Xilinx gpio driver ++ * Xilinx gpio driver for xps/axi_gpio IP. + * +- * Copyright 2008 Xilinx, Inc. ++ * Copyright 2008 - 2013 Xilinx, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 +@@ -12,6 +12,7 @@ + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + ++#include <linux/bitops.h> + #include <linux/init.h> + #include <linux/errno.h> + #include <linux/module.h> +@@ -26,11 +27,26 @@ + #define XGPIO_DATA_OFFSET (0x0) /* Data register */ + #define XGPIO_TRI_OFFSET (0x4) /* I/O direction register */ + ++#define XGPIO_CHANNEL_OFFSET 0x8 ++ ++/* Read/Write access to the GPIO registers */ ++#define xgpio_readreg(offset) in_be32(offset) ++#define xgpio_writereg(offset, val) out_be32(offset, val) ++ ++/** ++ * struct xgpio_instance - Stores information about GPIO device ++ * struct of_mm_gpio_chip mmchip: OF GPIO chip for memory mapped banks ++ * gpio_state: GPIO state shadow register ++ * gpio_dir: GPIO direction shadow register ++ * offset: GPIO channel offset ++ * gpio_lock: Lock used for synchronization ++ */ + struct xgpio_instance { + struct of_mm_gpio_chip mmchip; +- u32 gpio_state; /* GPIO state shadow register */ +- u32 gpio_dir; /* GPIO direction shadow register */ +- spinlock_t gpio_lock; /* Lock used for synchronization */ ++ u32 gpio_state; ++ u32 gpio_dir; ++ u32 offset; ++ spinlock_t gpio_lock; + }; + + /** +@@ -44,8 +60,12 @@ struct xgpio_instance { + static int xgpio_get(struct gpio_chip *gc, unsigned int gpio) + { + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); ++ struct xgpio_instance *chip = ++ container_of(mm_gc, struct xgpio_instance, mmchip); + +- return (in_be32(mm_gc->regs + XGPIO_DATA_OFFSET) >> gpio) & 1; ++ void __iomem *regs = mm_gc->regs + chip->offset; ++ ++ return !!(xgpio_readreg(regs + XGPIO_DATA_OFFSET) & BIT(gpio)); + } + + /** +@@ -63,6 +83,7 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct xgpio_instance *chip = + container_of(mm_gc, struct xgpio_instance, mmchip); ++ void __iomem *regs = mm_gc->regs; + + spin_lock_irqsave(&chip->gpio_lock, flags); + +@@ -71,7 +92,9 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) + chip->gpio_state |= 1 << gpio; + else + chip->gpio_state &= ~(1 << gpio); +- out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); ++ ++ xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET, ++ chip->gpio_state); + + spin_unlock_irqrestore(&chip->gpio_lock, flags); + } +@@ -91,12 +114,13 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct xgpio_instance *chip = + container_of(mm_gc, struct xgpio_instance, mmchip); ++ void __iomem *regs = mm_gc->regs; + + spin_lock_irqsave(&chip->gpio_lock, flags); + + /* Set the GPIO bit in shadow register and set direction as input */ + chip->gpio_dir |= (1 << gpio); +- out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); ++ xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir); + + spin_unlock_irqrestore(&chip->gpio_lock, flags); + +@@ -119,6 +143,7 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct xgpio_instance *chip = + container_of(mm_gc, struct xgpio_instance, mmchip); ++ void __iomem *regs = mm_gc->regs; + + spin_lock_irqsave(&chip->gpio_lock, flags); + +@@ -127,11 +152,12 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) + chip->gpio_state |= 1 << gpio; + else + chip->gpio_state &= ~(1 << gpio); +- out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); ++ xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET, ++ chip->gpio_state); + + /* Clear the GPIO bit in shadow register and set direction as output */ + chip->gpio_dir &= (~(1 << gpio)); +- out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); ++ xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir); + + spin_unlock_irqrestore(&chip->gpio_lock, flags); + +@@ -147,8 +173,10 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) + struct xgpio_instance *chip = + container_of(mm_gc, struct xgpio_instance, mmchip); + +- out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); +- out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); ++ xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_DATA_OFFSET, ++ chip->gpio_state); ++ xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_TRI_OFFSET, ++ chip->gpio_dir); + } + + /** +@@ -202,6 +230,57 @@ static int xgpio_of_probe(struct device_node *np) + np->full_name, status); + return status; + } ++ ++ pr_info("XGpio: %s: registered, base is %d\n", np->full_name, ++ chip->mmchip.gc.base); ++ ++ tree_info = of_get_property(np, "xlnx,is-dual", NULL); ++ if (tree_info && be32_to_cpup(tree_info)) { ++ chip = kzalloc(sizeof(*chip), GFP_KERNEL); ++ if (!chip) ++ return -ENOMEM; ++ ++ /* Add dual channel offset */ ++ chip->offset = XGPIO_CHANNEL_OFFSET; ++ ++ /* Update GPIO state shadow register with default value */ ++ of_property_read_u32(np, "xlnx,dout-default-2", ++ &chip->gpio_state); ++ ++ /* By default, all pins are inputs */ ++ chip->gpio_dir = 0xFFFFFFFF; ++ ++ /* Update GPIO direction shadow register with default value */ ++ of_property_read_u32(np, "xlnx,tri-default-2", &chip->gpio_dir); ++ ++ /* By default assume full GPIO controller */ ++ chip->mmchip.gc.ngpio = 32; ++ ++ /* Check device node and parent device node for device width */ ++ of_property_read_u32(np, "xlnx,gpio2-width", ++ (u32 *)&chip->mmchip.gc.ngpio); ++ ++ spin_lock_init(&chip->gpio_lock); ++ ++ chip->mmchip.gc.direction_input = xgpio_dir_in; ++ chip->mmchip.gc.direction_output = xgpio_dir_out; ++ chip->mmchip.gc.get = xgpio_get; ++ chip->mmchip.gc.set = xgpio_set; ++ ++ chip->mmchip.save_regs = xgpio_save_regs; ++ ++ /* Call the OF gpio helper to setup and register the GPIO dev */ ++ status = of_mm_gpiochip_add(np, &chip->mmchip); ++ if (status) { ++ kfree(chip); ++ pr_err("%s: error in probe function with status %d\n", ++ np->full_name, status); ++ return status; ++ } ++ pr_info("XGpio: %s: dual channel registered, base is %d\n", ++ np->full_name, chip->mmchip.gc.base); ++ } ++ + return 0; + } + +-- +1.8.5.rc3 + |