Loading drivers/gpio/gpio-xilinx.c +91 −12 Original line number Diff line number Diff line /* * 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 Loading @@ -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> Loading @@ -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; }; /** Loading @@ -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)); } /** Loading @@ -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); Loading @@ -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); } Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading @@ -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); } /** Loading Loading @@ -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; } Loading Loading
drivers/gpio/gpio-xilinx.c +91 −12 Original line number Diff line number Diff line /* * 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 Loading @@ -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> Loading @@ -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; }; /** Loading @@ -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)); } /** Loading @@ -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); Loading @@ -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); } Loading @@ -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); Loading @@ -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); Loading @@ -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); Loading @@ -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); } /** Loading Loading @@ -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; } Loading