Commit 1c44f5f16fee880b294f8068354bfb9dddf1349b
Committed by
Linus Torvalds
1 parent
7c2db759ec
Exists in
master
and in
7 other branches
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>
Showing 8 changed files with 236 additions and 122 deletions Side-by-side Diff
arch/arm/Kconfig
arch/arm/mach-pxa/Makefile
... | ... | @@ -3,7 +3,8 @@ |
3 | 3 | # |
4 | 4 | |
5 | 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 | 8 | obj-$(CONFIG_PXA25x) += pxa25x.o |
8 | 9 | obj-$(CONFIG_PXA27x) += pxa27x.o |
9 | 10 | obj-$(CONFIG_PXA3xx) += pxa3xx.o mfp.o smemc.o |
arch/arm/mach-pxa/generic.c
... | ... | @@ -32,7 +32,6 @@ |
32 | 32 | #include <asm/mach/map.h> |
33 | 33 | |
34 | 34 | #include <asm/arch/pxa-regs.h> |
35 | -#include <asm/arch/gpio.h> | |
36 | 35 | |
37 | 36 | #include "generic.h" |
38 | 37 | |
... | ... | @@ -67,97 +66,6 @@ |
67 | 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 | 69 | * Routine to safely enable or disable a clock in the CKEN |
162 | 70 | */ |
163 | 71 | void __pxa_set_cken(int clock, int enable) |
... | ... | @@ -172,7 +80,6 @@ |
172 | 80 | |
173 | 81 | local_irq_restore(flags); |
174 | 82 | } |
175 | - | |
176 | 83 | EXPORT_SYMBOL(__pxa_set_cken); |
177 | 84 | |
178 | 85 | /* |
arch/arm/mach-pxa/generic.h
... | ... | @@ -16,6 +16,7 @@ |
16 | 16 | extern void __init pxa_init_irq_high(void); |
17 | 17 | extern void __init pxa_init_irq_gpio(int gpio_nr); |
18 | 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 | 20 | extern void __init pxa25x_init_irq(void); |
20 | 21 | extern void __init pxa27x_init_irq(void); |
21 | 22 | extern void __init pxa3xx_init_irq(void); |
arch/arm/mach-pxa/gpio.c
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 | +} |
arch/arm/mach-pxa/irq.c
... | ... | @@ -311,6 +311,8 @@ |
311 | 311 | /* Install handler for GPIO>=2 edge detect interrupts */ |
312 | 312 | set_irq_chip(IRQ_GPIO_2_x, &pxa_internal_chip_low); |
313 | 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 | 318 | void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int)) |
include/asm-arm/arch-pxa/gpio.h
... | ... | @@ -28,43 +28,35 @@ |
28 | 28 | #include <asm/irq.h> |
29 | 29 | #include <asm/hardware.h> |
30 | 30 | |
31 | -static inline int gpio_request(unsigned gpio, const char *label) | |
32 | -{ | |
33 | - return 0; | |
34 | -} | |
31 | +#include <asm-generic/gpio.h> | |
35 | 32 | |
36 | -static inline void gpio_free(unsigned gpio) | |
37 | -{ | |
38 | - return; | |
39 | -} | |
40 | 33 | |
41 | -extern int gpio_direction_input(unsigned gpio); | |
42 | -extern int gpio_direction_output(unsigned gpio, int value); | |
34 | +/* NOTE: some PXAs have fewer on-chip GPIOs (like PXA255, with 85). | |
35 | + * Those cases currently cause holes in the GPIO number space. | |
36 | + */ | |
37 | +#define NR_BUILTIN_GPIO 128 | |
43 | 38 | |
44 | -static inline int __gpio_get_value(unsigned gpio) | |
39 | +static inline int gpio_get_value(unsigned gpio) | |
45 | 40 | { |
46 | - return GPLR(gpio) & GPIO_bit(gpio); | |
41 | + if (__builtin_constant_p(gpio) && (gpio < NR_BUILTIN_GPIO)) | |
42 | + return GPLR(gpio) & GPIO_bit(gpio); | |
43 | + else | |
44 | + return __gpio_get_value(gpio); | |
47 | 45 | } |
48 | 46 | |
49 | -#define gpio_get_value(gpio) \ | |
50 | - (__builtin_constant_p(gpio) ? \ | |
51 | - __gpio_get_value(gpio) : \ | |
52 | - pxa_gpio_get_value(gpio)) | |
53 | - | |
54 | -static inline void __gpio_set_value(unsigned gpio, int value) | |
47 | +static inline void gpio_set_value(unsigned gpio, int value) | |
55 | 48 | { |
56 | - if (value) | |
57 | - GPSR(gpio) = GPIO_bit(gpio); | |
58 | - else | |
59 | - GPCR(gpio) = GPIO_bit(gpio); | |
49 | + if (__builtin_constant_p(gpio) && (gpio < NR_BUILTIN_GPIO)) { | |
50 | + if (value) | |
51 | + GPSR(gpio) = GPIO_bit(gpio); | |
52 | + else | |
53 | + GPCR(gpio) = GPIO_bit(gpio); | |
54 | + } else { | |
55 | + __gpio_set_value(gpio, value); | |
56 | + } | |
60 | 57 | } |
61 | 58 | |
62 | -#define gpio_set_value(gpio,value) \ | |
63 | - (__builtin_constant_p(gpio) ? \ | |
64 | - __gpio_set_value(gpio, value) : \ | |
65 | - pxa_gpio_set_value(gpio, value)) | |
66 | - | |
67 | -#include <asm-generic/gpio.h> /* cansleep wrappers */ | |
59 | +#define gpio_cansleep __gpio_cansleep | |
68 | 60 | |
69 | 61 | #define gpio_to_irq(gpio) IRQ_GPIO(gpio) |
70 | 62 | #define irq_to_gpio(irq) IRQ_TO_GPIO(irq) |
include/asm-arm/arch-pxa/pxa-regs.h
... | ... | @@ -1131,6 +1131,19 @@ |
1131 | 1131 | * General Purpose I/O |
1132 | 1132 | */ |
1133 | 1133 | |
1134 | +#define GPIO0_BASE ((void __iomem *)io_p2v(0x40E00000)) | |
1135 | +#define GPIO1_BASE ((void __iomem *)io_p2v(0x40E00004)) | |
1136 | +#define GPIO2_BASE ((void __iomem *)io_p2v(0x40E00008)) | |
1137 | +#define GPIO3_BASE ((void __iomem *)io_p2v(0x40E00100)) | |
1138 | + | |
1139 | +#define GPLR_OFFSET 0x00 | |
1140 | +#define GPDR_OFFSET 0x0C | |
1141 | +#define GPSR_OFFSET 0x18 | |
1142 | +#define GPCR_OFFSET 0x24 | |
1143 | +#define GRER_OFFSET 0x30 | |
1144 | +#define GFER_OFFSET 0x3C | |
1145 | +#define GEDR_OFFSET 0x48 | |
1146 | + | |
1134 | 1147 | #define GPLR0 __REG(0x40E00000) /* GPIO Pin-Level Register GPIO<31:0> */ |
1135 | 1148 | #define GPLR1 __REG(0x40E00004) /* GPIO Pin-Level Register GPIO<63:32> */ |
1136 | 1149 | #define GPLR2 __REG(0x40E00008) /* GPIO Pin-Level Register GPIO<80:64> */ |