diff options
author | John Linn <john.linn@xilinx.com> | 2008-11-12 16:25:38 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-11-12 20:17:16 -0500 |
commit | 0bcb6069a6e1af5c114a2a8873ec43ada8933596 (patch) | |
tree | aafddacd65951f2ed7995dc6183fe9256811ee29 | |
parent | e33c3b5e172e2e45456f42fba47227d48745543f (diff) |
GPIO: add new Xilinx driver for powerpc
This driver supports the Xilinx XPS GPIO IP core which has the typical
GPIO features.
Signed-off-by: Kiran Sutariya <kirans@xilinx.com>
Signed-off-by: John Linn <john.linn@xilinx.com>
Cc: David Brownell <david-b@pacbell.net>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Kumar Gala <galak@gate.crashing.org>
Cc: "Grant Likely" <grant.likely@secretlab.ca>
Cc: <avorontsov@ru.mvista.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/gpio/Kconfig | 8 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/xilinx_gpio.c | 235 |
3 files changed, 244 insertions, 0 deletions
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 7f2ee27fe76b..48f49d93d249 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -65,6 +65,14 @@ config GPIO_SYSFS | |||
65 | 65 | ||
66 | # put expanders in the right section, in alphabetical order | 66 | # put expanders in the right section, in alphabetical order |
67 | 67 | ||
68 | comment "Memory mapped GPIO expanders:" | ||
69 | |||
70 | config GPIO_XILINX | ||
71 | bool "Xilinx GPIO support" | ||
72 | depends on PPC_OF | ||
73 | help | ||
74 | Say yes here to support the Xilinx FPGA GPIO device | ||
75 | |||
68 | comment "I2C GPIO expanders:" | 76 | comment "I2C GPIO expanders:" |
69 | 77 | ||
70 | config GPIO_MAX732X | 78 | config GPIO_MAX732X |
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 6aafdeb9ad03..49ac64e515e6 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
@@ -10,4 +10,5 @@ obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o | |||
10 | obj-$(CONFIG_GPIO_PCA953X) += pca953x.o | 10 | obj-$(CONFIG_GPIO_PCA953X) += pca953x.o |
11 | obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o | 11 | obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o |
12 | obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o | 12 | obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o |
13 | obj-$(CONFIG_GPIO_XILINX) += xilinx_gpio.o | ||
13 | obj-$(CONFIG_GPIO_BT8XX) += bt8xxgpio.o | 14 | obj-$(CONFIG_GPIO_BT8XX) += bt8xxgpio.o |
diff --git a/drivers/gpio/xilinx_gpio.c b/drivers/gpio/xilinx_gpio.c new file mode 100644 index 000000000000..3c1177abebd3 --- /dev/null +++ b/drivers/gpio/xilinx_gpio.c | |||
@@ -0,0 +1,235 @@ | |||
1 | /* | ||
2 | * Xilinx gpio driver | ||
3 | * | ||
4 | * Copyright 2008 Xilinx, Inc. | ||
5 | * | ||
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 | ||
8 | * as published by the Free Software Foundation. | ||
9 | * | ||
10 | * You should have received a copy of the GNU General Public License | ||
11 | * along with this program; if not, write to the Free Software | ||
12 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
13 | */ | ||
14 | |||
15 | #include <linux/init.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/of_device.h> | ||
18 | #include <linux/of_platform.h> | ||
19 | #include <linux/of_gpio.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/gpio.h> | ||
22 | |||
23 | /* Register Offset Definitions */ | ||
24 | #define XGPIO_DATA_OFFSET (0x0) /* Data register */ | ||
25 | #define XGPIO_TRI_OFFSET (0x4) /* I/O direction register */ | ||
26 | |||
27 | struct xgpio_instance { | ||
28 | struct of_mm_gpio_chip mmchip; | ||
29 | u32 gpio_state; /* GPIO state shadow register */ | ||
30 | u32 gpio_dir; /* GPIO direction shadow register */ | ||
31 | spinlock_t gpio_lock; /* Lock used for synchronization */ | ||
32 | }; | ||
33 | |||
34 | /** | ||
35 | * xgpio_get - Read the specified signal of the GPIO device. | ||
36 | * @gc: Pointer to gpio_chip device structure. | ||
37 | * @gpio: GPIO signal number. | ||
38 | * | ||
39 | * This function reads the specified signal of the GPIO device. It returns 0 if | ||
40 | * the signal clear, 1 if signal is set or negative value on error. | ||
41 | */ | ||
42 | static int xgpio_get(struct gpio_chip *gc, unsigned int gpio) | ||
43 | { | ||
44 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
45 | |||
46 | return (in_be32(mm_gc->regs + XGPIO_DATA_OFFSET) >> gpio) & 1; | ||
47 | } | ||
48 | |||
49 | /** | ||
50 | * xgpio_set - Write the specified signal of the GPIO device. | ||
51 | * @gc: Pointer to gpio_chip device structure. | ||
52 | * @gpio: GPIO signal number. | ||
53 | * @val: Value to be written to specified signal. | ||
54 | * | ||
55 | * This function writes the specified value in to the specified signal of the | ||
56 | * GPIO device. | ||
57 | */ | ||
58 | static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) | ||
59 | { | ||
60 | unsigned long flags; | ||
61 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
62 | struct xgpio_instance *chip = | ||
63 | container_of(mm_gc, struct xgpio_instance, mmchip); | ||
64 | |||
65 | spin_lock_irqsave(&chip->gpio_lock, flags); | ||
66 | |||
67 | /* Write to GPIO signal and set its direction to output */ | ||
68 | if (val) | ||
69 | chip->gpio_state |= 1 << gpio; | ||
70 | else | ||
71 | chip->gpio_state &= ~(1 << gpio); | ||
72 | out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); | ||
73 | |||
74 | spin_unlock_irqrestore(&chip->gpio_lock, flags); | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * xgpio_dir_in - Set the direction of the specified GPIO signal as input. | ||
79 | * @gc: Pointer to gpio_chip device structure. | ||
80 | * @gpio: GPIO signal number. | ||
81 | * | ||
82 | * This function sets the direction of specified GPIO signal as input. | ||
83 | * It returns 0 if direction of GPIO signals is set as input otherwise it | ||
84 | * returns negative error value. | ||
85 | */ | ||
86 | static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) | ||
87 | { | ||
88 | unsigned long flags; | ||
89 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
90 | struct xgpio_instance *chip = | ||
91 | container_of(mm_gc, struct xgpio_instance, mmchip); | ||
92 | |||
93 | spin_lock_irqsave(&chip->gpio_lock, flags); | ||
94 | |||
95 | /* Set the GPIO bit in shadow register and set direction as input */ | ||
96 | chip->gpio_dir |= (1 << gpio); | ||
97 | out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); | ||
98 | |||
99 | spin_unlock_irqrestore(&chip->gpio_lock, flags); | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | /** | ||
105 | * xgpio_dir_out - Set the direction of the specified GPIO signal as output. | ||
106 | * @gc: Pointer to gpio_chip device structure. | ||
107 | * @gpio: GPIO signal number. | ||
108 | * @val: Value to be written to specified signal. | ||
109 | * | ||
110 | * This function sets the direction of specified GPIO signal as output. If all | ||
111 | * GPIO signals of GPIO chip is configured as input then it returns | ||
112 | * error otherwise it returns 0. | ||
113 | */ | ||
114 | static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) | ||
115 | { | ||
116 | unsigned long flags; | ||
117 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
118 | struct xgpio_instance *chip = | ||
119 | container_of(mm_gc, struct xgpio_instance, mmchip); | ||
120 | |||
121 | spin_lock_irqsave(&chip->gpio_lock, flags); | ||
122 | |||
123 | /* Write state of GPIO signal */ | ||
124 | if (val) | ||
125 | chip->gpio_state |= 1 << gpio; | ||
126 | else | ||
127 | chip->gpio_state &= ~(1 << gpio); | ||
128 | out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); | ||
129 | |||
130 | /* Clear the GPIO bit in shadow register and set direction as output */ | ||
131 | chip->gpio_dir &= (~(1 << gpio)); | ||
132 | out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); | ||
133 | |||
134 | spin_unlock_irqrestore(&chip->gpio_lock, flags); | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | /** | ||
140 | * xgpio_save_regs - Set initial values of GPIO pins | ||
141 | * @mm_gc: pointer to memory mapped GPIO chip structure | ||
142 | */ | ||
143 | static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) | ||
144 | { | ||
145 | struct xgpio_instance *chip = | ||
146 | container_of(mm_gc, struct xgpio_instance, mmchip); | ||
147 | |||
148 | out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); | ||
149 | out_be32(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); | ||
150 | } | ||
151 | |||
152 | /** | ||
153 | * xgpio_of_probe - Probe method for the GPIO device. | ||
154 | * @np: pointer to device tree node | ||
155 | * | ||
156 | * This function probes the GPIO device in the device tree. It initializes the | ||
157 | * driver data structure. It returns 0, if the driver is bound to the GPIO | ||
158 | * device, or a negative value if there is an error. | ||
159 | */ | ||
160 | static int __devinit xgpio_of_probe(struct device_node *np) | ||
161 | { | ||
162 | struct xgpio_instance *chip; | ||
163 | struct of_gpio_chip *ofchip; | ||
164 | int status = 0; | ||
165 | const u32 *tree_info; | ||
166 | |||
167 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | ||
168 | if (!chip) | ||
169 | return -ENOMEM; | ||
170 | ofchip = &chip->mmchip.of_gc; | ||
171 | |||
172 | /* Update GPIO state shadow register with default value */ | ||
173 | tree_info = of_get_property(np, "xlnx,dout-default", NULL); | ||
174 | if (tree_info) | ||
175 | chip->gpio_state = *tree_info; | ||
176 | |||
177 | /* Update GPIO direction shadow register with default value */ | ||
178 | chip->gpio_dir = 0xFFFFFFFF; /* By default, all pins are inputs */ | ||
179 | tree_info = of_get_property(np, "xlnx,tri-default", NULL); | ||
180 | if (tree_info) | ||
181 | chip->gpio_dir = *tree_info; | ||
182 | |||
183 | /* Check device node and parent device node for device width */ | ||
184 | ofchip->gc.ngpio = 32; /* By default assume full GPIO controller */ | ||
185 | tree_info = of_get_property(np, "xlnx,gpio-width", NULL); | ||
186 | if (!tree_info) | ||
187 | tree_info = of_get_property(np->parent, | ||
188 | "xlnx,gpio-width", NULL); | ||
189 | if (tree_info) | ||
190 | ofchip->gc.ngpio = *tree_info; | ||
191 | |||
192 | spin_lock_init(&chip->gpio_lock); | ||
193 | |||
194 | ofchip->gpio_cells = 2; | ||
195 | ofchip->gc.direction_input = xgpio_dir_in; | ||
196 | ofchip->gc.direction_output = xgpio_dir_out; | ||
197 | ofchip->gc.get = xgpio_get; | ||
198 | ofchip->gc.set = xgpio_set; | ||
199 | |||
200 | chip->mmchip.save_regs = xgpio_save_regs; | ||
201 | |||
202 | /* Call the OF gpio helper to setup and register the GPIO device */ | ||
203 | status = of_mm_gpiochip_add(np, &chip->mmchip); | ||
204 | if (status) { | ||
205 | kfree(chip); | ||
206 | pr_err("%s: error in probe function with status %d\n", | ||
207 | np->full_name, status); | ||
208 | return status; | ||
209 | } | ||
210 | pr_info("XGpio: %s: registered\n", np->full_name); | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static struct of_device_id xgpio_of_match[] __devinitdata = { | ||
215 | { .compatible = "xlnx,xps-gpio-1.00.a", }, | ||
216 | { /* end of list */ }, | ||
217 | }; | ||
218 | |||
219 | static int __init xgpio_init(void) | ||
220 | { | ||
221 | struct device_node *np; | ||
222 | |||
223 | for_each_matching_node(np, xgpio_of_match) | ||
224 | xgpio_of_probe(np); | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | /* Make sure we get initialized before anyone else tries to use us */ | ||
230 | subsys_initcall(xgpio_init); | ||
231 | /* No exit call at the moment as we cannot unregister of GPIO chips */ | ||
232 | |||
233 | MODULE_AUTHOR("Xilinx, Inc."); | ||
234 | MODULE_DESCRIPTION("Xilinx GPIO driver"); | ||
235 | MODULE_LICENSE("GPL"); | ||