aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorPhilipp Zabel <philipp.zabel@gmail.com>2008-02-05 01:28:22 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-05 12:44:13 -0500
commit1c44f5f16fee880b294f8068354bfb9dddf1349b (patch)
treedd9815cf7a38af7d4abc55eb707574ceedd8a912 /arch/arm
parent7c2db759ece63fd166cf0849b7b271589fa1b754 (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')
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/mach-pxa/Makefile3
-rw-r--r--arch/arm/mach-pxa/generic.c93
-rw-r--r--arch/arm/mach-pxa/generic.h1
-rw-r--r--arch/arm/mach-pxa/gpio.c197
-rw-r--r--arch/arm/mach-pxa/irq.c2
6 files changed, 203 insertions, 94 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index a322f58cdc90..e19e7744e366 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -385,6 +385,7 @@ config ARCH_PXA
385 depends on MMU 385 depends on MMU
386 select ARCH_MTD_XIP 386 select ARCH_MTD_XIP
387 select GENERIC_GPIO 387 select GENERIC_GPIO
388 select HAVE_GPIO_LIB
388 select GENERIC_TIME 389 select GENERIC_TIME
389 select GENERIC_CLOCKEVENTS 390 select GENERIC_CLOCKEVENTS
390 select TICK_ONESHOT 391 select TICK_ONESHOT
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)
6obj-y += clock.o devices.o generic.o irq.o dma.o time.o 6obj-y += clock.o devices.o generic.o irq.o dma.o \
7 time.o gpio.o
7obj-$(CONFIG_PXA25x) += pxa25x.o 8obj-$(CONFIG_PXA25x) += pxa25x.o
8obj-$(CONFIG_PXA27x) += pxa27x.o 9obj-$(CONFIG_PXA27x) += pxa27x.o
9obj-$(CONFIG_PXA3xx) += pxa3xx.o mfp.o smemc.o 10obj-$(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)
67EXPORT_SYMBOL(get_memclk_frequency_10khz); 66EXPORT_SYMBOL(get_memclk_frequency_10khz);
68 67
69/* 68/*
70 * Handy function to set GPIO alternate functions
71 */
72int pxa_last_gpio;
73
74int 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
100EXPORT_SYMBOL(pxa_gpio_mode);
101
102int 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}
117EXPORT_SYMBOL(gpio_direction_input);
118
119int 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}
138EXPORT_SYMBOL(gpio_direction_output);
139
140/*
141 * Return GPIO level
142 */
143int pxa_gpio_get_value(unsigned gpio)
144{
145 return __gpio_get_value(gpio);
146}
147
148EXPORT_SYMBOL(pxa_gpio_get_value);
149
150/*
151 * Set output GPIO level
152 */
153void pxa_gpio_set_value(unsigned gpio, int value)
154{
155 __gpio_set_value(gpio, value);
156}
157
158EXPORT_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 */
163void __pxa_set_cken(int clock, int enable) 71void __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
176EXPORT_SYMBOL(__pxa_set_cken); 83EXPORT_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);
16extern void __init pxa_init_irq_high(void); 16extern void __init pxa_init_irq_high(void);
17extern void __init pxa_init_irq_gpio(int gpio_nr); 17extern void __init pxa_init_irq_gpio(int gpio_nr);
18extern void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int)); 18extern void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int));
19extern void __init pxa_init_gpio(int gpio_nr);
19extern void __init pxa25x_init_irq(void); 20extern void __init pxa25x_init_irq(void);
20extern void __init pxa27x_init_irq(void); 21extern void __init pxa27x_init_irq(void);
21extern void __init pxa3xx_init_irq(void); 22extern 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
26struct pxa_gpio_chip {
27 struct gpio_chip chip;
28 void __iomem *regbase;
29};
30
31int pxa_last_gpio;
32
33/*
34 * Configure pins for GPIO or other functions
35 */
36int 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}
61EXPORT_SYMBOL(pxa_gpio_mode);
62
63static 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
82static 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 */
107static 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 */
119static 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
132static 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
185void __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
316void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int)) 318void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int))