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