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 | |
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')
-rw-r--r-- | arch/arm/mach-pxa/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/mach-pxa/generic.c | 93 | ||||
-rw-r--r-- | arch/arm/mach-pxa/generic.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-pxa/gpio.c | 197 | ||||
-rw-r--r-- | arch/arm/mach-pxa/irq.c | 2 |
5 files changed, 202 insertions, 94 deletions
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 8604938bd948..6e0c4f5b5ae6 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile | |||
@@ -3,7 +3,8 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | # Common support (must be linked before board specific support) | 5 | # Common support (must be linked before board specific support) |
6 | obj-y += clock.o devices.o generic.o irq.o dma.o time.o | 6 | obj-y += clock.o devices.o generic.o irq.o dma.o \ |
7 | time.o gpio.o | ||
7 | obj-$(CONFIG_PXA25x) += pxa25x.o | 8 | obj-$(CONFIG_PXA25x) += pxa25x.o |
8 | obj-$(CONFIG_PXA27x) += pxa27x.o | 9 | obj-$(CONFIG_PXA27x) += pxa27x.o |
9 | obj-$(CONFIG_PXA3xx) += pxa3xx.o mfp.o smemc.o | 10 | obj-$(CONFIG_PXA3xx) += pxa3xx.o mfp.o smemc.o |
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index 76970598f550..80721c610d41 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c | |||
@@ -32,7 +32,6 @@ | |||
32 | #include <asm/mach/map.h> | 32 | #include <asm/mach/map.h> |
33 | 33 | ||
34 | #include <asm/arch/pxa-regs.h> | 34 | #include <asm/arch/pxa-regs.h> |
35 | #include <asm/arch/gpio.h> | ||
36 | 35 | ||
37 | #include "generic.h" | 36 | #include "generic.h" |
38 | 37 | ||
@@ -67,97 +66,6 @@ unsigned int get_memclk_frequency_10khz(void) | |||
67 | EXPORT_SYMBOL(get_memclk_frequency_10khz); | 66 | EXPORT_SYMBOL(get_memclk_frequency_10khz); |
68 | 67 | ||
69 | /* | 68 | /* |
70 | * Handy function to set GPIO alternate functions | ||
71 | */ | ||
72 | int pxa_last_gpio; | ||
73 | |||
74 | int pxa_gpio_mode(int gpio_mode) | ||
75 | { | ||
76 | unsigned long flags; | ||
77 | int gpio = gpio_mode & GPIO_MD_MASK_NR; | ||
78 | int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8; | ||
79 | int gafr; | ||
80 | |||
81 | if (gpio > pxa_last_gpio) | ||
82 | return -EINVAL; | ||
83 | |||
84 | local_irq_save(flags); | ||
85 | if (gpio_mode & GPIO_DFLT_LOW) | ||
86 | GPCR(gpio) = GPIO_bit(gpio); | ||
87 | else if (gpio_mode & GPIO_DFLT_HIGH) | ||
88 | GPSR(gpio) = GPIO_bit(gpio); | ||
89 | if (gpio_mode & GPIO_MD_MASK_DIR) | ||
90 | GPDR(gpio) |= GPIO_bit(gpio); | ||
91 | else | ||
92 | GPDR(gpio) &= ~GPIO_bit(gpio); | ||
93 | gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2)); | ||
94 | GAFR(gpio) = gafr | (fn << (((gpio) & 0xf)*2)); | ||
95 | local_irq_restore(flags); | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | EXPORT_SYMBOL(pxa_gpio_mode); | ||
101 | |||
102 | int gpio_direction_input(unsigned gpio) | ||
103 | { | ||
104 | unsigned long flags; | ||
105 | u32 mask; | ||
106 | |||
107 | if (gpio > pxa_last_gpio) | ||
108 | return -EINVAL; | ||
109 | |||
110 | mask = GPIO_bit(gpio); | ||
111 | local_irq_save(flags); | ||
112 | GPDR(gpio) &= ~mask; | ||
113 | local_irq_restore(flags); | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | EXPORT_SYMBOL(gpio_direction_input); | ||
118 | |||
119 | int gpio_direction_output(unsigned gpio, int value) | ||
120 | { | ||
121 | unsigned long flags; | ||
122 | u32 mask; | ||
123 | |||
124 | if (gpio > pxa_last_gpio) | ||
125 | return -EINVAL; | ||
126 | |||
127 | mask = GPIO_bit(gpio); | ||
128 | local_irq_save(flags); | ||
129 | if (value) | ||
130 | GPSR(gpio) = mask; | ||
131 | else | ||
132 | GPCR(gpio) = mask; | ||
133 | GPDR(gpio) |= mask; | ||
134 | local_irq_restore(flags); | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | EXPORT_SYMBOL(gpio_direction_output); | ||
139 | |||
140 | /* | ||
141 | * Return GPIO level | ||
142 | */ | ||
143 | int pxa_gpio_get_value(unsigned gpio) | ||
144 | { | ||
145 | return __gpio_get_value(gpio); | ||
146 | } | ||
147 | |||
148 | EXPORT_SYMBOL(pxa_gpio_get_value); | ||
149 | |||
150 | /* | ||
151 | * Set output GPIO level | ||
152 | */ | ||
153 | void pxa_gpio_set_value(unsigned gpio, int value) | ||
154 | { | ||
155 | __gpio_set_value(gpio, value); | ||
156 | } | ||
157 | |||
158 | EXPORT_SYMBOL(pxa_gpio_set_value); | ||
159 | |||
160 | /* | ||
161 | * Routine to safely enable or disable a clock in the CKEN | 69 | * Routine to safely enable or disable a clock in the CKEN |
162 | */ | 70 | */ |
163 | void __pxa_set_cken(int clock, int enable) | 71 | void __pxa_set_cken(int clock, int enable) |
@@ -172,7 +80,6 @@ void __pxa_set_cken(int clock, int enable) | |||
172 | 80 | ||
173 | local_irq_restore(flags); | 81 | local_irq_restore(flags); |
174 | } | 82 | } |
175 | |||
176 | EXPORT_SYMBOL(__pxa_set_cken); | 83 | EXPORT_SYMBOL(__pxa_set_cken); |
177 | 84 | ||
178 | /* | 85 | /* |
diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h index 1a16ad3ecee6..b3d10b0e52a0 100644 --- a/arch/arm/mach-pxa/generic.h +++ b/arch/arm/mach-pxa/generic.h | |||
@@ -16,6 +16,7 @@ extern void __init pxa_init_irq_low(void); | |||
16 | extern void __init pxa_init_irq_high(void); | 16 | extern void __init pxa_init_irq_high(void); |
17 | extern void __init pxa_init_irq_gpio(int gpio_nr); | 17 | extern void __init pxa_init_irq_gpio(int gpio_nr); |
18 | extern void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int)); | 18 | extern void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int)); |
19 | extern void __init pxa_init_gpio(int gpio_nr); | ||
19 | extern void __init pxa25x_init_irq(void); | 20 | extern void __init pxa25x_init_irq(void); |
20 | extern void __init pxa27x_init_irq(void); | 21 | extern void __init pxa27x_init_irq(void); |
21 | extern void __init pxa3xx_init_irq(void); | 22 | extern void __init pxa3xx_init_irq(void); |
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 | } | ||
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c index 5a1d5eef10a4..36c6a68beca2 100644 --- a/arch/arm/mach-pxa/irq.c +++ b/arch/arm/mach-pxa/irq.c | |||
@@ -311,6 +311,8 @@ void __init pxa_init_irq_gpio(int gpio_nr) | |||
311 | /* Install handler for GPIO>=2 edge detect interrupts */ | 311 | /* Install handler for GPIO>=2 edge detect interrupts */ |
312 | set_irq_chip(IRQ_GPIO_2_x, &pxa_internal_chip_low); | 312 | set_irq_chip(IRQ_GPIO_2_x, &pxa_internal_chip_low); |
313 | set_irq_chained_handler(IRQ_GPIO_2_x, pxa_gpio_demux_handler); | 313 | set_irq_chained_handler(IRQ_GPIO_2_x, pxa_gpio_demux_handler); |
314 | |||
315 | pxa_init_gpio(gpio_nr); | ||
314 | } | 316 | } |
315 | 317 | ||
316 | void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int)) | 318 | void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int)) |