diff options
Diffstat (limited to 'arch/arm/mach-pnx4008/gpio.c')
-rw-r--r-- | arch/arm/mach-pnx4008/gpio.c | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/arch/arm/mach-pnx4008/gpio.c b/arch/arm/mach-pnx4008/gpio.c new file mode 100644 index 000000000000..e1ce050d8fe0 --- /dev/null +++ b/arch/arm/mach-pnx4008/gpio.c | |||
@@ -0,0 +1,330 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-pnx4008/gpio.c | ||
3 | * | ||
4 | * PNX4008 GPIO driver | ||
5 | * | ||
6 | * Author: Dmitry Chigirev <source@mvista.com> | ||
7 | * | ||
8 | * Based on reference code by Iwo Mergler and Z.Tabaaloute from Philips: | ||
9 | * Copyright (c) 2005 Koninklijke Philips Electronics N.V. | ||
10 | * | ||
11 | * 2005 (c) MontaVista Software, Inc. This file is licensed under | ||
12 | * the terms of the GNU General Public License version 2. This program | ||
13 | * is licensed "as is" without any warranty of any kind, whether express | ||
14 | * or implied. | ||
15 | */ | ||
16 | |||
17 | #include <linux/config.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <asm/semaphore.h> | ||
22 | #include <asm/io.h> | ||
23 | #include <asm/arch/platform.h> | ||
24 | #include <asm/arch/gpio.h> | ||
25 | |||
26 | /* register definitions */ | ||
27 | #define PIO_VA_BASE IO_ADDRESS(PNX4008_PIO_BASE) | ||
28 | |||
29 | #define PIO_INP_STATE (0x00U) | ||
30 | #define PIO_OUTP_SET (0x04U) | ||
31 | #define PIO_OUTP_CLR (0x08U) | ||
32 | #define PIO_OUTP_STATE (0x0CU) | ||
33 | #define PIO_DRV_SET (0x10U) | ||
34 | #define PIO_DRV_CLR (0x14U) | ||
35 | #define PIO_DRV_STATE (0x18U) | ||
36 | #define PIO_SDINP_STATE (0x1CU) | ||
37 | #define PIO_SDOUTP_SET (0x20U) | ||
38 | #define PIO_SDOUTP_CLR (0x24U) | ||
39 | #define PIO_MUX_SET (0x28U) | ||
40 | #define PIO_MUX_CLR (0x2CU) | ||
41 | #define PIO_MUX_STATE (0x30U) | ||
42 | |||
43 | static inline void gpio_lock(void) | ||
44 | { | ||
45 | local_irq_disable(); | ||
46 | } | ||
47 | |||
48 | static inline void gpio_unlock(void) | ||
49 | { | ||
50 | local_irq_enable(); | ||
51 | } | ||
52 | |||
53 | /* Inline functions */ | ||
54 | static inline int gpio_read_bit(u32 reg, int gpio) | ||
55 | { | ||
56 | u32 bit, val; | ||
57 | int ret = -EFAULT; | ||
58 | |||
59 | if (gpio < 0) | ||
60 | goto out; | ||
61 | |||
62 | bit = GPIO_BIT(gpio); | ||
63 | if (bit) { | ||
64 | val = __raw_readl(PIO_VA_BASE + reg); | ||
65 | ret = (val & bit) ? 1 : 0; | ||
66 | } | ||
67 | out: | ||
68 | return ret; | ||
69 | } | ||
70 | |||
71 | static inline int gpio_set_bit(u32 reg, int gpio) | ||
72 | { | ||
73 | u32 bit, val; | ||
74 | int ret = -EFAULT; | ||
75 | |||
76 | if (gpio < 0) | ||
77 | goto out; | ||
78 | |||
79 | bit = GPIO_BIT(gpio); | ||
80 | if (bit) { | ||
81 | val = __raw_readl(PIO_VA_BASE + reg); | ||
82 | val |= bit; | ||
83 | __raw_writel(val, PIO_VA_BASE + reg); | ||
84 | ret = 0; | ||
85 | } | ||
86 | out: | ||
87 | return ret; | ||
88 | } | ||
89 | |||
90 | /* Very simple access control, bitmap for allocated/free */ | ||
91 | static unsigned long access_map[4]; | ||
92 | #define INP_INDEX 0 | ||
93 | #define OUTP_INDEX 1 | ||
94 | #define GPIO_INDEX 2 | ||
95 | #define MUX_INDEX 3 | ||
96 | |||
97 | /*GPIO to Input Mapping */ | ||
98 | static short gpio_to_inp_map[32] = { | ||
99 | -1, -1, -1, -1, -1, -1, -1, -1, | ||
100 | -1, -1, -1, -1, -1, -1, -1, -1, | ||
101 | -1, -1, -1, -1, -1, -1, -1, -1, | ||
102 | -1, 10, 11, 12, 13, 14, 24, -1 | ||
103 | }; | ||
104 | |||
105 | /*GPIO to Mux Mapping */ | ||
106 | static short gpio_to_mux_map[32] = { | ||
107 | -1, -1, -1, -1, -1, -1, -1, -1, | ||
108 | -1, -1, -1, -1, -1, -1, -1, -1, | ||
109 | -1, -1, -1, -1, -1, -1, -1, -1, | ||
110 | -1, -1, -1, 0, 1, 4, 5, -1 | ||
111 | }; | ||
112 | |||
113 | /*Output to Mux Mapping */ | ||
114 | static short outp_to_mux_map[32] = { | ||
115 | -1, -1, -1, 6, -1, -1, -1, -1, | ||
116 | -1, -1, -1, -1, -1, -1, -1, -1, | ||
117 | -1, -1, -1, -1, -1, 2, -1, -1, | ||
118 | -1, -1, -1, -1, -1, -1, -1, -1 | ||
119 | }; | ||
120 | |||
121 | int pnx4008_gpio_register_pin(unsigned short pin) | ||
122 | { | ||
123 | unsigned long bit = GPIO_BIT(pin); | ||
124 | int ret = -EBUSY; /* Already in use */ | ||
125 | |||
126 | gpio_lock(); | ||
127 | |||
128 | if (GPIO_ISBID(pin)) { | ||
129 | if (access_map[GPIO_INDEX] & bit) | ||
130 | goto out; | ||
131 | access_map[GPIO_INDEX] |= bit; | ||
132 | |||
133 | } else if (GPIO_ISRAM(pin)) { | ||
134 | if (access_map[GPIO_INDEX] & bit) | ||
135 | goto out; | ||
136 | access_map[GPIO_INDEX] |= bit; | ||
137 | |||
138 | } else if (GPIO_ISMUX(pin)) { | ||
139 | if (access_map[MUX_INDEX] & bit) | ||
140 | goto out; | ||
141 | access_map[MUX_INDEX] |= bit; | ||
142 | |||
143 | } else if (GPIO_ISOUT(pin)) { | ||
144 | if (access_map[OUTP_INDEX] & bit) | ||
145 | goto out; | ||
146 | access_map[OUTP_INDEX] |= bit; | ||
147 | |||
148 | } else if (GPIO_ISIN(pin)) { | ||
149 | if (access_map[INP_INDEX] & bit) | ||
150 | goto out; | ||
151 | access_map[INP_INDEX] |= bit; | ||
152 | } else | ||
153 | goto out; | ||
154 | ret = 0; | ||
155 | |||
156 | out: | ||
157 | gpio_unlock(); | ||
158 | return ret; | ||
159 | } | ||
160 | |||
161 | EXPORT_SYMBOL(pnx4008_gpio_register_pin); | ||
162 | |||
163 | int pnx4008_gpio_unregister_pin(unsigned short pin) | ||
164 | { | ||
165 | unsigned long bit = GPIO_BIT(pin); | ||
166 | int ret = -EFAULT; /* Not registered */ | ||
167 | |||
168 | gpio_lock(); | ||
169 | |||
170 | if (GPIO_ISBID(pin)) { | ||
171 | if (~access_map[GPIO_INDEX] & bit) | ||
172 | goto out; | ||
173 | access_map[GPIO_INDEX] &= ~bit; | ||
174 | } else if (GPIO_ISRAM(pin)) { | ||
175 | if (~access_map[GPIO_INDEX] & bit) | ||
176 | goto out; | ||
177 | access_map[GPIO_INDEX] &= ~bit; | ||
178 | } else if (GPIO_ISMUX(pin)) { | ||
179 | if (~access_map[MUX_INDEX] & bit) | ||
180 | goto out; | ||
181 | access_map[MUX_INDEX] &= ~bit; | ||
182 | } else if (GPIO_ISOUT(pin)) { | ||
183 | if (~access_map[OUTP_INDEX] & bit) | ||
184 | goto out; | ||
185 | access_map[OUTP_INDEX] &= ~bit; | ||
186 | } else if (GPIO_ISIN(pin)) { | ||
187 | if (~access_map[INP_INDEX] & bit) | ||
188 | goto out; | ||
189 | access_map[INP_INDEX] &= ~bit; | ||
190 | } else | ||
191 | goto out; | ||
192 | ret = 0; | ||
193 | |||
194 | out: | ||
195 | gpio_unlock(); | ||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | EXPORT_SYMBOL(pnx4008_gpio_unregister_pin); | ||
200 | |||
201 | unsigned long pnx4008_gpio_read_pin(unsigned short pin) | ||
202 | { | ||
203 | unsigned long ret = -EFAULT; | ||
204 | int gpio = GPIO_BIT_MASK(pin); | ||
205 | gpio_lock(); | ||
206 | if (GPIO_ISOUT(pin)) { | ||
207 | ret = gpio_read_bit(PIO_OUTP_STATE, gpio); | ||
208 | } else if (GPIO_ISRAM(pin)) { | ||
209 | if (gpio_read_bit(PIO_DRV_STATE, gpio) == 0) { | ||
210 | ret = gpio_read_bit(PIO_SDINP_STATE, gpio); | ||
211 | } | ||
212 | } else if (GPIO_ISBID(pin)) { | ||
213 | ret = gpio_read_bit(PIO_DRV_STATE, gpio); | ||
214 | if (ret > 0) | ||
215 | ret = gpio_read_bit(PIO_OUTP_STATE, gpio); | ||
216 | else if (ret == 0) | ||
217 | ret = | ||
218 | gpio_read_bit(PIO_INP_STATE, gpio_to_inp_map[gpio]); | ||
219 | } else if (GPIO_ISIN(pin)) { | ||
220 | ret = gpio_read_bit(PIO_INP_STATE, gpio); | ||
221 | } | ||
222 | gpio_unlock(); | ||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | EXPORT_SYMBOL(pnx4008_gpio_read_pin); | ||
227 | |||
228 | /* Write Value to output */ | ||
229 | int pnx4008_gpio_write_pin(unsigned short pin, int output) | ||
230 | { | ||
231 | int gpio = GPIO_BIT_MASK(pin); | ||
232 | int ret = -EFAULT; | ||
233 | |||
234 | gpio_lock(); | ||
235 | if (GPIO_ISOUT(pin)) { | ||
236 | printk( "writing '%x' to '%x'\n", | ||
237 | gpio, output ? PIO_OUTP_SET : PIO_OUTP_CLR ); | ||
238 | ret = gpio_set_bit(output ? PIO_OUTP_SET : PIO_OUTP_CLR, gpio); | ||
239 | } else if (GPIO_ISRAM(pin)) { | ||
240 | if (gpio_read_bit(PIO_DRV_STATE, gpio) > 0) | ||
241 | ret = gpio_set_bit(output ? PIO_SDOUTP_SET : | ||
242 | PIO_SDOUTP_CLR, gpio); | ||
243 | } else if (GPIO_ISBID(pin)) { | ||
244 | if (gpio_read_bit(PIO_DRV_STATE, gpio) > 0) | ||
245 | ret = gpio_set_bit(output ? PIO_OUTP_SET : | ||
246 | PIO_OUTP_CLR, gpio); | ||
247 | } | ||
248 | gpio_unlock(); | ||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | EXPORT_SYMBOL(pnx4008_gpio_write_pin); | ||
253 | |||
254 | /* Value = 1 : Set GPIO pin as output */ | ||
255 | /* Value = 0 : Set GPIO pin as input */ | ||
256 | int pnx4008_gpio_set_pin_direction(unsigned short pin, int output) | ||
257 | { | ||
258 | int gpio = GPIO_BIT_MASK(pin); | ||
259 | int ret = -EFAULT; | ||
260 | |||
261 | gpio_lock(); | ||
262 | if (GPIO_ISBID(pin) || GPIO_ISRAM(pin)) { | ||
263 | ret = gpio_set_bit(output ? PIO_DRV_SET : PIO_DRV_CLR, gpio); | ||
264 | } | ||
265 | gpio_unlock(); | ||
266 | return ret; | ||
267 | } | ||
268 | |||
269 | EXPORT_SYMBOL(pnx4008_gpio_set_pin_direction); | ||
270 | |||
271 | /* Read GPIO pin direction: 0= pin used as input, 1= pin used as output*/ | ||
272 | int pnx4008_gpio_read_pin_direction(unsigned short pin) | ||
273 | { | ||
274 | int gpio = GPIO_BIT_MASK(pin); | ||
275 | int ret = -EFAULT; | ||
276 | |||
277 | gpio_lock(); | ||
278 | if (GPIO_ISBID(pin) || GPIO_ISRAM(pin)) { | ||
279 | ret = gpio_read_bit(PIO_DRV_STATE, gpio); | ||
280 | } | ||
281 | gpio_unlock(); | ||
282 | return ret; | ||
283 | } | ||
284 | |||
285 | EXPORT_SYMBOL(pnx4008_gpio_read_pin_direction); | ||
286 | |||
287 | /* Value = 1 : Set pin to muxed function */ | ||
288 | /* Value = 0 : Set pin as GPIO */ | ||
289 | int pnx4008_gpio_set_pin_mux(unsigned short pin, int output) | ||
290 | { | ||
291 | int gpio = GPIO_BIT_MASK(pin); | ||
292 | int ret = -EFAULT; | ||
293 | |||
294 | gpio_lock(); | ||
295 | if (GPIO_ISBID(pin)) { | ||
296 | ret = | ||
297 | gpio_set_bit(output ? PIO_MUX_SET : PIO_MUX_CLR, | ||
298 | gpio_to_mux_map[gpio]); | ||
299 | } else if (GPIO_ISOUT(pin)) { | ||
300 | ret = | ||
301 | gpio_set_bit(output ? PIO_MUX_SET : PIO_MUX_CLR, | ||
302 | outp_to_mux_map[gpio]); | ||
303 | } else if (GPIO_ISMUX(pin)) { | ||
304 | ret = gpio_set_bit(output ? PIO_MUX_SET : PIO_MUX_CLR, gpio); | ||
305 | } | ||
306 | gpio_unlock(); | ||
307 | return ret; | ||
308 | } | ||
309 | |||
310 | EXPORT_SYMBOL(pnx4008_gpio_set_pin_mux); | ||
311 | |||
312 | /* Read pin mux function: 0= pin used as GPIO, 1= pin used for muxed function*/ | ||
313 | int pnx4008_gpio_read_pin_mux(unsigned short pin) | ||
314 | { | ||
315 | int gpio = GPIO_BIT_MASK(pin); | ||
316 | int ret = -EFAULT; | ||
317 | |||
318 | gpio_lock(); | ||
319 | if (GPIO_ISBID(pin)) { | ||
320 | ret = gpio_read_bit(PIO_MUX_STATE, gpio_to_mux_map[gpio]); | ||
321 | } else if (GPIO_ISOUT(pin)) { | ||
322 | ret = gpio_read_bit(PIO_MUX_STATE, outp_to_mux_map[gpio]); | ||
323 | } else if (GPIO_ISMUX(pin)) { | ||
324 | ret = gpio_read_bit(PIO_MUX_STATE, gpio); | ||
325 | } | ||
326 | gpio_unlock(); | ||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | EXPORT_SYMBOL(pnx4008_gpio_read_pin_mux); | ||