diff options
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-imx/generic.c | 118 | ||||
-rw-r--r-- | include/asm-arm/arch-imx/gpio.h | 102 | ||||
-rw-r--r-- | include/asm-arm/arch-imx/imx-regs.h | 2 |
4 files changed, 223 insertions, 0 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 50d9f3e4e0f1..8b553954365f 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -241,6 +241,7 @@ config ARCH_H720X | |||
241 | 241 | ||
242 | config ARCH_IMX | 242 | config ARCH_IMX |
243 | bool "IMX" | 243 | bool "IMX" |
244 | select GENERIC_GPIO | ||
244 | help | 245 | help |
245 | Support for Motorola's i.MX family of processors (MX1, MXL). | 246 | Support for Motorola's i.MX family of processors (MX1, MXL). |
246 | 247 | ||
diff --git a/arch/arm/mach-imx/generic.c b/arch/arm/mach-imx/generic.c index 1c474cf709ca..a58b678006df 100644 --- a/arch/arm/mach-imx/generic.c +++ b/arch/arm/mach-imx/generic.c | |||
@@ -28,12 +28,16 @@ | |||
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/string.h> | 29 | #include <linux/string.h> |
30 | 30 | ||
31 | #include <asm/errno.h> | ||
31 | #include <asm/arch/imxfb.h> | 32 | #include <asm/arch/imxfb.h> |
32 | #include <asm/hardware.h> | 33 | #include <asm/hardware.h> |
33 | #include <asm/arch/imx-regs.h> | 34 | #include <asm/arch/imx-regs.h> |
34 | 35 | ||
35 | #include <asm/mach/map.h> | 36 | #include <asm/mach/map.h> |
36 | #include <asm/arch/mmc.h> | 37 | #include <asm/arch/mmc.h> |
38 | #include <asm/arch/gpio.h> | ||
39 | |||
40 | unsigned long imx_gpio_alloc_map[(GPIO_PORT_MAX + 1) * 32 / BITS_PER_LONG]; | ||
37 | 41 | ||
38 | void imx_gpio_mode(int gpio_mode) | 42 | void imx_gpio_mode(int gpio_mode) |
39 | { | 43 | { |
@@ -95,6 +99,120 @@ void imx_gpio_mode(int gpio_mode) | |||
95 | 99 | ||
96 | EXPORT_SYMBOL(imx_gpio_mode); | 100 | EXPORT_SYMBOL(imx_gpio_mode); |
97 | 101 | ||
102 | int imx_gpio_request(unsigned gpio, const char *label) | ||
103 | { | ||
104 | if(gpio >= (GPIO_PORT_MAX + 1) * 32) | ||
105 | printk(KERN_ERR "imx_gpio: Attempt to request nonexistent GPIO %d for \"%s\"\n", | ||
106 | gpio, label ? label : "?"); | ||
107 | return -EINVAL; | ||
108 | |||
109 | if(test_and_set_bit(gpio, imx_gpio_alloc_map)) { | ||
110 | printk(KERN_ERR "imx_gpio: GPIO %d already used. Allocation for \"%s\" failed\n", | ||
111 | gpio, label ? label : "?"); | ||
112 | return -EBUSY; | ||
113 | } | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | EXPORT_SYMBOL(imx_gpio_request); | ||
119 | |||
120 | void imx_gpio_free(unsigned gpio) | ||
121 | { | ||
122 | if(gpio >= (GPIO_PORT_MAX + 1) * 32) | ||
123 | return; | ||
124 | |||
125 | clear_bit(gpio, imx_gpio_alloc_map); | ||
126 | } | ||
127 | |||
128 | EXPORT_SYMBOL(imx_gpio_free); | ||
129 | |||
130 | int imx_gpio_direction_input(unsigned gpio) | ||
131 | { | ||
132 | imx_gpio_mode(gpio| GPIO_IN); | ||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | EXPORT_SYMBOL(imx_gpio_direction_input); | ||
137 | |||
138 | int imx_gpio_direction_output(unsigned gpio, int value) | ||
139 | { | ||
140 | imx_gpio_set_value(gpio, value); | ||
141 | imx_gpio_mode(gpio| GPIO_OUT); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | EXPORT_SYMBOL(imx_gpio_direction_output); | ||
146 | |||
147 | int imx_gpio_setup_multiple_pins(const int *pin_list, unsigned count, | ||
148 | int alloc_mode, const char *label) | ||
149 | { | ||
150 | const int *p = pin_list; | ||
151 | int i; | ||
152 | unsigned gpio; | ||
153 | unsigned mode; | ||
154 | |||
155 | for (i = 0; i < count; i++) { | ||
156 | gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK); | ||
157 | mode = *p & ~(GPIO_PIN_MASK | GPIO_PORT_MASK); | ||
158 | |||
159 | if (gpio >= (GPIO_PORT_MAX + 1) * 32) | ||
160 | goto setup_error; | ||
161 | |||
162 | if (alloc_mode & IMX_GPIO_ALLOC_MODE_RELEASE) | ||
163 | imx_gpio_free(gpio); | ||
164 | else if (!(alloc_mode & IMX_GPIO_ALLOC_MODE_NO_ALLOC)) | ||
165 | if (imx_gpio_request(gpio, label)) | ||
166 | if (!(alloc_mode & IMX_GPIO_ALLOC_MODE_TRY_ALLOC)) | ||
167 | goto setup_error; | ||
168 | |||
169 | if (!(alloc_mode & (IMX_GPIO_ALLOC_MODE_ALLOC_ONLY | | ||
170 | IMX_GPIO_ALLOC_MODE_RELEASE))) | ||
171 | imx_gpio_mode(gpio | mode); | ||
172 | |||
173 | p++; | ||
174 | } | ||
175 | return 0; | ||
176 | |||
177 | setup_error: | ||
178 | if(alloc_mode & (IMX_GPIO_ALLOC_MODE_NO_ALLOC | | ||
179 | IMX_GPIO_ALLOC_MODE_TRY_ALLOC)) | ||
180 | return -EINVAL; | ||
181 | |||
182 | while (p != pin_list) { | ||
183 | p--; | ||
184 | gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK); | ||
185 | imx_gpio_free(gpio); | ||
186 | } | ||
187 | |||
188 | return -EINVAL; | ||
189 | } | ||
190 | |||
191 | EXPORT_SYMBOL(imx_gpio_setup_multiple_pins); | ||
192 | |||
193 | void __imx_gpio_set_value(unsigned gpio, int value) | ||
194 | { | ||
195 | imx_gpio_set_value_inline(gpio, value); | ||
196 | } | ||
197 | |||
198 | EXPORT_SYMBOL(__imx_gpio_set_value); | ||
199 | |||
200 | int imx_gpio_to_irq(unsigned gpio) | ||
201 | { | ||
202 | return IRQ_GPIOA(0) + gpio; | ||
203 | } | ||
204 | |||
205 | EXPORT_SYMBOL(imx_gpio_to_irq); | ||
206 | |||
207 | int imx_irq_to_gpio(unsigned irq) | ||
208 | { | ||
209 | if (irq < IRQ_GPIOA(0)) | ||
210 | return -EINVAL; | ||
211 | return irq - IRQ_GPIOA(0); | ||
212 | } | ||
213 | |||
214 | EXPORT_SYMBOL(imx_irq_to_gpio); | ||
215 | |||
98 | /* | 216 | /* |
99 | * get the system pll clock in Hz | 217 | * get the system pll clock in Hz |
100 | * | 218 | * |
diff --git a/include/asm-arm/arch-imx/gpio.h b/include/asm-arm/arch-imx/gpio.h new file mode 100644 index 000000000000..486023263f32 --- /dev/null +++ b/include/asm-arm/arch-imx/gpio.h | |||
@@ -0,0 +1,102 @@ | |||
1 | #ifndef _IMX_GPIO_H | ||
2 | |||
3 | #include <asm/arch/imx-regs.h> | ||
4 | |||
5 | #define IMX_GPIO_ALLOC_MODE_NORMAL 0 | ||
6 | #define IMX_GPIO_ALLOC_MODE_NO_ALLOC 1 | ||
7 | #define IMX_GPIO_ALLOC_MODE_TRY_ALLOC 2 | ||
8 | #define IMX_GPIO_ALLOC_MODE_ALLOC_ONLY 4 | ||
9 | #define IMX_GPIO_ALLOC_MODE_RELEASE 8 | ||
10 | |||
11 | extern int imx_gpio_request(unsigned gpio, const char *label); | ||
12 | |||
13 | extern void imx_gpio_free(unsigned gpio); | ||
14 | |||
15 | extern int imx_gpio_setup_multiple_pins(const int *pin_list, unsigned count, | ||
16 | int alloc_mode, const char *label); | ||
17 | |||
18 | extern int imx_gpio_direction_input(unsigned gpio); | ||
19 | |||
20 | extern int imx_gpio_direction_output(unsigned gpio, int value); | ||
21 | |||
22 | extern void __imx_gpio_set_value(unsigned gpio, int value); | ||
23 | |||
24 | static inline int imx_gpio_get_value(unsigned gpio) | ||
25 | { | ||
26 | return SSR(gpio >> GPIO_PORT_SHIFT) & (1 << (gpio & GPIO_PIN_MASK)); | ||
27 | } | ||
28 | |||
29 | static inline void imx_gpio_set_value_inline(unsigned gpio, int value) | ||
30 | { | ||
31 | unsigned long flags; | ||
32 | |||
33 | raw_local_irq_save(flags); | ||
34 | if(value) | ||
35 | DR(gpio >> GPIO_PORT_SHIFT) |= (1 << (gpio & GPIO_PIN_MASK)); | ||
36 | else | ||
37 | DR(gpio >> GPIO_PORT_SHIFT) &= ~(1 << (gpio & GPIO_PIN_MASK)); | ||
38 | raw_local_irq_restore(flags); | ||
39 | } | ||
40 | |||
41 | static inline void imx_gpio_set_value(unsigned gpio, int value) | ||
42 | { | ||
43 | if(__builtin_constant_p(gpio)) | ||
44 | imx_gpio_set_value_inline(gpio, value); | ||
45 | else | ||
46 | __imx_gpio_set_value(gpio, value); | ||
47 | } | ||
48 | |||
49 | extern int imx_gpio_to_irq(unsigned gpio); | ||
50 | |||
51 | extern int imx_irq_to_gpio(unsigned irq); | ||
52 | |||
53 | /*-------------------------------------------------------------------------*/ | ||
54 | |||
55 | /* Wrappers for "new style" GPIO calls. These calls i.MX specific versions | ||
56 | * to allow future extension of GPIO logic. | ||
57 | */ | ||
58 | |||
59 | static inline int gpio_request(unsigned gpio, const char *label) | ||
60 | { | ||
61 | return imx_gpio_request(gpio, label); | ||
62 | } | ||
63 | |||
64 | static inline void gpio_free(unsigned gpio) | ||
65 | { | ||
66 | imx_gpio_free(gpio); | ||
67 | } | ||
68 | |||
69 | static inline int gpio_direction_input(unsigned gpio) | ||
70 | { | ||
71 | return imx_gpio_direction_input(gpio); | ||
72 | } | ||
73 | |||
74 | static inline int gpio_direction_output(unsigned gpio, int value) | ||
75 | { | ||
76 | return imx_gpio_direction_output(gpio, value); | ||
77 | } | ||
78 | |||
79 | static inline int gpio_get_value(unsigned gpio) | ||
80 | { | ||
81 | return imx_gpio_get_value(gpio); | ||
82 | } | ||
83 | |||
84 | static inline void gpio_set_value(unsigned gpio, int value) | ||
85 | { | ||
86 | imx_gpio_set_value(gpio, value); | ||
87 | } | ||
88 | |||
89 | #include <asm-generic/gpio.h> /* cansleep wrappers */ | ||
90 | |||
91 | static inline int gpio_to_irq(unsigned gpio) | ||
92 | { | ||
93 | return imx_gpio_to_irq(gpio); | ||
94 | } | ||
95 | |||
96 | static inline int irq_to_gpio(unsigned irq) | ||
97 | { | ||
98 | return imx_irq_to_gpio(irq); | ||
99 | } | ||
100 | |||
101 | |||
102 | #endif | ||
diff --git a/include/asm-arm/arch-imx/imx-regs.h b/include/asm-arm/arch-imx/imx-regs.h index 30de404c61f5..fb9de2733879 100644 --- a/include/asm-arm/arch-imx/imx-regs.h +++ b/include/asm-arm/arch-imx/imx-regs.h | |||
@@ -77,6 +77,8 @@ | |||
77 | #define SWR(x) __REG2(IMX_GPIO_BASE + 0x3c, ((x) & 3) << 8) | 77 | #define SWR(x) __REG2(IMX_GPIO_BASE + 0x3c, ((x) & 3) << 8) |
78 | #define PUEN(x) __REG2(IMX_GPIO_BASE + 0x40, ((x) & 3) << 8) | 78 | #define PUEN(x) __REG2(IMX_GPIO_BASE + 0x40, ((x) & 3) << 8) |
79 | 79 | ||
80 | #define GPIO_PORT_MAX 3 | ||
81 | |||
80 | #define GPIO_PIN_MASK 0x1f | 82 | #define GPIO_PIN_MASK 0x1f |
81 | #define GPIO_PORT_MASK (0x3 << 5) | 83 | #define GPIO_PORT_MASK (0x3 << 5) |
82 | 84 | ||