From 6f8bf50031a68f533ae7eba3d3277c38ee7806f5 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 3 Jun 2013 14:31:16 +0200 Subject: GPIO: xilinx: Simplify driver probe function Simplification is done by using OF helper function which increase readability of code and remove (if (var) var = be32_to_cpup;) assignment. Signed-off-by: Michal Simek Signed-off-by: Linus Walleij --- drivers/gpio/gpio-xilinx.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'drivers/gpio/gpio-xilinx.c') diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index 9ae7aa8ca48a..2aad53497a63 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -170,24 +170,20 @@ static int xgpio_of_probe(struct device_node *np) return -ENOMEM; /* Update GPIO state shadow register with default value */ - tree_info = of_get_property(np, "xlnx,dout-default", NULL); - if (tree_info) - chip->gpio_state = be32_to_cpup(tree_info); + of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state); + + /* By default, all pins are inputs */ + chip->gpio_dir = 0xFFFFFFFF; /* Update GPIO direction shadow register with default value */ - chip->gpio_dir = 0xFFFFFFFF; /* By default, all pins are inputs */ - tree_info = of_get_property(np, "xlnx,tri-default", NULL); - if (tree_info) - chip->gpio_dir = be32_to_cpup(tree_info); + of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir); + + /* By default assume full GPIO controller */ + chip->mmchip.gc.ngpio = 32; /* Check device node and parent device node for device width */ - chip->mmchip.gc.ngpio = 32; /* By default assume full GPIO controller */ - tree_info = of_get_property(np, "xlnx,gpio-width", NULL); - if (!tree_info) - tree_info = of_get_property(np->parent, - "xlnx,gpio-width", NULL); - if (tree_info) - chip->mmchip.gc.ngpio = be32_to_cpup(tree_info); + of_property_read_u32(np, "xlnx,gpio-width", + (u32 *)&chip->mmchip.gc.ngpio); spin_lock_init(&chip->gpio_lock); -- cgit v1.2.3 From 74600ee017557b2ebb669e45237f655e9e2fbac8 Mon Sep 17 00:00:00 2001 From: Michal Simek 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 Signed-off-by: Linus Walleij --- drivers/gpio/gpio-xilinx.c | 103 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 91 insertions(+), 12 deletions(-) (limited to 'drivers/gpio/gpio-xilinx.c') 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 #include #include #include @@ -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; } -- cgit v1.2.3 From cc090d61d1a88f30f2fb75a91bce684ad1bd2e94 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 3 Jun 2013 14:31:18 +0200 Subject: GPIO: xilinx: Use __raw_readl/__raw_writel IO functions This driver can be used on Xilinx ARM Zynq platform where in_be32/out_be32 functions are not implemented. Use __raw_readl/__raw_writel functions which are implemented on Microblaze and PowerPC. For ARM readl/writel functions are used instead. The correct way how to implement this is to detect endians directly on IP. But for the gpio case without interrupt connected(it means without interrupt logic) there are just 2 registers data and tristate where auto detection can't be done. Signed-off-by: Michal Simek Signed-off-by: Linus Walleij --- drivers/gpio/gpio-xilinx.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/gpio/gpio-xilinx.c') diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index 626eaa876f09..791ddaedbfb4 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -30,8 +30,13 @@ #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) +#ifdef CONFIG_ARCH_ZYNQ +# define xgpio_readreg(offset) readl(offset) +# define xgpio_writereg(offset, val) writel(val, offset) +#else +# define xgpio_readreg(offset) __raw_readl(offset) +# define xgpio_writereg(offset, val) __raw_writel(val, offset) +#endif /** * struct xgpio_instance - Stores information about GPIO device -- cgit v1.2.3 From 9f7f0b2bbcff719233e6724d756a8c93d3285ade Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 3 Jun 2013 14:31:19 +0200 Subject: GPIO: xilinx: Use BIT macro Use BIT macro from linux/bitops.h. Signed-off-by: Michal Simek Signed-off-by: Linus Walleij --- drivers/gpio/gpio-xilinx.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/gpio/gpio-xilinx.c') diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index 791ddaedbfb4..792a05ad4649 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -94,9 +94,9 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) /* Write to GPIO signal and set its direction to output */ if (val) - chip->gpio_state |= 1 << gpio; + chip->gpio_state |= BIT(gpio); else - chip->gpio_state &= ~(1 << gpio); + chip->gpio_state &= ~BIT(gpio); xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET, chip->gpio_state); @@ -124,7 +124,7 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) spin_lock_irqsave(&chip->gpio_lock, flags); /* Set the GPIO bit in shadow register and set direction as input */ - chip->gpio_dir |= (1 << gpio); + chip->gpio_dir |= BIT(gpio); xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir); spin_unlock_irqrestore(&chip->gpio_lock, flags); @@ -154,14 +154,14 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) /* Write state of GPIO signal */ if (val) - chip->gpio_state |= 1 << gpio; + chip->gpio_state |= BIT(gpio); else - chip->gpio_state &= ~(1 << gpio); + chip->gpio_state &= ~BIT(gpio); xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET, chip->gpio_state); /* Clear the GPIO bit in shadow register and set direction as output */ - chip->gpio_dir &= (~(1 << gpio)); + chip->gpio_dir &= ~BIT(gpio); xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir); spin_unlock_irqrestore(&chip->gpio_lock, flags); -- cgit v1.2.3