diff options
author | Philipp Zabel <philipp.zabel@gmail.com> | 2008-02-05 01:28:22 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-05 12:44:13 -0500 |
commit | 1c44f5f16fee880b294f8068354bfb9dddf1349b (patch) | |
tree | dd9815cf7a38af7d4abc55eb707574ceedd8a912 /arch/arm/mach-pxa/gpio.c | |
parent | 7c2db759ece63fd166cf0849b7b271589fa1b754 (diff) |
gpiolib support for the PXA architecture
This adds gpiolib support for the PXA architecture:
- move all GPIO API functions from generic.c into gpio.c
- convert the gpio_get/set_value macros into inline functions
This makes it easier to hook up GPIOs provided by external chips like
ASICs and CPLDs.
Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
Cc: Jean Delvare <khali@linux-fr.org>
Cc: Eric Miao <eric.miao@marvell.com>
Cc: Sam Ravnborg <sam@ravnborg.org>
Cc: Haavard Skinnemoen <hskinnemoen@atmel.com>
Cc: Ben Gardner <bgardner@wabtec.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
[ Minor ARM fixup from David Brownell folded into this ]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/arm/mach-pxa/gpio.c')
-rw-r--r-- | arch/arm/mach-pxa/gpio.c | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/arch/arm/mach-pxa/gpio.c b/arch/arm/mach-pxa/gpio.c new file mode 100644 index 000000000000..8638dd7dd076 --- /dev/null +++ b/arch/arm/mach-pxa/gpio.c | |||
@@ -0,0 +1,197 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-pxa/gpio.c | ||
3 | * | ||
4 | * Generic PXA GPIO handling | ||
5 | * | ||
6 | * Author: Nicolas Pitre | ||
7 | * Created: Jun 15, 2001 | ||
8 | * Copyright: MontaVista Software Inc. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/init.h> | ||
16 | #include <linux/module.h> | ||
17 | |||
18 | #include <asm/gpio.h> | ||
19 | #include <asm/hardware.h> | ||
20 | #include <asm/io.h> | ||
21 | #include <asm/arch/pxa-regs.h> | ||
22 | |||
23 | #include "generic.h" | ||
24 | |||
25 | |||
26 | struct pxa_gpio_chip { | ||
27 | struct gpio_chip chip; | ||
28 | void __iomem *regbase; | ||
29 | }; | ||
30 | |||
31 | int pxa_last_gpio; | ||
32 | |||
33 | /* | ||
34 | * Configure pins for GPIO or other functions | ||
35 | */ | ||
36 | int pxa_gpio_mode(int gpio_mode) | ||
37 | { | ||
38 | unsigned long flags; | ||
39 | int gpio = gpio_mode & GPIO_MD_MASK_NR; | ||
40 | int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8; | ||
41 | int gafr; | ||
42 | |||
43 | if (gpio > pxa_last_gpio) | ||
44 | return -EINVAL; | ||
45 | |||
46 | local_irq_save(flags); | ||
47 | if (gpio_mode & GPIO_DFLT_LOW) | ||
48 | GPCR(gpio) = GPIO_bit(gpio); | ||
49 | else if (gpio_mode & GPIO_DFLT_HIGH) | ||
50 | GPSR(gpio) = GPIO_bit(gpio); | ||
51 | if (gpio_mode & GPIO_MD_MASK_DIR) | ||
52 | GPDR(gpio) |= GPIO_bit(gpio); | ||
53 | else | ||
54 | GPDR(gpio) &= ~GPIO_bit(gpio); | ||
55 | gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2)); | ||
56 | GAFR(gpio) = gafr | (fn << (((gpio) & 0xf)*2)); | ||
57 | local_irq_restore(flags); | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | EXPORT_SYMBOL(pxa_gpio_mode); | ||
62 | |||
63 | static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||
64 | { | ||
65 | unsigned long flags; | ||
66 | u32 mask = 1 << offset; | ||
67 | u32 value; | ||
68 | struct pxa_gpio_chip *pxa; | ||
69 | void __iomem *gpdr; | ||
70 | |||
71 | pxa = container_of(chip, struct pxa_gpio_chip, chip); | ||
72 | gpdr = pxa->regbase + GPDR_OFFSET; | ||
73 | local_irq_save(flags); | ||
74 | value = __raw_readl(gpdr); | ||
75 | value &= ~mask; | ||
76 | __raw_writel(value, gpdr); | ||
77 | local_irq_restore(flags); | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int pxa_gpio_direction_output(struct gpio_chip *chip, | ||
83 | unsigned offset, int value) | ||
84 | { | ||
85 | unsigned long flags; | ||
86 | u32 mask = 1 << offset; | ||
87 | u32 tmp; | ||
88 | struct pxa_gpio_chip *pxa; | ||
89 | void __iomem *gpdr; | ||
90 | |||
91 | pxa = container_of(chip, struct pxa_gpio_chip, chip); | ||
92 | __raw_writel(mask, | ||
93 | pxa->regbase + (value ? GPSR_OFFSET : GPCR_OFFSET)); | ||
94 | gpdr = pxa->regbase + GPDR_OFFSET; | ||
95 | local_irq_save(flags); | ||
96 | tmp = __raw_readl(gpdr); | ||
97 | tmp |= mask; | ||
98 | __raw_writel(tmp, gpdr); | ||
99 | local_irq_restore(flags); | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * Return GPIO level | ||
106 | */ | ||
107 | static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
108 | { | ||
109 | u32 mask = 1 << offset; | ||
110 | struct pxa_gpio_chip *pxa; | ||
111 | |||
112 | pxa = container_of(chip, struct pxa_gpio_chip, chip); | ||
113 | return __raw_readl(pxa->regbase + GPLR_OFFSET) & mask; | ||
114 | } | ||
115 | |||
116 | /* | ||
117 | * Set output GPIO level | ||
118 | */ | ||
119 | static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
120 | { | ||
121 | u32 mask = 1 << offset; | ||
122 | struct pxa_gpio_chip *pxa; | ||
123 | |||
124 | pxa = container_of(chip, struct pxa_gpio_chip, chip); | ||
125 | |||
126 | if (value) | ||
127 | __raw_writel(mask, pxa->regbase + GPSR_OFFSET); | ||
128 | else | ||
129 | __raw_writel(mask, pxa->regbase + GPCR_OFFSET); | ||
130 | } | ||
131 | |||
132 | static struct pxa_gpio_chip pxa_gpio_chip[] = { | ||
133 | [0] = { | ||
134 | .regbase = GPIO0_BASE, | ||
135 | .chip = { | ||
136 | .label = "gpio-0", | ||
137 | .direction_input = pxa_gpio_direction_input, | ||
138 | .direction_output = pxa_gpio_direction_output, | ||
139 | .get = pxa_gpio_get, | ||
140 | .set = pxa_gpio_set, | ||
141 | .base = 0, | ||
142 | .ngpio = 32, | ||
143 | }, | ||
144 | }, | ||
145 | [1] = { | ||
146 | .regbase = GPIO1_BASE, | ||
147 | .chip = { | ||
148 | .label = "gpio-1", | ||
149 | .direction_input = pxa_gpio_direction_input, | ||
150 | .direction_output = pxa_gpio_direction_output, | ||
151 | .get = pxa_gpio_get, | ||
152 | .set = pxa_gpio_set, | ||
153 | .base = 32, | ||
154 | .ngpio = 32, | ||
155 | }, | ||
156 | }, | ||
157 | [2] = { | ||
158 | .regbase = GPIO2_BASE, | ||
159 | .chip = { | ||
160 | .label = "gpio-2", | ||
161 | .direction_input = pxa_gpio_direction_input, | ||
162 | .direction_output = pxa_gpio_direction_output, | ||
163 | .get = pxa_gpio_get, | ||
164 | .set = pxa_gpio_set, | ||
165 | .base = 64, | ||
166 | .ngpio = 32, /* 21 for PXA25x */ | ||
167 | }, | ||
168 | }, | ||
169 | #if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) | ||
170 | [3] = { | ||
171 | .regbase = GPIO3_BASE, | ||
172 | .chip = { | ||
173 | .label = "gpio-3", | ||
174 | .direction_input = pxa_gpio_direction_input, | ||
175 | .direction_output = pxa_gpio_direction_output, | ||
176 | .get = pxa_gpio_get, | ||
177 | .set = pxa_gpio_set, | ||
178 | .base = 96, | ||
179 | .ngpio = 32, | ||
180 | }, | ||
181 | }, | ||
182 | #endif | ||
183 | }; | ||
184 | |||
185 | void __init pxa_init_gpio(int gpio_nr) | ||
186 | { | ||
187 | int i; | ||
188 | |||
189 | /* add a GPIO chip for each register bank. | ||
190 | * the last PXA25x register only contains 21 GPIOs | ||
191 | */ | ||
192 | for (i = 0; i < gpio_nr; i += 32) { | ||
193 | if (i+32 > gpio_nr) | ||
194 | pxa_gpio_chip[i/32].chip.ngpio = gpio_nr - i; | ||
195 | gpiochip_add(&pxa_gpio_chip[i/32].chip); | ||
196 | } | ||
197 | } | ||