diff options
Diffstat (limited to 'drivers/gpio/gpio-xilinx.c')
-rw-r--r-- | drivers/gpio/gpio-xilinx.c | 103 |
1 files 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 @@ | |||
1 | /* | 1 | /* |
2 | * Xilinx gpio driver | 2 | * Xilinx gpio driver for xps/axi_gpio IP. |
3 | * | 3 | * |
4 | * Copyright 2008 Xilinx, Inc. | 4 | * Copyright 2008 - 2013 Xilinx, Inc. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License version 2 | 7 | * it under the terms of the GNU General Public License version 2 |
@@ -12,6 +12,7 @@ | |||
12 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 12 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/bitops.h> | ||
15 | #include <linux/init.h> | 16 | #include <linux/init.h> |
16 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
17 | #include <linux/module.h> | 18 | #include <linux/module.h> |
@@ -26,11 +27,26 @@ | |||
26 | #define XGPIO_DATA_OFFSET (0x0) /* Data register */ | 27 | #define XGPIO_DATA_OFFSET (0x0) /* Data register */ |
27 | #define XGPIO_TRI_OFFSET (0x4) /* I/O direction register */ | 28 | #define XGPIO_TRI_OFFSET (0x4) /* I/O direction register */ |
28 | 29 | ||
30 | #define XGPIO_CHANNEL_OFFSET 0x8 | ||
31 | |||
32 | /* Read/Write access to the GPIO registers */ | ||
33 | #define xgpio_readreg(offset) in_be32(offset) | ||
34 | #define xgpio_writereg(offset, val) out_be32(offset, val) | ||
35 | |||
36 | /** | ||
37 | * struct xgpio_instance - Stores information about GPIO device | ||
38 | * struct of_mm_gpio_chip mmchip: OF GPIO chip for memory mapped banks | ||
39 | * gpio_state: GPIO state shadow register | ||
40 | * gpio_dir: GPIO direction shadow register | ||
41 | * offset: GPIO channel offset | ||
42 | * gpio_lock: Lock used for synchronization | ||
43 | */ | ||
29 | struct xgpio_instance { | 44 | struct xgpio_instance { |
30 | struct of_mm_gpio_chip mmchip; | 45 | struct of_mm_gpio_chip mmchip; |
31 | u32 gpio_state; /* GPIO state shadow register */ | 46 | u32 gpio_state; |
32 | u32 gpio_dir; /* GPIO direction shadow register */ | 47 | u32 gpio_dir; |
33 | spinlock_t gpio_lock; /* Lock used for synchronization */ | 48 | u32 offset; |
49 | spinlock_t gpio_lock; | ||
34 | }; | 50 | }; |
35 | 51 | ||
36 | /** | 52 | /** |
@@ -44,8 +60,12 @@ struct xgpio_instance { | |||
44 | static int xgpio_get(struct gpio_chip *gc, unsigned int gpio) | 60 | static int xgpio_get(struct gpio_chip *gc, unsigned int gpio) |
45 | { | 61 | { |
46 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | 62 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); |
63 | struct xgpio_instance *chip = | ||
64 | container_of(mm_gc, struct xgpio_instance, mmchip); | ||
47 | 65 | ||
48 | return (in_be32(mm_gc->regs + XGPIO_DATA_OFFSET) >> gpio) & 1; | 66 | void __iomem *regs = mm_gc->regs + chip->offset; |
67 | |||
68 | return !!(xgpio_readreg(regs + XGPIO_DATA_OFFSET) & BIT(gpio)); | ||
49 | } | 69 | } |
50 | 70 | ||
51 | /** | 71 | /** |
@@ -63,6 +83,7 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) | |||
63 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | 83 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); |
64 | struct xgpio_instance *chip = | 84 | struct xgpio_instance *chip = |
65 | container_of(mm_gc, struct xgpio_instance, mmchip); | 85 | container_of(mm_gc, struct xgpio_instance, mmchip); |
86 | void __iomem *regs = mm_gc->regs; | ||
66 | 87 | ||
67 | spin_lock_irqsave(&chip->gpio_lock, flags); | 88 | spin_lock_irqsave(&chip->gpio_lock, flags); |
68 | 89 | ||
@@ -71,7 +92,9 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) | |||
71 | chip->gpio_state |= 1 << gpio; | 92 | chip->gpio_state |= 1 << gpio; |
72 | else | 93 | else |
73 | chip->gpio_state &= ~(1 << gpio); | 94 | chip->gpio_state &= ~(1 << gpio); |
74 | out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); | 95 | |
96 | xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET, | ||
97 | chip->gpio_state); | ||
75 | 98 | ||
76 | spin_unlock_irqrestore(&chip->gpio_lock, flags); | 99 | spin_unlock_irqrestore(&chip->gpio_lock, flags); |
77 | } | 100 | } |
@@ -91,12 +114,13 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) | |||
91 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | 114 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); |
92 | struct xgpio_instance *chip = | 115 | struct xgpio_instance *chip = |
93 | container_of(mm_gc, struct xgpio_instance, mmchip); | 116 | container_of(mm_gc, struct xgpio_instance, mmchip); |
117 | void __iomem *regs = mm_gc->regs; | ||
94 | 118 | ||
95 | spin_lock_irqsave(&chip->gpio_lock, flags); | 119 | spin_lock_irqsave(&chip->gpio_lock, flags); |
96 | 120 | ||
97 | /* Set the GPIO bit in shadow register and set direction as input */ | 121 | /* Set the GPIO bit in shadow register and set direction as input */ |
98 | chip->gpio_dir |= (1 << gpio); | 122 | chip->gpio_dir |= (1 << gpio); |
99 | out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); | 123 | xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir); |
100 | 124 | ||
101 | spin_unlock_irqrestore(&chip->gpio_lock, flags); | 125 | spin_unlock_irqrestore(&chip->gpio_lock, flags); |
102 | 126 | ||
@@ -119,6 +143,7 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) | |||
119 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | 143 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); |
120 | struct xgpio_instance *chip = | 144 | struct xgpio_instance *chip = |
121 | container_of(mm_gc, struct xgpio_instance, mmchip); | 145 | container_of(mm_gc, struct xgpio_instance, mmchip); |
146 | void __iomem *regs = mm_gc->regs; | ||
122 | 147 | ||
123 | spin_lock_irqsave(&chip->gpio_lock, flags); | 148 | spin_lock_irqsave(&chip->gpio_lock, flags); |
124 | 149 | ||
@@ -127,11 +152,12 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) | |||
127 | chip->gpio_state |= 1 << gpio; | 152 | chip->gpio_state |= 1 << gpio; |
128 | else | 153 | else |
129 | chip->gpio_state &= ~(1 << gpio); | 154 | chip->gpio_state &= ~(1 << gpio); |
130 | out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); | 155 | xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET, |
156 | chip->gpio_state); | ||
131 | 157 | ||
132 | /* Clear the GPIO bit in shadow register and set direction as output */ | 158 | /* Clear the GPIO bit in shadow register and set direction as output */ |
133 | chip->gpio_dir &= (~(1 << gpio)); | 159 | chip->gpio_dir &= (~(1 << gpio)); |
134 | out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); | 160 | xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir); |
135 | 161 | ||
136 | spin_unlock_irqrestore(&chip->gpio_lock, flags); | 162 | spin_unlock_irqrestore(&chip->gpio_lock, flags); |
137 | 163 | ||
@@ -147,8 +173,10 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) | |||
147 | struct xgpio_instance *chip = | 173 | struct xgpio_instance *chip = |
148 | container_of(mm_gc, struct xgpio_instance, mmchip); | 174 | container_of(mm_gc, struct xgpio_instance, mmchip); |
149 | 175 | ||
150 | out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); | 176 | xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_DATA_OFFSET, |
151 | out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); | 177 | chip->gpio_state); |
178 | xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_TRI_OFFSET, | ||
179 | chip->gpio_dir); | ||
152 | } | 180 | } |
153 | 181 | ||
154 | /** | 182 | /** |
@@ -202,6 +230,57 @@ static int xgpio_of_probe(struct device_node *np) | |||
202 | np->full_name, status); | 230 | np->full_name, status); |
203 | return status; | 231 | return status; |
204 | } | 232 | } |
233 | |||
234 | pr_info("XGpio: %s: registered, base is %d\n", np->full_name, | ||
235 | chip->mmchip.gc.base); | ||
236 | |||
237 | tree_info = of_get_property(np, "xlnx,is-dual", NULL); | ||
238 | if (tree_info && be32_to_cpup(tree_info)) { | ||
239 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | ||
240 | if (!chip) | ||
241 | return -ENOMEM; | ||
242 | |||
243 | /* Add dual channel offset */ | ||
244 | chip->offset = XGPIO_CHANNEL_OFFSET; | ||
245 | |||
246 | /* Update GPIO state shadow register with default value */ | ||
247 | of_property_read_u32(np, "xlnx,dout-default-2", | ||
248 | &chip->gpio_state); | ||
249 | |||
250 | /* By default, all pins are inputs */ | ||
251 | chip->gpio_dir = 0xFFFFFFFF; | ||
252 | |||
253 | /* Update GPIO direction shadow register with default value */ | ||
254 | of_property_read_u32(np, "xlnx,tri-default-2", &chip->gpio_dir); | ||
255 | |||
256 | /* By default assume full GPIO controller */ | ||
257 | chip->mmchip.gc.ngpio = 32; | ||
258 | |||
259 | /* Check device node and parent device node for device width */ | ||
260 | of_property_read_u32(np, "xlnx,gpio2-width", | ||
261 | (u32 *)&chip->mmchip.gc.ngpio); | ||
262 | |||
263 | spin_lock_init(&chip->gpio_lock); | ||
264 | |||
265 | chip->mmchip.gc.direction_input = xgpio_dir_in; | ||
266 | chip->mmchip.gc.direction_output = xgpio_dir_out; | ||
267 | chip->mmchip.gc.get = xgpio_get; | ||
268 | chip->mmchip.gc.set = xgpio_set; | ||
269 | |||
270 | chip->mmchip.save_regs = xgpio_save_regs; | ||
271 | |||
272 | /* Call the OF gpio helper to setup and register the GPIO dev */ | ||
273 | status = of_mm_gpiochip_add(np, &chip->mmchip); | ||
274 | if (status) { | ||
275 | kfree(chip); | ||
276 | pr_err("%s: error in probe function with status %d\n", | ||
277 | np->full_name, status); | ||
278 | return status; | ||
279 | } | ||
280 | pr_info("XGpio: %s: dual channel registered, base is %d\n", | ||
281 | np->full_name, chip->mmchip.gc.base); | ||
282 | } | ||
283 | |||
205 | return 0; | 284 | return 0; |
206 | } | 285 | } |
207 | 286 | ||